# mod_remoteip stack buffer overflow and NULL pointer dereference

mod_remoteip with RemoteIPProxyProtocol On mishandles PROXY v1/v2 headers, causing stack overflows via memcpy/strcpy and a NULL deref DoS.

- Payout: hidden
- Severity: medium
- Program: Internet Bug Bounty
- Found by: ccppuu
- Disclosed: 2019-11-07
- CVE: CVE-2019-10097
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/674540
- Library page: https://bugbountylibrary.com/r/h1%3A674540
- Tags: area:cloud domain:infra impact:dos impact:rce kind:bounty platform:hackerone sev:medium tech:linux technique:source-review vuln:dos vuln:memory-corruption

**Target:** Apache httpd mod_remoteip PROXY protocol input filter
**Root cause:** remoteip_input_filter memcpy's attacker data into ctx->header without bounds check; remoteip_process_v1_handler strcpy's hdr->v1.line into a fixed 108-byte stack buffer; and HDR_DONE is returned for unsupported families/LOCAL command leaving client_addr NULL before deref.
**Steps:**
1. Enable `RemoteIPProxyProtocol On` and load mod_remoteip.
2. Send oversized PROXY v1 line: `printf "PROXY aaaa...\r\n" | nc localhost 6666` to overflow via memcpy/strcpy.
3. Send oversized PROXY v2 binary header with valid sig/ver/cmd/family to overflow via memcpy.
4. Send PROXY v2 LOCAL command `\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x20\x11\x00\x00` to trigger NULL deref at conn_conf->client_addr->port.
**How found:** Code review of mod_remoteip.c PROXY handling: spotted unchecked memcpy/strcpy into fixed buffers and traced HDR_DONE paths where client_addr stays NULL, cross-referencing HAProxy example code assumptions.
**Exploitation:** Attacker sends crafted PROXY v1/v2 header to a server with RemoteIPProxyProtocol On; oversized input corrupts stack (potential RCE), or LOCAL/unsupported-family v2 header causes worker thread segfault (DoS).
**Escalation:** Compromised front-end proxy in DMZ can pivot to RCE on backend app server via crafted PROXY request.
**Insight:** When a module adopts sample code from a protocol spec, check whether the spec's preconditions (e.g. sockaddr already filled by accept()) hold in the new context; here HDR_DONE was returned assuming addresses were populated.

