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

From: Date: Tue, 20 Jun 2017 05:07:57 +0000
Subject: Bug #74603 [Opn]: PHP INI Parsing Stack Buffer Overflow Vulnerability
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-209599@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: Bug Package: Scripting Engine problem Operating System: * PHP Version: 7.1.5 Block user comment: N Private report: N New Comment: Seems to be reproducible only on 32-bit PHP, since i_op* are ints, so it is required that sizeof(int) == sizeof(long) to reproduce the issue. Previous Comments: ------------------------------------------------------------------------ [2017-06-20 04:39:58] l dot wei at ntu dot edu dot sg Hi stas, thanks for the reply. It is true that php.ini should be protected from tampering, if modified, other issues could arise too. However it seems to me that parse_ini_file() and parse_ini_string() are not limited to protected ini files, as there is no inherent restriction whatsoever that stops these functions from being called on untrusted external inputs, especially for parse_ini_string(), as a handy PHP API. So I think maybe this should qualify a security bug ? The implementation bears some assumptions that ini files/strings should always be protected to the same level as the PHP module, however such implicit requirements cannot be guaranteed. ------------------------------------------------------------------------ [2017-06-19 23:39:59] stas@php.net Since .ini files are inherently admin functions, not a security issue. ------------------------------------------------------------------------ [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

« previous php.bugs (#209599) next »