Sec Bug->Bug #74603 [Opn]: PHP INI Parsing Stack Buffer Overflow Vulnerability

From: Date: Mon, 19 Jun 2017 23:40:01 +0000
Subject: Sec Bug->Bug #74603 [Opn]: PHP INI Parsing Stack Buffer Overflow Vulnerability
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-209596@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=74603&edit=1

 ID:                 74603
 Updated by:         stas@php.net
 Reported by:        l dot wei at ntu dot edu dot sg
 Summary:            PHP INI Parsing Stack Buffer Overflow Vulnerability
 Status:             Open
-Type:               Security
+Type:               Bug
 Package:            Scripting Engine problem
 Operating System:   *
 PHP Version:        7.1.5
 Block user comment: N
 Private report:     Y

 New Comment:

Since .ini files are inherently admin functions, not a security issue.


Previous Comments:
------------------------------------------------------------------------
[2017-05-28 08:44:45] l dot wei at ntu dot edu dot sg

Affecting Zend, changed package to Scripting Engine. Can also be triggered via ini string (e.g., in
cmdline argument, use -d foor=[bar] with the crasher above).

------------------------------------------------------------------------
[2017-05-17 02:29:46] 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




------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=74603&edit=1


Thread (1 message)

  • stas@php.net
  • Unknown Message
    • stas@php.net
« previous php.bugs (#209596) next »