CVE-2016-10162: NULL Pointer Dereference (CWE-476)
value: The php_wddx_pop_element function in ext/wddx/wddx.c in PHP 7.0.x before 7.0.15 and 7.1.x before 7.1.1 allows remote attackers to cause a denial of service (NULL pointer dereference and application crash) via an inapplicable class name in a wddxPacket XML document, leading to mishandling in a wddx_deserialize call.
CWE description: The product dereferences a pointer that it expects to be valid but is NULL.
CVSS v3 base score: 7.5
Published: 2017-01-24T21:59Z
Repository: https://github.com/php/php-src
Language: C
Files changed: ext/wddx/tests/bug73831.phpt, ext/wddx/wddx.c
Commit date: 2016-12-31 20:14:20 -0800
Commit message: Fix bug #73831 - NULL Pointer Dereference while unserialize php object

Diff: diff --git a/ext/wddx/tests/bug73831.phpt b/ext/wddx/tests/bug73831.phpt
new file mode 100644
index 00000000000..0f8b8b12649
--- /dev/null
+++ b/ext/wddx/tests/bug73831.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Bug #73831 (NULL Pointer Dereference while unserialize php object)
+--SKIPIF--
+<?php if (!extension_loaded("wddx")) print "skip"; ?>
+--FILE--
+<?php
+$xml = <<<EOF
+<?xml version="1.0" ?>
+<wddxPacket version="1.0">
+	<struct>
+		<var name="php_class_name">
+			<string>Throwable</string>
+                </var>
+        </struct>
+</wddxPacket>
+EOF;
+try {
+	$wddx = wddx_deserialize($xml);
+} catch(Error $e) { echo $e->getMessage(); }
+?>
+--EXPECTF--
+Warning: wddx_deserialize(): Class throwable can not be instantiated in %sbug73831.php on line %d
+Cannot instantiate interface Throwable
diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c
index d58a564593c..70c62134072 100644
--- a/ext/wddx/wddx.c
+++ b/ext/wddx/wddx.c
@@ -906,11 +906,11 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name)
 			return;
 		}
 
 		if (!strcmp((char *)name, EL_BINARY)) {
 			zend_string *new_str = NULL;
-			
+
 			if (ZSTR_EMPTY_ALLOC() != Z_STR(ent1->data)) {
 				new_str = php_base64_decode(
 					(unsigned char *)Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));
 			}
 
@@ -965,26 +965,30 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name)
 							zval_ptr_dtor(&ent2->data);
 							ZVAL_UNDEF(&ent2->data);
 							php_error_docref(NULL, E_WARNING, "Class %s can not be unserialized", Z_STRVAL(ent1->data));
 						} else {
 							/* Initialize target object */
-							object_init_ex(&obj, pce);
-
-							/* Merge current hashtable with object's default properties */
-							zend_hash_merge(Z_OBJPROP(obj),
-											Z_ARRVAL(ent2->data),
-											zval_add_ref, 0);
-
-							if (incomplete_class) {
-								php_store_class_name(&obj, Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));
+							if (object_init_ex(&obj, pce) != SUCCESS || EG(exception)) {
+								zval_ptr_dtor(&ent2->data);
+								ZVAL_UNDEF(&ent2->data);
+								php_error_docref(NULL, E_WARNING, "Class %s can not be instantiated", Z_STRVAL(ent1->data));
+							} else {
+								/* Merge current hashtable with object's default properties */
+								zend_hash_merge(Z_OBJPROP(obj),
+												Z_ARRVAL(ent2->data),
+												zval_add_ref, 0);
+
+								if (incomplete_class) {
+									php_store_class_name(&obj, Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));
+								}
+
+								/* Clean up old array entry */
+								zval_ptr_dtor(&ent2->data);
+
+								/* Set stack entry to point to the newly created object */
+								ZVAL_COPY_VALUE(&ent2->data, &obj);
 							}
-
-							/* Clean up old array entry */
-							zval_ptr_dtor(&ent2->data);
-
-							/* Set stack entry to point to the newly created object */
-							ZVAL_COPY_VALUE(&ent2->data, &obj);
 						}
 
 						/* Clean up class name var entry */
 						zval_ptr_dtor(&ent1->data);
 					} else if (Z_TYPE(ent2->data) == IS_OBJECT) {

Vulnerable code: 			
							object_init_ex(&obj, pce);

							/* Merge current hashtable with object's default properties */
							zend_hash_merge(Z_OBJPROP(obj),
											Z_ARRVAL(ent2->data),
											zval_add_ref, 0);

							if (incomplete_class) {
								php_store_class_name(&obj, Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));

							/* Clean up old array entry */
							zval_ptr_dtor(&ent2->data);

							/* Set stack entry to point to the newly created object */
							ZVAL_COPY_VALUE(&ent2->data, &obj);
Fixed code: --TEST--
Bug #73831 (NULL Pointer Dereference while unserialize php object)
--SKIPIF--
<?php if (!extension_loaded("wddx")) print "skip"; ?>
--FILE--
<?php
$xml = <<<EOF
<?xml version="1.0" ?>
<wddxPacket version="1.0">
	<struct>
		<var name="php_class_name">
			<string>Throwable</string>
                </var>
        </struct>
</wddxPacket>
EOF;
try {
	$wddx = wddx_deserialize($xml);
} catch(Error $e) { echo $e->getMessage(); }
?>
--EXPECTF--
Warning: wddx_deserialize(): Class throwable can not be instantiated in %sbug73831.php on line %d
Cannot instantiate interface Throwable

							if (object_init_ex(&obj, pce) != SUCCESS || EG(exception)) {
								zval_ptr_dtor(&ent2->data);
								ZVAL_UNDEF(&ent2->data);
								php_error_docref(NULL, E_WARNING, "Class %s can not be instantiated", Z_STRVAL(ent1->data));
							} else {
								/* Merge current hashtable with object's default properties */
								zend_hash_merge(Z_OBJPROP(obj),
												Z_ARRVAL(ent2->data),
												zval_add_ref, 0);

								if (incomplete_class) {
									php_store_class_name(&obj, Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));
								}

								/* Clean up old array entry */
								zval_ptr_dtor(&ent2->data);

								/* Set stack entry to point to the newly created object */
								ZVAL_COPY_VALUE(&ent2->data, &obj);