# Memory corruption when parsing a hostile PHAR archive

Off-by-one NUL write in PHP's phar_parse_pharfile() when a hostile PHAR alias mismatches, corrupting emalloc metadata and enabling arbitrary memory write.

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

**Target:** PHP ext/phar phar_parse_pharfile() PHAR archive parser
**Root cause:** phar_parse_pharfile() writes buffer[tmp_len]='\0' without bounding tmp_len to the buffer end; a hostile manifest sets tmp_len to manifest_length-14, writing one byte past the allocation and clobbering emalloc metadata.
**Steps:**
1. Craft a hostile PHAR whose manifest makes tmp_len equal manifest_length - 14 so the alias-mismatch path writes '\0' just past the buffer.
2. Load it via `Phar::LoadPhar('example_hostile.phar', 'alias.phar')` from a PHP script that pre-allocates str_repeat chunks of length 192.
3. The off-by-one overwrites emalloc metadata; subsequent str_repeat allocations write to the corrupted pointer (0xDEADBEEF in the PoC), crashing in _emalloc.
**How found:** Code review of ext/phar/phar.c phar_parse_pharfile() spotted the unbounded `buffer[tmp_len] = '\0'` on the alias-mismatch path; crafted manifest length to push tmp_len to the buffer edge and confirmed via gdb crash at 0xDEADBEEF.
**Exploitation:** Attacker supplies a hostile PHAR archive to a PHP app that parses it; the off-by-one NUL corrupts heap allocator metadata, giving a controlled memory write to an arbitrary address (0xDEADBEEF demonstrated), potentially leading to RCE.
**Escalation:** Heap metadata corruption converted into arbitrary-address write, which the author suggests could enable remote code execution.
**Insight:** In C parsers, audit every NUL-termination write against the actual buffer end (endbuffer - buffer), especially on error/mismatch branches where length fields come straight from attacker-controlled headers.

