Back Sploitus Exploit for Improperly Controlled Sequential Memory Allocation in Php
| A | FPM 8.2.34 `:18080` | **OK** | `uid=33(www-data)` through session injection + LFI |
| A | FPM 8.2.35 `:18082` | **OK** | same, confirming this chain is not fixed by the PHP patch |
| C | FPM 8.2.34 `:18080` | **OK** | `__destruct` gadget fired after the handler mismatch |
| D | mod_php 8.2.34 `:18081` | **partial** | OOM in the multipart parser; **no code execution attempted** |
| E | FPM 8.2.34 `:18080` | **not reproduced** | producer OOM observed, stale consumer state not reproduced |
Unit tests cover the request builders, the WAF, the guard and all four
verifiers. The end-to-end outputs are in [docs/VERIFICATION.md](docs/VERIFICATION.md).
Requirements: Go 1.22+ and Docker (for the lab only).
git clone
docker compose -f lab/docker-compose.yml up -d
go run ./cmd/php2shell verify chain-e # experimental, may fail
`verify all` expects the default lab ports. Use `--fpm-target` and
| `--target` | ` | target base URL |
| `--allow-public` | `false` | allow a non-local target (authorized systems only) |
| `--command` | `id` | command executed by chains A/C |
| `--session-dir` | `/tmp/sessions` | `session.save_path` on the target |
| `--stall` | `true` (chain A) | hold the upload open while triggering the LFI |
| `--attempts` | `3` | retries for race-dependent steps |
| `--headers`, `--header-size` | `30000`, `512` | chain D OOM amplification |
| `--size` | `24 MiB` | chain E seeded session size |
# A: default cleanup=On target, with a stalled upload
php2shell verify chain-a --target
# A: target with session.upload_progress.cleanup=Off
php2shell verify chain-a --target --stall=false
# C: lab endpoints with different serialize_handler values
php2shell verify chain-c --target --attempts 5
php2shell verify chain-d --target
php2shell verify chain-e --target --size 25165824
Exit codes: `0` all selected chains confirmed, `1` at least one failed,
`2` usage error. `verify all` currently exits `1` because chain E is not
confirmed; run the individual commands if you need a green run.
Chain C interpolates the command into a serialized gadget, so it must not
contain `"`, `\` or NUL bytes. Chain A passes the command as a query parameter
Run the WAF as a reverse proxy in front of the lab (or any PHP upstream):
- a `PHPSESSID` form field (session id in the body);
- `<?` or `|O:` / `|a:` / `|C:` / `|s:` in an upload filename;
- optionally, a chunked multipart body (`--block-chunked`).
`--log-only` observes without blocking. A blocked request returns `403` with a
php2shell rules check # UUID/ID validation and duplicates
The ModSecurity rules use `ARGS_POST` and `FILES_NAMES` (not `REQUEST_BODY`,
which is usually empty for multipart). Enable `SecRequestBodyAccess On`; the
response rule also needs `SecResponseBodyAccess On`.
| Service | Image | Host port | Purpose |
|---------|-------|-----------|---------|
| `fpm` | `php:8.2.34-fpm` | `:18080` via nginx | vulnerable FPM target |
| `fpm-patched` | `php:8.2.35-fpm` | `:18082` via nginx | patched differential target |
| `apache` | `php:8.2.34-apache` | `:18081` | mod_php target (chain D) |
| `nginx` | `nginx:1.27-alpine` | `:18080`, `:18082` | FastCGI front end |
Endpoints include `/index.php` (session), `/vuln.php?page=` (LFI), `/app/` and
`/api/` (`.user.ini` handler mismatch), `/nosession.php` and
`/seed_session.php` (lab-only chain E seeder). See [lab/README.md](lab/README.md).
The compose file is committed, so `docker compose up -d` works without a setup
script. `lab/setup.sh` is only a convenience wrapper.
- No target lists, no CIDR scans, no concurrency across hosts.
- No WAF evasion, payload encoding, or persistence.
- No exploit for chain B: it needs PHP-side code execution, not an HTTP client.
- Chains D and E do not produce code execution here; they demonstrate the crash
- [GHSA-w8hw-w9fx-j79w]( — CVE-2026-109618
- [GHSA-6wmf-4rv5-p3rp]( — CVE-2026-109619
- [PHP security release](
- [SANS ISC diary](
- [Original Python research](
MIT. Use only against systems you are authorized to test.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
