Menu

#71 Buffer over-write when giffix'ing a malformed gif file with an image block with width wider than entire image.

v1.0_(example)
closed
None
1
2016-02-09
2015-11-24
No

Hi,

This was found on git master, commit cb85cee9c10efdb5662831c011daa740e9ebb6d5.

I found this file with afl-fuzz. It produces the following crash.

$ ./util/giffix giffix-crash.gif

Following error occurred (and ignored):GIF-LIB error: Image is defective, decoding aborted.
Segmentation fault

When compiled with ASAN:

$ ./util/giffix giffix-crash.gif


Following error occurred (and ignored):GIF-LIB error: Image is defective, decoding aborted.
=================================================================
==12690== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x607a00019d30 at pc 0x4039cd bp 0x7fff9bbd5700 sp 0x7fff9bbd56f8
WRITE of size 1 at 0x607a00019d30 thread T0
    #0 0x4039cc in main /root/giflib-code/util/giffix.c:149
    #1 0x7fcf80b18ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #2 0x403ecc in _start (/root/giflib-code/util/.libs/lt-giffix+0x403ecc)
0x607a00019d30 is located 0 bytes to the right of 12336-byte region [0x607a00016d00,0x607a00019d30)
allocated by thread T0 here:
    #0 0x7fcf810f941a (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x1541a)
    #1 0x401a0f in main /root/giflib-code/util/giffix.c:94
SUMMARY: AddressSanitizer: heap-buffer-overflow /root/giflib-code/util/giffix.c:170 main
Shadow bytes around the buggy address:
  0x0c0fbfffb350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0fbfffb360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0fbfffb370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0fbfffb380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0fbfffb390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c0fbfffb3a0: 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa fa fa
  0x0c0fbfffb3b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0fbfffb3c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0fbfffb3d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0fbfffb3e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0fbfffb3f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==12690== ABORTING
Aborted

The file is:

$ xxd -g 1 giffix-crash.gif
0000000: 47 49 46 30 30 30 30 30 30 30 f2 30 30 30 30 30  GIF0000000.00000
0000010: 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30  0000000000000000
0000020: 30 30 30 30 30 2c 30 30 30 30 30 e0 30 30 30 30  00000,00000.0000

Another file with the same root cause leads to overwriting a pointer that is later free'd.

$ ./util/giffix giffix-free.gif

Following error occurred (and ignored):GIF-LIB error: Image is defective, decoding aborted.

