# Use of uninitialized memory in unserialize()

PHP unserialize() uses uninitialized memory for oversized array allocations, letting attacker-controlled bytes overwrite a HashTable destructor pointer and execute code.

- Payout: hidden
- Severity: medium
- Program: Internet Bug Bounty
- Found by: rc0r
- Disclosed: 2017-06-01
- CVE: CVE-2017-5340
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/195950
- Library page: https://bugbountylibrary.com/r/h1%3A195950
- Tags: area:oss domain:oss impact:rce kind:bounty platform:hackerone sev:medium tech:php technique:fuzzing vuln:deserialization vuln:memory-corruption vuln:rce

**Target:** PHP unserialize() / Zend HashTable allocation
**Root cause:** On integer-overflow-detected allocation failure during unserialize of a huge array, PHP shuts down with a partially initialized zend_array whose fields (including pDestructor) still hold attacker-controlled uninitialized heap bytes.
**Steps:**
1. Craft serialized payload `a:9000111000000010:{...` with 0x30 ('0') filler controlling the uninitialized region.
2. Pass it to `unserialize()` in test.php; `_array_init` requests 2736264714 elements.
3. Integer overflow detected in zend_hash_check_size triggers fatal error and shutdown.
4. During shutdown zend_hash_destroy calls `ht->pDestructor(&p->val)` where pDestructor = 0x3030303030303030.
5. Use ROP gadgets (php-7.0.13/7.0.14 Arch) in exploit.py to pivot and execute gnome-calculator.
**How found:** Fuzzing PHP's unserialize() with afl-fuzz/afl-utils surfaced the crash; gdb watchpoints on the HashTable showed the struct was populated from attacker-controlled 0x30 bytes via memmove before allocation failure.
**Exploitation:** Attacker supplies crafted serialized string; uninitialized heap memory filled with 0x30 bytes becomes the HashTable struct; on shutdown the overwritten pDestructor function pointer is called, and ROP chain from the payload achieves arbitrary code execution locally (demo pops gnome-calculator).
**Insight:** When an allocation fails mid-deserialization, shutdown destructors may run on partially initialized structs; watch for attacker-controlled filler bytes landing in function-pointer fields like pDestructor.

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

**Crafted unserialize payload with huge array length**

```
a:9000111000000010:{...`
in `payload.master` ([2]).
```

**PoC exploit script executing gnome-calculator via ROP**

```
$ python exploit.py
    [............... <gnome-calculator pops open!> ......]

Upon success `gnome-calculator` should be executed. You may want to replace
`gnome-calculator` with sth. else like, f.e. `touch a` in `epxloit.py`
```

