|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2017-05-17 02:29 UTC] l dot wei at ntu dot edu dot sg
Description:
------------
A stack buffer overflow exists in the latest stable release of PHP-7.1.5 and PHP-5.6.30 in PHP INI parsing API, which may accept network / local filesystem input. On malformed inputs, a stack buffer overflow in zend_ini_do_op() could write 1-byte off a fixed size stack buffer. On installations with the stack smashing mitigation, this would cause an immediate DoS; upto optimization levels, build options and stack buffer overflow mitigations, this vulnerability may allow corrupting other local variables or the frame pointer, potentially allows remotely executing code.
In php-7.1.5/Zend/zend_long.h:
110 #if SIZEOF_ZEND_LONG == 4
111 # define MAX_LENGTH_OF_LONG 11
112 # define LONG_MIN_DIGITS "2147483648"
113 #elif SIZEOF_ZEND_LONG == 8
114 # define MAX_LENGTH_OF_LONG 20
115 # define LONG_MIN_DIGITS "9223372036854775808"
116 #else
117 # error "Unknown SIZEOF_ZEND_LONG"
118 #endif
In php-7.1.5/Zend/zend_ini_parser.c:
123 /* {{{ zend_ini_do_op()
124 */
125 static void zend_ini_do_op(char type, zval *result, zval *op1, zval *op2)
126 {
127 int i_result;
128 int i_op1, i_op2;
129 int str_len;
130 char str_result[MAX_LENGTH_OF_LONG];
131
132 i_op1 = atoi(Z_STRVAL_P(op1));
133 zend_string_free(Z_STR_P(op1));
134 if (op2) {
135 i_op2 = atoi(Z_STRVAL_P(op2));
136 zend_string_free(Z_STR_P(op2));
137 } else {
138 i_op2 = 0;
139 }
140
141 switch (type) {
142 case '|':
143 i_result = i_op1 | i_op2;
144 break;
145 case '&':
146 i_result = i_op1 & i_op2;
147 break;
148 case '^':
149 i_result = i_op1 ^ i_op2;
150 break;
151 case '~':
152 i_result = ~i_op1;
153 break;
154 case '!':
155 i_result = !i_op1;
156 break;
157 default:
158 i_result = 0;
159 break;
160 }
161
162 str_len = zend_sprintf(str_result, "%d", i_result);
163 ZVAL_NEW_STR(result, zend_string_init(str_result, str_len, ZEND_SYSTEM_INI));
164 }
165 /* }}} */
The minimums, "-2147483648" and "-9223372036854775808" are of length 11 and 20 respectively,
the proper definition of str_result[] array would be: str_result[MAX_LENGTH_OF_LONG + 1]. A
crafted ini entry would cause an overflow.
Credit: Wei Lei and Liu Yang of Nanyang Technological University.
Test script:
---------------
$ cat input.ini
0=0&~2000000000
$ cat input.php
<?php
$argc = $_SERVER['argc'];
$argv = $_SERVER['argv'];
$file_loc = dirname(__FILE__)."/".$argv[1];
var_dump(parse_ini_file($file_loc, true, INI_SCANNER_NORMAL));
?>
Expected result:
----------------
No crash.
Actual result:
--------------
$ bin/php input.php input.ini
*** buffer overflow detected ***: bin/php terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x68e4e)[0xb7527e4e]
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x6b)[0xb75ba85b]
/lib/i386-linux-gnu/libc.so.6(+0xfa6ea)[0xb75b96ea]
/lib/i386-linux-gnu/libc.so.6(+0xf9e48)[0xb75b8e48]
/lib/i386-linux-gnu/libc.so.6(_IO_default_xsputn+0x8e)[0xb752fc0e]
/lib/i386-linux-gnu/libc.so.6(_IO_vfprintf+0x89b)[0xb7502f3b]
/lib/i386-linux-gnu/libc.so.6(__vsprintf_chk+0xb1)[0xb75b8f01]
/lib/i386-linux-gnu/libc.so.6(__sprintf_chk+0x2f)[0xb75b8e2f]
bin/php[0x82e7aa0]
bin/php[0x82e87d3]
bin/php(zend_parse_ini_file+0x47)[0x82e8b07]
bin/php[0x8255788]
bin/php[0x83631f6]
bin/php(execute_ex+0x22)[0x8353c52]
bin/php(zend_execute+0x13b)[0x83a341b]
bin/php(zend_execute_scripts+0x30)[0x8313010]
bin/php(php_execute_script+0x286)[0x82b3f26]
bin/php[0x83a57de]
bin/php[0x80683b9]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb74d8a83]
bin/php[0x8068444]
======= Memory map: ========
08048000-0888d000 r-xp 00000000 08:01 704181 /home/weilei/php7_gdb/bin/php
0888d000-0888e000 r--p 00844000 08:01 704181 /home/weilei/php7_gdb/bin/php
0888e000-08899000 rw-p 00845000 08:01 704181 /home/weilei/php7_gdb/bin/php
08899000-088b2000 rw-p 00000000 00:00 0
09ae7000-09b9a000 rw-p 00000000 00:00 0 [heap]
b7000000-b7200000 r--p 00000000 08:01 271314 /usr/lib/locale/locale-archive
b7200000-b7400000 rw-p 00000000 00:00 0
b7464000-b7480000 r-xp 00000000 08:01 787579 /lib/i386-linux-gnu/libgcc_s.so.1
b7480000-b7481000 rw-p 0001b000 08:01 787579 /lib/i386-linux-gnu/libgcc_s.so.1
b7496000-b74bf000 rw-p 00000000 00:00 0
b74bf000-b7667000 r-xp 00000000 08:01 787552 /lib/i386-linux-gnu/libc-2.19.so
b7667000-b7669000 r--p 001a8000 08:01 787552 /lib/i386-linux-gnu/libc-2.19.so
b7669000-b766a000 rw-p 001aa000 08:01 787552 /lib/i386-linux-gnu/libc-2.19.so
b766a000-b766d000 rw-p 00000000 00:00 0
b766d000-b7670000 r-xp 00000000 08:01 787569 /lib/i386-linux-gnu/libdl-2.19.so
b7670000-b7671000 r--p 00002000 08:01 787569 /lib/i386-linux-gnu/libdl-2.19.so
b7671000-b7672000 rw-p 00003000 08:01 787569 /lib/i386-linux-gnu/libdl-2.19.so
b7672000-b7673000 rw-p 00000000 00:00 0
b7673000-b76b7000 r-xp 00000000 08:01 787602 /lib/i386-linux-gnu/libm-2.19.so
b76b7000-b76b8000 r--p 00043000 08:01 787602 /lib/i386-linux-gnu/libm-2.19.so
b76b8000-b76b9000 rw-p 00044000 08:01 787602 /lib/i386-linux-gnu/libm-2.19.so
b76b9000-b76cc000 r-xp 00000000 08:01 787678 /lib/i386-linux-gnu/libresolv-2.19.so
b76cc000-b76cd000 ---p 00013000 08:01 787678 /lib/i386-linux-gnu/libresolv-2.19.so
b76cd000-b76ce000 r--p 00013000 08:01 787678 /lib/i386-linux-gnu/libresolv-2.19.so
b76ce000-b76cf000 rw-p 00014000 08:01 787678 /lib/i386-linux-gnu/libresolv-2.19.so
b76cf000-b76e4000 rw-p 00000000 00:00 0
b76e4000-b76e5000 r--s 00000000 08:01 554280 /home/weilei/php7_gdb/input.ini
b76e5000-b76e6000 r--p 00855000 08:01 271314 /usr/lib/locale/locale-archive
b76e6000-b76e8000 rw-p 00000000 00:00 0
b76e8000-b76ea000 r--p 00000000 00:00 0 [vvar]
b76ea000-b76ec000 r-xp 00000000 00:00 0 [vdso]
b76ec000-b770c000 r-xp 00000000 08:01 787528 /lib/i386-linux-gnu/ld-2.19.so
b770c000-b770d000 r--p 0001f000 08:01 787528 /lib/i386-linux-gnu/ld-2.19.so
b770d000-b770e000 rw-p 00020000 08:01 787528 /lib/i386-linux-gnu/ld-2.19.so
bff25000-bff47000 rw-p 00000000 00:00 0 [stack]
Aborted
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Oct 26 09:00:01 2025 UTC |
static void zend_ini_do_op(char type, zval *result, zval *op1, zval *op2) { int i_result; int i_op1, i_op2; char str_result[MAX_LENGTH_OF_LONG]; On the mentioned Windows build, checking the following two: bp !php5ts+436f0 // ini_parse() bp !php5ts+375d20 // zend_ini_do_op() Stack cookie protection is on, with canary store in [ebp-4]. The mitigation re-ordered the 4-byte aligned char array str_result to be next to the canary, starting at [ebp-10h]. When the overflow occurred, the 1-byte '\0' just occupied the 1-byte padding. Therefore it does not affect this build. When mitigation is not in place, or the string is not aligned to 4-byte, it may cause an immediate DoS (cookie corruption); or 1-byte of ebp (no stack smash protection).