CVE-2016-5771 (published 2016-08-07T10:59Z)

spl_array.c in the SPL extension in PHP before 5.5.37 and 5.6.x before 5.6.23 improperly interacts with the unserialize implementation and garbage collection, which allows remote attackers to execute arbitrary code or cause a denial of service (use-after-free and application crash) via crafted serialized data.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-416
cwe_name: Use After Free
description: The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.
extended_description: 
             
             
             
			 
             
             
         
         

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: 2016-06-20 21:26:33-07:00
msg: Fixed ##72433: Use After Free Vulnerability in PHP's GC algorithm and 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: gc_024.phpt
change_type: ModificationType.MODIFY
diff: @@ -13,5 +13,5 @@
 echo "ok\n";
 ?>
 --EXPECT--
-int(1)
+int(2)
 ok

programming_language: PHP
filename: spl_array.c
change_type: ModificationType.MODIFY
diff: @@ -831,6 +831,16 @@ static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /*
 }
 /* }}} */
 
+static HashTable *spl_array_get_gc(zval *object, zval ***gc_data, int *gc_data_count TSRMLS_DC) /* {{{ */
+{
+	spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+
+	*gc_data = &intern->array;
+	*gc_data_count = 1;
+	return zend_std_get_properties(object);
+}
+/* }}} */
+
 static zval *spl_array_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
 {
 	spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
@@ -1961,6 +1971,7 @@ PHP_MINIT_FUNCTION(spl_array)
 
 	spl_handler_ArrayObject.get_properties = spl_array_get_properties;
 	spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info;
+	spl_handler_ArrayObject.get_gc = spl_array_get_gc;
 	spl_handler_ArrayObject.read_property = spl_array_read_property;
 	spl_handler_ArrayObject.write_property = spl_array_write_property;
 	spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;

programming_language: C
filename: bug72433.phpt
change_type: ModificationType.ADD
diff: @@ -0,0 +1,32 @@
+--TEST--
+Bug #72433: Use After Free Vulnerability in PHP's GC algorithm and unserialize
+--FILE--
+<?php
+// Fill any potential freed spaces until now.
+$filler = array();
+for($i = 0; $i < 100; $i++)
+	$filler[] = "";
+// Create our payload and unserialize it.
+$serialized_payload = 'a:3:{i:0;r:1;i:1;r:1;i:2;C:11:"ArrayObject":19:{x:i:0;r:1;;m:a:0:{}}}';
+$free_me = unserialize($serialized_payload);
+// We need to increment the reference counter of our ArrayObject s.t. all reference counters of our unserialized array become 0.
+$inc_ref_by_one = $free_me[2];
+// The call to gc_collect_cycles will free '$free_me'.
+gc_collect_cycles();
+// We now have multiple freed spaces. Fill all of them.
+$fill_freed_space_1 = "filler_zval_1";
+$fill_freed_space_2 = "filler_zval_2";
+var_dump($free_me);
+?>
+--EXPECTF--
+array(3) {
+  [0]=>
+  *RECURSION*
+  [1]=>
+  *RECURSION*
+  [2]=>
+  object(ArrayObject)#%d (1) {
+    ["storage":"ArrayObject":private]=>
+    *RECURSION*
+  }
+}

programming_language: PHP