# Buffer overflow in HTTP parse_hostinfo(), parse_userinfo() and parse_scheme()

Off-by-one in pecl-http URL parser loops lets a malformed HTTP request overflow state->buffer and corrupt a php_stream_ops pointer, crashing or likely achieving code execution.

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

**Target:** PHP pecl-http extension URL parser (php_http_url.c)
**Root cause:** Parser loops use `while (++ptr != end)` and `if (ptr != end)` instead of `<`, so ptr can be incremented past end and the loop keeps writing into state->buffer beyond its bounds.
**Steps:**
1. Build pecl-http with `./configure --enable-raphf --enable-propro --with-http && make`
2. Craft a malformed HTTP request (bug73185.bin) whose hostinfo/userinfo/scheme fields drive ptr past end
3. Instantiate `new http\Message(file_get_contents("bug73185.bin"), false)`
4. Parser overflows state->buffer, corrupting adjacent php_stream struct including its ops function pointer
5. On parse failure, `_php_stream_free()` calls `*0x10(%rax)` with attacker-controlled rax (e.g. 0x4142434445464748) -> SIGSEGV
**How found:** Code review of the parse loops in php_http_url.c noticed the pre-increment `++ptr != end` check can be skipped when ptr jumps past end via `ptr += mb - 1`, allowing the loop to continue writing past the buffer.
**Exploitation:** Attacker supplies a malformed HTTP message to any code path that parses it into an http\Message; the overflow overwrites a php_stream structure and its php_stream_ops pointer, which is dereferenced and called during stream cleanup, giving control of the call target.
**Escalation:** Overwrite of php_stream_ops function pointer converts a parse crash into a likely arbitrary code execution primitive.
**Insight:** In C parsers, any loop using `++ptr != end` (rather than `<`) combined with multi-byte advances like `ptr += mb - 1` can skip the end check entirely; audit such loops for buffer writes after the pointer leaps past end.

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

**PHP script parsing malformed HTTP request file**

```
<?php
    $http_msg = new http\Message(file_get_contents("bug73185.bin"), false);
?>
```

