# php2shell in Practice: Exploitable, Conditional, and Hard to Mass-Exploit

OOM during PHP multipart upload parsing leaves dangling PS(id) session pointer, reused in Set-Cookie to leak heap and reach RCE under mod_php.

- Payout: Research
- Severity: critical
- Program: PHP
- Found by (vendor credit): Ryan at Calif.io, Wiz, OpenAI
- Write-up by: Michelle Rhodes
- Disclosed: 2026-10-27
- CVE: CVE-2026-109618, CVE-2026-109619
- Write-up quality: 8/10
- Original: https://www.praetorian.com/blog/php2shell/
- Library page: https://bugbountylibrary.com/r/blog%3Apraetorian-com-blog-php2shell
- Tags: area:web domain:web impact:data-leak impact:rce kind:research platform:research sev:critical tech:php technique:race-window technique:source-review vuln:info-disclosure vuln:memory-corruption vuln:rce

**Target:** PHP core session upload-progress module under Apache mod_php
**Root cause:** An out-of-memory error during multipart file-upload parsing leaves dangling pointers in the session "PS" global variables, which are reused on subsequent requests; a stale PS(id) is passed to php_url_encode when building the Set-Cookie header.
**Steps:**
1. Submit a multipart form with a `PHPSESSID` field and a `PHP_SESSION_UPLOAD_PROGRESS` field to enable upload progress tracking and set progress->sid/progress->key.
2. In MULTIPART_EVENT_FILE_START, attacker-controlled progress->sid is copied into PS(id); supply a null byte as first byte of PHPSESSID so php_session_initialize reallocates PS(id) and sets PS(send_cookie)=1.
3. Force php_session_send_cookie to fail so PS(send_cookie) stays 1: with display_errors=On trigger an error earlier so SG(headers_sent) is true; with display_errors=Off time an OOM inside php_url_encode's heap allocation with freelist buckets exhausted.
4. Trigger OOM during multipart parsing so PS(id) points at stale, attacker-reclaimable data; spray heap to build a string object with attacker-controlled length.
5. On a subsequent request, PS(id) is used in php_url_encode for the Set-Cookie header, leaking adjacent heap data (ASLR/libphp base).
6. Use leaked heap and libphp pointers to call zif_system with attacker-controlled input for RCE.
**How found:** Code review of php_session_rfc1867_callback switch(event) logic; noticed PS(id) is attacker-controlled via progress->sid and that PS(send_cookie)=1 persists only if php_session_send_cookie fails, then enumerated its failure modes (SG(headers_sent), OOM in php_url_encode) to widen the window.
**Exploitation:** Two requests must land on the same mod_php worker (prefork shares heap/module base until restart). Request A establishes the session and triggers the OOM leaving PS(send_cookie)=1 and stale PS(id); request B reuses the stale pointer to leak heap memory via the Set-Cookie header, defeating ASLR, then a crafted heap object drives zif_system for code execution. Requires version/build-specific offsets and precise heap control; demo achieved RCE against PHP 8.4.26 under Apache mod_php.
**Escalation:** Low-severity exposed phpinfo page supplies exact version, build provider, Server API (mod_php), display_errors and memory_limit, removing recon guesswork and enabling offset selection; DMZ RCE then abused via trusted-IP conditional access MFA exemption and domain reputation for phishing.
**Insight:** When a security-relevant global is set and reset within one call chain, enumerate the callee's failure paths (headers already sent, allocation failure) to leave the flag set across requests; and note that freelist-served allocations skip memory_limit checks, so OOM must be timed to a fresh page request.

## Write-ups of the same bug (oldest first)
- 2026-10-21: [PHP2Shell: AI uncovers critical RCE vulnerabilities affecting 70% of the Internet](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-php2shell-php-rce) — Wiz Research
- 2026-10-27: [Responder Guidance for PHP2Shell (CVE-2026-109618 and CVE-2026-109619)](https://bugbountylibrary.com/r/blog%3Abishopfox-com-blog-responder-guidance-for-php2shell)
- 2026-10-27: [php2shell in Practice: Exploitable, Conditional, and Hard to Mass-Exploit](https://bugbountylibrary.com/r/blog%3Apraetorian-com-blog-php2shell) — Michelle Rhodes (this one)

