Back Sploitus Exploit for Improperly Controlled Sequential Memory Allocation in Php
([GHSA-w8hw-w9fx-j79w](
"RCE via OOM corruption", CVSS v4.0 **9.2 Critical**, CWE-416) — one of the
two PHP core advisories fixed on **2026-10-21** in
> **Overview** — PHP handled out-of-memory errors with `longjmp()`. During
> the multipart (`rfc1867`) parsing window — which runs **before** the
> application and before full request initialization — request memory can be
> reachable but not fully initialized. An allocation failure there bails out
> and leaves invalid state; `php_request_shutdown()` still runs over it
> (mod_php always runs shutdown, even after a failed startup). Request-owned
> state published in worker globals survives the heap free and can be
> consumed by later requests on the same worker. The vendor-confirmed impact
| Pre-application OOM abort during request startup (stock limits: `memory_limit=128M`, `post_max_size=8M`) | **captured** | `evidence/02-trigger-oom-request-startup.txt` — `Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 69632 bytes) in Unknown on line 0` |
| Worker-pool degradation after aborts (DoS tier) | **captured** — 8/8 connection drops following aborts | `evidence/04-recorded-loop-receipts.txt` |
| Patched-build negative test (php-8.5.12, source-built) | **captured** — zero receipts, both PoC variants | `evidence/03-negative-patched-build.txt` |
| Cross-request UAF sanitizer receipt / memory disclosure / RCE | **documented, not reproduced here** | see reference links: vendor-confirmed RCE on stock WordPress/Drupal/Joomla (Wiz), both independent audits report full RCE requires per-build offsets + heap grooming |
Two independent peer-review passes were performed on this material (one
reject-and-fix iteration, one confirmation pass with zero blocking items).
poc/exploit_opt.py compact driver (seed -> arm -> fire)
poc/exploit_readable.py same chain, tutorial-grade
evidence/ captured lab transcripts (paths scrubbed)
Evidence transcripts are kept as captured; some `Command:` headers in them
reference the foundry's internal workspace layout (and an internal trigger
probe equivalent to the PoC's seed stage). The shipped `poc/` drivers
python3 poc/exploit_opt.py --url
python3 poc/exploit_readable.py --url
# negative check on a patched build must print no receipts (exit 2)
Knobs: `--key-mb` (progress-key size; grows the session file via aborted
seeds), `--seed-pad-mb` (padding so the seed aborts after the progress-entry
Expected on a vulnerable target: each aborted seed returns the OOM fatal
(`in Unknown on line 0` = fired during request startup, outside application
code), and `/tmp/sess_*` inside the container shows the persisted oversized
`upload_progress_*` keys. Expect worker-pool degradation after several
aborts — DoS-class corroboration, **not** a use-after-free receipt; the tool
prints each tier's receipt status separately and never claims an unreached
## Notes that matter if you study this bug
- The gate is at `main/rfc1867.c:697`: the `post_max_size` check compares
the **declared** `Content-Length` only. A chunked request declares no
length, so parsing continues until the real limiter — `memory_limit` —
- The widely repeated "cached `post_bytes_processed` zval pointer UAF"
(`php_session_rfc1867_callback`) is **not a UAF**: `Z_TRY_ADDREF` keeps the
progress array alive. Both public audits reached the same conclusion.
- Per-SAPI behavior differs: mod_php streams chunked bodies (bypass works);
the built-in server buffers them and derives their length (gate fires as a
- The fix (`31c0ea7d7f` "Avoid state corruption via bailout", php-src) is
shared with the sibling advisory CVE-2026-109619: OOM no longer
`longjmp()`s (delayed soft OOM + hard `_exit()` threshold), `ZEND_HAS_OOM()`
checks through the parser, part-header keep-list, pre-RINIT session decode
locked to `__PHP_Incomplete_Class`, early global resets.
1. **The complete fix is the updated release:** update to
2. `session.upload_progress.enabled=0` closes the session-lifecycle paths
(incomplete for other state families). On 8.5 also
`fatal_error_backtraces=0` removes the confirmed backtrace producer.
3. Do NOT use `RLIMIT_AS`/`RLIMIT_DATA` (mmap failure re-enters the
4. Frontend: block/rate-limit multipart POSTs where not needed; keep
`post_max_size` conservative; keep `fastcgi_request_buffering on` (nginx).
A self-contained `docker compose` lab ships in `lab/` (dedicated
network; ports published to loopback only):
docker compose build # vulnerable twin from a pinned image + ASAN and
# patched twins built from source (~25 min)
docker compose up -d # 8080=vuln(8.5.11) 8081=fixed(8.5.12) 8082=asan
curl # expect: app-ok 8.5.11, sapi=apache2handler
The compose file builds with `network: host` — on hosts whose resolver is
unroutable from bridge networks (AAAA-only DNS, no IPv6 route) that is
required; remove it if your host has clean bridge DNS.
- `Allowed memory size of ... exhausted ... in Unknown on line 0` with no
- Oversized/malformed `PHPSESSID` response cookies.
- Unexplained worker churn / connection drops after multipart bursts.
This material is for **authorized security research and defense work on
systems you own or are explicitly permitted to test**, in isolated lab
environments. The maintainers released fixes on the disclosure date; for
post-fix testing use a source build of the last vulnerable tag
(`php-8.5.11`). No warranty, see `LICENSE`.
- [GHSA-w8hw-w9fx-j79w — RCE via OOM corruption](
- [GHSA-6wmf-4rv5-p3rp — companion advisory (stale global state)](
- Wiz Research "PHP2Shell" blog; Calif + OpenAI disclosure blogs
- JackalSyn "php-up-2026" writeup (SAPI survival matrix, validation receipts)
Prepared with the b63 exploit-foundry tooling: advisory verification against
primary sources, a reproducible pinned-build lab, two PoC variants, captured
transcripts including a patched-build negative test, and two adversarial
review passes. Feedback and corrections welcome via issues.
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.
