# Type Confusion Vulnerability in SoapClient

SoapClient::__getCookies() trusts the _cookies property as a HashTable, so a crafted unserialize payload fakes a zval/HashTable/Bucket to achieve remote code execution in PHP.

- Payout: hidden
- Severity: critical
- Program: Internet Bug Bounty
- Found by: ryat
- Disclosed: 2015-04-16
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/73245
- Library page: https://bugbountylibrary.com/r/h1%3A73245
- Tags: area:oss domain:oss impact:rce kind:bounty platform:hackerone sev:critical tech:php technique:source-review vuln:deserialization vuln:memory-corruption vuln:rce

**Target:** PHP SoapClient object __getCookies() method
**Root cause:** __getCookies() fetches the user-controllable _cookies property and applies Z_ARRVAL_P to it without verifying it is actually an array, so a string zval is reinterpreted as a HashTable pointer.
**Steps:**
1. Craft serialized object `O:10:"SoapClient":1:{s:8:"_cookies";s:<len>:"<fake hashtable bytes>";}` where _cookies is a string, not an array.
2. Heap-spray fake Bucket, HashTable, zval and shellcode at predictable addresses via a large repeated string (`str_repeat($part, 1024*1024*256/4096)`).
3. unserialize() the payload to create the SoapClient with attacker-controlled _cookies string.
4. Call `$z->__getCookies()`; Z_ARRVAL_P(*cookies) treats the string as a HashTable, following the fake Bucket to the fake zval.
5. Fake zval points to a function pointer (zend_eval_string) and shellcode `eval($_SERVER['argv'][1]);` to execute arbitrary PHP.
**How found:** Code review of __getCookies() showed Z_ARRVAL_P applied to the _cookies property without a type check; since _cookies is settable via unserialize, a string zval could be reinterpreted as a HashTable, motivating a fake-structure heap-spray exploit.
**Exploitation:** Attacker controls the serialized SoapClient object (e.g. via an unserialize sink on user input). Heap spray places fake HashTable/Bucket/zval at a fixed address; calling __getCookies() dereferences the fake structures and invokes zend_eval_string with attacker-supplied code, yielding arbitrary command execution.
**Insight:** Magic methods that read object properties and apply Z_ARRVAL_P/Z_OBJPROP_P without a Z_TYPE check are type-confusion candidates reachable through unserialize; look for internal PHP methods that trust user-settable properties as arrays or objects.

## Proof of concept (copied exactly from the original report)

**Serialized SoapClient payload triggering __getCookies**

```
$exploit = 'O:10:"SoapClient":1:{s:8:"_cookies";s:'.strlen($hashtable).':"'.$hashtable.'";}';
$z = unserialize($exploit);
// $z = new SoapClient(null, array('location' => "", 'uri' => ""));
// $z->_cookies = $hashtable;
$z->__getCookies();
```

