CVE-2015-0231 (published 2015-01-27T20:03Z)

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.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)

Weakness information:
cwe_id: NVD-CWE-Other
cwe_name: Other
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.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/php/php-src
commit_details: repo_url: https://github.com/php/php-src
author: Stanislav Malyshev
author_date: 2015-01-01 16:19:05-08:00
msg: Fix for bug #68710 (Use After Free Vulnerability in PHP's unserialize())
repository: repo_url: https://github.com/php/php-src
repo_name: php/php-src
description: The PHP Interpreter
repo_language: C
owner: php
file_changes: filename: NEWS
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,10 @@
 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)
 

programming_language: Markdown
filename: bug68710.phpt
change_type: ModificationType.ADD
diff: @@ -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===

programming_language: PHP
filename: var_unserializer.c
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-/* 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"
 /*
   +----------------------------------------------------------------------+
@@ -343,7 +343,7 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long
 		} 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,

programming_language: C
filename: var_unserializer.re
change_type: ModificationType.MODIFY
diff: @@ -347,7 +347,7 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long
 		} 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,

programming_language: C