# Heap overflow due to integer overflow in php_escape_html_entities_ex() function

Integer overflow in php_escape_html_entities_ex() on 32-bit PHP makes maxlen wrap to 0x10, so htmlentities() heap-overflows and can reach code execution.

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

**Target:** ext/standard/html.c php_escape_html_entities_ex() / htmlentities()
**Root cause:** maxlen = 2 * oldlen overflows when oldlen is near PHP_INT_MAX (0x7fffffff on 32-bit), wrapping to 0xfffffffe; the aligned allocation size ((oldlen*2+0x14)&0xfffffffc) becomes 0x10, so zend_string_alloc returns a tiny buffer that the encoder then overflows.
**Steps:**
1. Run on a 32-bit PHP build with `ini_set('memory_limit', -1);`
2. Create oversized input: `$s = str_repeat("A", PHP_INT_MAX);`
3. Call `htmlentities($s, 0, "", true);`
4. Observe in gdb at ext/standard/html.c:1269 that oldlen=0x7fffffff and maxlen=0xfffffffe
5. Step into _emalloc: requested size is 0x10 due to integer wrap
6. Continue: writes past the 0x10 buffer corrupt adjacent heap objects until SIGSEGV at html.c:1378 `ZSTR_VAL(replaced)[len++] = mbsequence[0];`
**How found:** Code review of the initial size estimate in php_escape_html_entities_ex(); noticed the `maxlen = 2 * oldlen` multiplication and the subsequent `if (maxlen < oldlen)` check, then reasoned that oldlen=PHP_INT_MAX wraps maxlen and the aligned allocation size collapses to 0x10. Confirmed under gdb on a 32-bit build.
**Exploitation:** Attacker controls the input string passed to htmlentities(); the undersized allocation is overflowed with attacker bytes, allowing overwrite of adjacent PHP heap objects. The reporter states they can leak memory to bypass ASLR+DEP and control EIP for arbitrary code execution, running /bin/sh locally.
**Escalation:** Heap overflow used to leak library addresses (ASLR bypass) and hijack EIP, turning a memory-corruption crash into arbitrary code execution.
**Insight:** When auditing size-estimate code, check the multiplication overflow guard: `if (maxlen < oldlen)` misses cases where the wrapped value is still larger than oldlen (e.g. 0xfffffffe > 0x7fffffff), and the later alignment mask can shrink it further to a tiny allocation.

