CVE-2015-0231: Other (NVD-CWE-Other)
value: Use-after-free vulnerability in the process_nested_data function in ext/standard/var_unserializer.re in PHP before 5.4.37, 5.5.x before 5.5.21, and 5.6.x before 5.6.5 allows remote attackers to execute arbitrary code via a crafted unserialize call that leverages improper handling of duplicate numerical keys within the serialized properties of an object.  NOTE: this vulnerability exists because of an incomplete fix for CVE-2014-8142.
CWE description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
Published: 2015-01-27T20:03Z
Repository: https://github.com/php/php-src
Language: Other
Files changed: NEWS, ext/standard/tests/strings/bug68710.phpt, ext/standard/var_unserializer.c, ext/standard/var_unserializer.re
Commit date: 2015-01-01 16:19:05 -0800
Commit message: Fix for bug #68710 (Use After Free Vulnerability in PHP's unserialize())

Diff: diff --git a/NEWS b/NEWS
index fa57ef3161c..f789a9258e3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,12 @@
 PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? 20?? PHP 5.4.37
+- Core:
+  . Fix bug #68710 (Use after free vulnerability in unserialize(), incomplete
+    fix for #68594). (Stefan Esser)
+
 - CGI:
   . Fix bug #68618 (out of bounds read crashes php-cgi). (Stas)
 
 18 Dec 2014 PHP 5.4.36
 
diff --git a/ext/standard/tests/strings/bug68710.phpt b/ext/standard/tests/strings/bug68710.phpt
new file mode 100644
index 00000000000..729a12011b5
--- /dev/null
+++ b/ext/standard/tests/strings/bug68710.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #68710 Use after free vulnerability in unserialize() (bypassing the
+CVE-2014-8142 fix)
+--FILE--
+<?php
+for ($i=4; $i<100; $i++) {
+    $m = new StdClass();
+
+    $u = array(1);
+
+    $m->aaa = array(1,2,&$u,4,5);
+    $m->bbb = 1;
+    $m->ccc = &$u;
+    $m->ddd = str_repeat("A", $i);
+
+    $z = serialize($m);
+    $z = str_replace("aaa", "123", $z);
+    $z = str_replace("bbb", "123", $z);
+    $y = unserialize($z);
+    $z = serialize($y);
+}
+?>
+===DONE===
+--EXPECTF--
+===DONE===
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index a12d2fa24e3..f114080b86e 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -1,6 +1,6 @@
-/* Generated by re2c 0.13.7.5 on Thu Dec 11 19:26:19 2014 */
+/* Generated by re2c 0.13.7.5 on Thu Jan  1 14:43:18 2015 */
 #line 1 "ext/standard/var_unserializer.re"
 /*
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
@@ -341,11 +341,11 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long
 				break;
 			}
 		} else {
 			/* object properties should include no integers */
 			convert_to_string(key);
-			if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
+			if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
 				var_push_dtor(var_hash, old_data);
 			}
 			zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data,
 					sizeof data, NULL);
 		}
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index 4cf1d108328..f04fc74c312 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -345,11 +345,11 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long
 				break;
 			}
 		} else {
 			/* object properties should include no integers */
 			convert_to_string(key);
-			if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
+			if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
 				var_push_dtor(var_hash, old_data);
 			}
 			zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data,
 					sizeof data, NULL);
 		}

Vulnerable code: /* Generated by re2c 0.13.7.5 on Thu Dec 11 19:26:19 2014 */
			if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
			if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
Fixed code: - Core:
  . Fix bug #68710 (Use after free vulnerability in unserialize(), incomplete
    fix for #68594). (Stefan Esser)

--TEST--
Bug #68710 Use after free vulnerability in unserialize() (bypassing the
CVE-2014-8142 fix)
--FILE--
<?php
for ($i=4; $i<100; $i++) {
    $m = new StdClass();

    $u = array(1);

    $m->aaa = array(1,2,&$u,4,5);
    $m->bbb = 1;
    $m->ccc = &$u;
    $m->ddd = str_repeat("A", $i);

    $z = serialize($m);
    $z = str_replace("aaa", "123", $z);
    $z = str_replace("bbb", "123", $z);
    $y = unserialize($z);
    $z = serialize($y);
}
?>
===DONE===
--EXPECTF--
===DONE===
/* Generated by re2c 0.13.7.5 on Thu Jan  1 14:43:18 2015 */
			if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
			if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {