Title: PHP yaml_parse_url Double Free Credit: John Leitch (john@autosectools.com) Url1: http://autosectools.com/Page/PHP-yaml_parse_url-Double-Free Url2: https://bugs.php.net/bug.php?id=69616 Resolution: Fixed The yaml_* parsing functions suffers from an exploitable double free caused by the error path for the php_var_unserialize() call on line 797 of pecl/file_formats/yaml.git/parse.c: if (IS_NOT_IMPLICIT_AND_TAG_IS(event, YAML_PHP_TAG)) { const unsigned char *p; php_unserialize_data_t var_hash; p = (const unsigned char *) value; PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize( &retval, &p, p + (int) length, &var_hash TSRMLS_CC)) { PHP_VAR_UNSERIALIZE_DESTROY(var_hash); <<<<<<<< First free php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Failed to unserialize class"); /* return the serialized string directly */ ZVAL_STRINGL(retval, value, length, 1); } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); <<<<<<<< Second free return retval; } Should php_var_unserialize return false, var_hash is immediately freed via PHP_VAR_UNSERIALIZE_DESTROY, and then freed once more prior to the function returning. This code path can be forced by crafting a YAML document that contains an invalid !php/object value. An example is as follows: And it produces the following crash: eax=00000000 ebx=55a0b760 ecx=02fc9e58 edx=000a0d08 esi=015c41f8 edi=02deedc8 eip=55a0b7dc esp=014ce1d0 ebp=00000000 iopl=0 nv up ei ng nz ac pe cy cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010297 php5ts!_efree+0x7c: 55a0b7dc 8b043a mov eax,dword ptr [edx+edi] ds:002b:02e8fad0=?????? ?? 0:000> k ChildEBP RetAddr 014ce1d8 55b9d92c php5ts!_efree+0x7c 014ce1ec 613b45bd php5ts!var_destroy+0x1c 014ce25c 613b50fb php_yaml!eval_scalar+0x60d 014ce2ac 613b4a38 php_yaml!handle_scalar+0x2b 014ce2c8 613b4d09 php_yaml!get_next_element+0xb8 014ce384 613b4a16 php_yaml!handle_mapping+0x159 014ce3a0 613b4afe php_yaml!get_next_element+0x96 014ce3c4 613b3f33 php_yaml!handle_document+0x5e 014ce3e4 613b5f37 php_yaml!php_yaml_read_partial+0x93 014ce560 559e8721 php_yaml!zif_yaml_parse+0x177 014ce5c4 559e7de8 php5ts!zend_do_fcall_common_helper_SPEC+0x161 014ce600 559d33ea php5ts!execute_ex+0x378 014ce628 559d31ab php5ts!zend_execute+0x1ca 014ce65c 559d3694 php5ts!zend_execute_scripts+0x14b 014ce86c 770c9580 php5ts!php_execute_script+0x1b4 014ce8c4 76b9a3fa ntdll!RtlInitializeCriticalSectionEx+0xc2 014ce8dc 76b9a293 KERNELBASE!BasepInitializeFindFileHandle+0x51 014cecac 76b9a293 KERNELBASE!FindFirstFileExW+0x347 014cefb4 76bc39cc KERNELBASE!FindFirstFileExW+0x347 014cf25c 770eb1b7 KERNELBASE!FindFirstFileA+0x6c 014cf29c 770c8891 ntdll!LdrpApplyLookupReference+0x1e 014cf354 770c8c78 ntdll!RtlWow64EnableFsRedirectionEx+0x51 014cf4c4 770c9493 ntdll!RtlDosApplyFileIsolationRedirection_Ustr+0x2d8 014cf528 770c8092 ntdll!LdrpApplyFileNameRedirection+0x96 014cf5fc 770d4d3e ntdll!_SEH_epilog4_GS+0xa 014cf640 00000000 ntdll!LdrpGetProcedureAddress+0x3d Further, the document can be leveraged to manipulate the layout of memory, allowing for EIP control after the double free has occurred, and thus arbitrary code execution. 0:000> r eax=b6072cb5 ebx=00000000 ecx=55fc7ce0 edx=01564358 esi=02e57450 edi=0155e4b8 eip=b6072cb5 esp=014ce3f0 ebp=014ce45c iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 b6072cb5 ?? ??? 0:000> k ChildEBP RetAddr WARNING: Frame IP not in any known module. Following frames may be wrong. 014ce3ec 55a095a9 0xb6072cb5 014ce40c 55d7bbd0 php5ts!_zval_copy_ctor_func+0x139 00000000 00000000 php5ts!zend_std_read_property+0x3967e0 To fix this issue, it is recommended that the free be removed from the error path taken when php_var_unserialize() returns false.