Skip to content
Exploit for Improperly Controlled Sequential Memory Allocation in Php

Exploit for Improperly Controlled Sequential Memory Allocation in Php

Sploitus • October 27, 2026

standard-library Python, tested end-to-end against a real `php:8.4.26-apache-bookworm`

> ⚠️ **For authorized security testing and research only.** Run against systems

> you own or have explicit written permission to test. The exploit tool crashes

> workers by design and can exhaust memory.

| **Lab** | ✅ running — `php2shell-lab` on ` (PHP 8.4.26, mod_php) |

| **Scanner** | ✅ v1.2 — version + SAPI + upload-progress fingerprinting, opt-in crash probe |

| **Exploit** | 🟡 tool complete — OOM producer + full A1→B1 chain verified; **leak/RCE not yet confirmed** (see [status](#exploitation-status)) |

Both bugs live in request startup, **before application code runs**, and both

stem from PHP's OOM bailout: an allocation exceeding `memory_limit` makes

`emalloc` fail → `zend_error_noreturn` → `zend_bailout()` → `longjmp` to the

request boundary, **skipping every cleanup step in between**.

| **CVE-2026-109618** (GHSA-w8hw-w9fx-j79w) | RCE via **OOM corruption** — half-initialized / freed-but-referenced structures survive the bailout; shutdown later reads attacker-shaped memory | 9.2 | 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 |

| **CVE-2026-109619** (GHSA-6wmf-4rv5-p3rp) | RCE via **stale global state** — the bailout skips a per-request global reset; dangling `zval*` survive into the request on the same worker → heap UAF / disclosure | 9.2 | 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 |

| **CVE-2026-115560** (Oct 23) | RCE via session upload progress — requires an unusual runtime switch of `session.serialize_handler`; informational advisory, fixed in the routine release | — | regular release |

- **Affected:** PHP 5.4 → 8.5.11 (all SAPIs serving web requests; **Apache mod_php = highest risk**, PHP-FPM / php-cgi / FrankenPHP / LiteSpeed also affected)

- **EOL:** PHP ≤ 8.1 — no official patch (some distros/LTS vendors backported)

- **Entry point:** `session.upload_progress` (default **on**). A multipart POST with a `PHP_SESSION_UPLOAD_PROGRESS` field writes a progress record into the session file **during request startup**; `session.use_strict_mode=0` lets the attacker pick the ID via the `PHPSESSID` POST field.

- **Heap pressure:** chunked / lengthless requests bypass `post_max_size`; hundreds of empty `filename=""` parts with nested names (`files[a][b][c]…`) build six `$_FILES` entries each and don't count toward `max_file_uploads` → a The image `php:8.4.27-apache-bookworm` (patched) is handy as a negative control.

> A bare image ships no PHP files — copy `version.php`/`upload.php` in for parity.

./scanner.py 127.0.0.1:8090 # → VULNERABLE (8.4.26, mod_php)

./scanner.py -f targets.txt --json --workers 16

./scanner.py example.com --no-active --verbose # passive fingerprint only

./scanner.py example.com --crash-probe # opt-in OOM probe (may trigger the bug!)

Verdicts: `VULNERABLE` · `LIKELY_VULNERABLE` · `LIKELY_PATCHED` · `EOL` · `UNKNOWN`.

Exit codes: `0` clean · `1` ≥1 vulnerable/likely/EOL · `2` no targets reachable · `3` usage error.

Detection: version fingerprint (`X-Powered-By`, `Server`, phpinfo heading, JSON

`php_version`), SAPI hints (Apache+PHP → mod_php; `Set-Cookie: PHPSESSID` as

PHP-presence evidence), and a graded upload-progress probe (an app echoing the

parsed `PHP_SESSION_UPLOAD_PROGRESS` field is a strong signal). The README

documents how CISA's SIGMA rule, Nuclei, Corelight, Assetnote, Wiz and httpx

detect PHP2Shell — and where each falls short.

python3 exploit.py check

python3 exploit.py offsets assets/libphp.so # → zval_ptr_dtor=0x64eb60 zif_system=0x45a3b0

# leak attempt (A1 OOM producer → B1 consumer → decode heap from response/cookie)

python3 exploit.py leak \

# RCE attempt — claim success only on proof

python3 exploit.py rce \

--cmd 'touch /tmp/pwned' --spray 500 --workers 12 --retries 1 --timeout 60

podman exec php2shell-lab ls -la /tmp/pwned

Use `--dry-run` to print the exact spray/gadget bytes without sending anything.

**Verified** (transcripts in [`exploit/tests/`](exploit/tests)):

1. **A1 OOM producer** — 1.06 MB chunked multipart (860 empty `filename=""`

nested parts + `PHP_SESSION_UPLOAD_PROGRESS`) reliably triggers

`PHP Fatal error: Allowed memory size of 134217728 bytes exhausted

(tried to allocate 8192 bytes) in Unknown on line 0` → HTTP 500 — the exact

pre-app-code window of CVE-2026-109618. The worker survives the bailout.

2. **Full A1→B1 chain** — the 33 MB B1 leak consumer executes cleanly; the

response carries a normal ~40 B `PHPSESSID` cookie (no heap payload yet).

3. **Ground truth** — host-side `/proc//mem` reads of worker `ps_globals`

work (validated non-zero reads); `PS(id)` is NULL in all idle workers.

**Not yet achieved:** heap leak / RCE. Open items (details in

[`exploit/README.md`](exploit/README.md#furthest-verified-phase--open-issues)):

1. **Worker affinity** — with a growing prefork pool, A1 and B1 may land on

different workers; correlate A1's PID from `podman logs` with B1's.

2. **`ps_globals` offsets** — the `id@+0x10` doc is unverified for this build;

3. **Heap-landing offset** — `s_offset=0xF8398` is uncalibrated; use

`rce --sweep` (bounded) once (1) and (2) are fixed.

The original unbounded recipe (`--workers 149`) pinned a growing prefork pool —

up to ~150 workers × 128 MB PHP heap ≈ 19 GB worst case — and OOM-killed the

--workers 12 --retries 1 --timeout 60 # wrap runs in `timeout(1)`

free -m # check before/after (≥ 2 GB available observed)

`--workers 12` = pool 11 + 1 free for the chain. Avoid unbounded

`/proc//mem` scans; the helper reads are 0x200 B per worker.

- [calif.io/php2shell]( — discovery writeup (request B = session ID + progress field, no file part, same worker)

- [TheCyberGeek/php2shell-research]( — five PoC chains, Docker labs

- [Wiz — PHP2Shell]( — `PHPSESSID` cookie carrying reclaimed heap

- [Assetnote/php2shell-scanner]( — differential empty-500 detection

- [Corelight/php2shell-detect]( — Zeek/Suricata signatures

- [CISA alert + SIGMA rule]( · [PHP Foundation](

- PHP security release: [8.5.12 / 8.4.27 / 8.3.36 / 8.2.35]( · GHSA-w8hw-w9fx-j79w · GHSA-6wmf-4rv5-p3rp

Vulnerabilities discovered by Wiz with Calif Research and OpenAI ("Patch the

Planet"). This repository is an independent lab/reproduction for defensive

Extracted Entities