# Double Free Corruption in wddx.c (extension)

Malformed <boolean value> in wddx_deserialize frees varname twice, corrupting Zend heap free list and enabling controlled allocation for potential RCE.

- Payout: hidden
- Severity: high
- Program: Internet Bug Bounty
- Found by: hoangnguyen
- Disclosed: 2019-11-12
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/146255
- Library page: https://bugbountylibrary.com/r/h1%3A146255
- Tags: area:oss domain:oss impact:dos impact:rce kind:bounty platform:hackerone sev:high tech:php technique:source-review vuln:dos vuln:memory-corruption vuln:rce

**Target:** ext/wddx wddx_deserialize XML parser
**Root cause:** php_wddx_process_data frees ent->varname when boolean value isn't 'true'/'false', but the same stack entry is processed again for the element's text content, freeing varname a second time.
**Steps:**
1. Craft WDDX XML with `<boolean value="none">AAAAAAA</boolean>` inside a named var so value is neither true nor false.
2. Deserialize via `wddx_deserialize($xml)`; first process_data call efree's ent->varname.
3. Element text triggers a second process_data on same stack top with type still ST_BOOLEAN, efree'ing varname again.
4. Zend free list now self-referential; subsequent same-size allocations return the same chunk repeatedly.
5. Place attacker-controlled names (YYYYYYYY, ZZZZZZZZ, EZEZEZEZ) to steer allocations and crash at zend_mm_alloc_small.
**How found:** Code review of php_wddx_push_element/php_wddx_process_data revealed varname freed on invalid boolean value, then noticed the element's text content re-invokes process_data on the same stack entry, causing a second free.
**Exploitation:** Double free makes heap->free_slot[bin_num] point to itself; repeated same-size estrdup allocations return the same chunk. By substituting a GOT address (e.g. memcpy@got) for one name, zend_mm_alloc_small returns that address and a subsequent memcpy writes attacker-controlled bytes there, potentially achieving code execution.
**Escalation:** Heap free-list corruption converted into arbitrary write via GOT overwrite, escalating DoS to potential RCE.
**Insight:** In SAX-style XML deserializers, check whether character-data callbacks re-process the same stack entry already handled by the start-element callback; state left on the stack after an error branch can be freed twice.