Following unrecoverable error occured:GIF-LIB error: Failed to read from given file.
GIF-LIB undefined error 0.
*** Error in `/root/giflib-code/util/.libs/lt-giffix': free(): invalid pointer: 0x0000000002130a20 ***
Aborted

Under ASAN:

$ ./util/giffix giffix-free.gif

Following error occurred (and ignored):GIF-LIB error: Image is defective, decoding aborted.
=================================================================
==12017== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60080000c000 at pc 0x4039cd bp 0x7ffcfd30fe10 sp 0x7ffcfd30fe08
WRITE of size 1 at 0x60080000c000 thread T0
    #0 0x4039cc in main /root/giflib-code/util/giffix.c:149
    #1 0x7fec3d650ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #2 0x403ecc in _start (/root/giflib-code/util/.libs/lt-giffix+0x403ecc)
0x60080000c000 is located 0 bytes to the right of 48-byte region [0x60080000bfd0,0x60080000c000)
allocated by thread T0 here:
    #0 0x7fec3dc3141a (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x1541a)
    #1 0x401a0f in main /root/giflib-code/util/giffix.c:94
SUMMARY: AddressSanitizer: heap-buffer-overflow /root/giflib-code/util/giffix.c:170 main
Shadow bytes around the buggy address:
  0x0c017fff97b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c017fff97c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c017fff97d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c017fff97e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c017fff97f0: fa fa fa fa fa fa fa fa fa fa 00 00 00 00 00 00
=>0x0c017fff9800:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c017fff9810: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c017fff9820: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c017fff9830: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c017fff9840: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c017fff9850: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==12017== ABORTING
Aborted

The second file is:

$ xxd -g 1 giffix-free.gif
0000000: 47 49 46 30 30 30 30 00 30 30 f2 30 30 30 30 30  GIF0000.00.00000
0000010: 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30  0000000000000000
0000020: 30 30 30 30 30 2c 30 30 30 30 30 03 30 18 ba 30  00000,00000.0..0
0000030: 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30  0000000000000000
0000040: 30 30 30 30 30 30 30 30                          00000000

With both of these files, these images have a corrupt image section within the gif file which has a width greater than the total width (SWidth).

I've made a patch to fix this, as follows:

diff --git a/util/giffix.c b/util/giffix.c
index 6fba84a..04f56fb 100644
--- a/util/giffix.c
+++ b/util/giffix.c
@@ -144,6 +144,9 @@ int main(int argc, char **argv)
                    fprintf(stderr,"\nFollowing error occurred (and ignored):");
                    PrintGifError(GifFileIn->Error);


+                   if (Width > GifFileIn->SWidth)
+                       GIF_EXIT("Image is wider than total");
+
                    /* Fill in with the darkest color in color map. */
                    for (j = 0; j < Width; j++)
                        LineBuffer[j] = DarkestColor;

Hope that helps, let me know if you need any more info.

Cheers,

Hugh

Discussion

  • Hugh Davenport

    Hugh Davenport - 2015-11-24

    Added first crash file.

     
  • Hugh Davenport

    Hugh Davenport - 2015-11-24

    Added second crash file (causes bad memory to be free'd when not compiled with ASAN).

     
  • Hugh Davenport

    Hugh Davenport - 2015-11-24

    Added patch to fix.

     
  • Hugh Davenport

    Hugh Davenport - 2015-11-24

    Forgot to attache the gdb outputs...

    (gdb) bt
    #0  memset () at ../sysdeps/x86_64/memset.S:80
    #1  0x0000000000402918 in main (argc=<optimized out>, argv=<optimized out>) at giffix.c:149
    (gdb) i r
    rax            0x624920 6441248
    rbx            0x610030 6357040
    rcx            0x624940 6441280
    rdx            0xe030   57392
    rsi            0x0      0
    rdi            0x624920 6441248
    rbp            0x0      0x0
    rsp            0x7fffffffe858   0x7fffffffe858
    r8             0x7ffff7fed740   140737354061632
    r9             0x6f636564202c6576       8026370441615271286
    r10            0x7fffffffe620   140737488348704
    r11            0x7ffff78795c0   140737346246080
    r12            0xe030   57392
    r13            0x12c0   4800
    r14            0x624920 6441248
    r15            0x6164a0 6382752
    rip            0x7ffff787961d   0x7ffff787961d <memset+93>
    eflags         0x10202  [ IF RF ]
    cs             0x33     51
    ss             0x2b     43
    ds             0x0      0
    es             0x0      0
    fs             0x0      0
    gs             0x0      0
    (gdb) x/i $rip
    => 0x7ffff787961d <memset+93>:  movdqu %xmm8,-0x10(%rdi,%rdx,1)
    
    Starting program: /root/giflib-code/util/.libs/lt-giffix < giffix-free.gif > /dev/null
    
    Following error occurred (and ignored):GIF-LIB error: Image is defective, decoding aborted.
    
    Following unrecoverable error occured:GIF-LIB error: Failed to read from given file.
    GIF-LIB undefined error 0.
    *** Error in `/root/giflib-code/util/.libs/lt-giffix': free(): invalid pointer: 0x0000000000624a20 ***
    
    Program received signal SIGABRT, Aborted.
    0x00007ffff7823cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
    56      ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
    (gdb) bt
    #0  0x00007ffff7823cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
    #1  0x00007ffff78270d8 in __GI_abort () at abort.c:89
    #2  0x00007ffff7860394 in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7ffff796eb28 "*** Error in `%s': %s: 0x%s ***\n")
        at ../sysdeps/posix/libc_fatal.c:175
    #3  0x00007ffff786c66e in malloc_printerr (ptr=<optimized out>, str=0x7ffff796ac19 "free(): invalid pointer", action=1) at malloc.c:4996
    #4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:3840
    #5  0x00007ffff7bc89d5 in EGifCloseFile (GifFile=GifFile@entry=0x6164a0, ErrorCode=ErrorCode@entry=0x0) at egif_lib.c:781
    #6  0x00000000004039fa in QuitGifError (GifFileIn=GifFileIn@entry=0x610030, GifFileOut=GifFileOut@entry=0x6164a0) at giffix.c:208
    #7  0x000000000040330b in main (argc=<optimized out>, argv=<optimized out>) at giffix.c:175
    (gdb) x/i $rip
    => 0x7ffff7823cc9 <__GI_raise+57>:      cmp    $0xfffffffffffff000,%rax
    (gdb) i r
    rax            0x0      0
    rbx            0x67     103
    rcx            0xffffffffffffffff       -1
    rdx            0x6      6
    rsi            0x750b   29963
    rdi            0x750b   29963
    rbp            0x7fffffffe750   0x7fffffffe750
    rsp            0x7fffffffe3b8   0x7fffffffe3b8
    r8             0x3032613432363030       3472945139464679472
    r9             0x696c2e2f6c697475       7596497452684375157
    r10            0x8      8
    r11            0x246    582
    r12            0x7fffffffe560   140737488348512
    r13            0x7      7
    r14            0x67     103
    r15            0x7      7
    rip            0x7ffff7823cc9   0x7ffff7823cc9 <__GI_raise+57>
    eflags         0x246    [ PF ZF IF ]
    cs             0x33     51
    ss             0x2b     43
    ds             0x0      0
    es             0x0      0
    fs             0x0      0
    gs             0x0      0
    

    And some when running the first file under ASAN:

    Starting program: /root/giflib-code/util/.libs/lt-giffix < giffix-crash.gif > /dev/null
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    
    Following error occurred (and ignored):GIF-LIB error: Image is defective, decoding aborted.
    =================================================================
    ==18822== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x607a00019d30 at pc 0x4036b5 bp 0x7fffffffe620 sp 0x7fffffffe618
    WRITE of size 1 at 0x607a00019d30 thread T0
        #0 0x4036b4 in main /root/giflib-code/util/giffix.c:149
        #1 0x7ffff487fec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
        #2 0x403a99 in _start (/root/giflib-code/util/.libs/lt-giffix+0x403a99)
    0x607a00019d30 is located 0 bytes to the right of 12336-byte region [0x607a00016d00,0x607a00019d30)
    allocated by thread T0 here:
        #0 0x7ffff4e6041a (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x1541a)
        #1 0x401a1f in main /root/giflib-code/util/giffix.c:94
    SUMMARY: AddressSanitizer: heap-buffer-overflow /root/giflib-code/util/giffix.c:170 main
    Shadow bytes around the buggy address:
      0x0c0fbfffb350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c0fbfffb360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c0fbfffb370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c0fbfffb380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c0fbfffb390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    =>0x0c0fbfffb3a0: 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa fa fa
      0x0c0fbfffb3b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c0fbfffb3c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c0fbfffb3d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c0fbfffb3e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c0fbfffb3f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    Shadow byte legend (one shadow byte represents 8 application bytes):
      Addressable:           00
      Partially addressable: 01 02 03 04 05 06 07 
      Heap left redzone:     fa
      Heap righ redzone:     fb
      Freed Heap region:     fd
      Stack left redzone:    f1
      Stack mid redzone:     f2
      Stack right redzone:   f3
      Stack partial redzone: f4
      Stack after return:    f5
      Stack use after scope: f8
      Global redzone:        f9
      Global init order:     f6
      Poisoned by user:      f7
      ASan internal:         fe
    ==18822== ABORTING
    
    Program received signal SIGABRT, Aborted.
    0x00007ffff4894cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
    56      ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
    (gdb) bt
    #0  0x00007ffff4894cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
    #1  0x00007ffff48980d8 in __GI_abort () at abort.c:89
    #2  0x00007ffff4e66829 in ?? () from /usr/lib/x86_64-linux-gnu/libasan.so.0
    #3  0x00007ffff4e5d3ec in ?? () from /usr/lib/x86_64-linux-gnu/libasan.so.0
    #4  0x00007ffff4e64012 in ?? () from /usr/lib/x86_64-linux-gnu/libasan.so.0
    #5  0x00007ffff4e63121 in __asan_report_error () from /usr/lib/x86_64-linux-gnu/libasan.so.0
    #6  0x00007ffff4e5d797 in __asan_report_store1 () from /usr/lib/x86_64-linux-gnu/libasan.so.0
    #7  0x00000000004036b5 in main (argc=<optimized out>, argv=<optimized out>) at giffix.c:149
    (gdb) frame 7
    #7  0x00000000004036b5 in main (argc=<optimized out>, argv=<optimized out>) at giffix.c:149
    149                             LineBuffer[j] = DarkestColor;
    (gdb) p Width
    $1 = 57392
    (gdb) p GifFileIn->SWidth
    $2 = 12336
    

    I guessed the SWidth thing, because LineBuffer is initialized on line 94

     94     if ((LineBuffer = (GifRowType) malloc(GifFileIn->SWidth)) == NULL)
     95         GIF_EXIT("Failed to allocate memory required, aborted.");
    

    So that shows that with this file, the Width is a lot more than the allocated space, leading to almost instant segfault. The other file the gap isn't as large, so doesn't segfault until free is called at the end. This could be used to build a custom exploit to get remote code execution potentially.

    Cheers,

    Hugh

     
  • Hugh Davenport

    Hugh Davenport - 2015-11-26

    Ok, so fuzzing found more with that patch, so I believe you have to move the width check closer to when width is set.

    A new patch, also attached.

    diff --git a/util/giffix.c b/util/giffix.c
    index a613987..e21b261 100644
    --- a/util/giffix.c
    +++ b/util/giffix.c
    @@ -112,6 +112,8 @@ int main(int argc, char **argv)
                    Height = GifFileIn->Image.Height;
                    GifQprintf("\n%s: Image %d at (%d, %d) [%dx%d]:     ",
                        PROGRAM_NAME, ++ImageNum, Col, Row, Width, Height);
    
    +               if (Width > GifFileIn->SWidth)
    +                   GIF_EXIT("Image is wider than total");
    
                    /* Put the image descriptor to out file: */
                    if (EGifPutImageDesc(GifFileOut, Col, Row, Width, Height,
    
     
  • Hugh Davenport

    Hugh Davenport - 2015-12-13

    Hi, Just checking whether anyone has seen this?

    Cheers,

    Hugh

     
  • Eric S. Raymond

    Eric S. Raymond - 2016-01-06
    • status: open --> closed
    • assigned_to: Eric S. Raymond
     
  • Eric S. Raymond

    Eric S. Raymond - 2016-02-09
    • private: Yes --> No
     

Log in to post a comment.

MongoDB Logo MongoDB