syrex1013 / php2shell
git clone https://github.com/syrex1013/php2shell.git
CVE-2026-109618/109619 PoC — PHP session.upload_progress heap use-after-free (CVSS 9.2)
+56
stars, 24h · #699
+113
stars, 7 days · #1,892
+113
stars, 30 days · #6,280
113
★ total · +113% this week
73
forks · 0 open issues
Star history (as recorded here)
LanguagePython
LicenseMIT
Created2026-10-21 (1d ago)
Last push1d ago
Watchers0
OwnerUser
Links
README excerpt
# php2shell — CVE-2026-109618 / CVE-2026-109619 PoC > **Heap Use-After-Free in PHP `session.upload_progress`** > CVSS 9.2 · PHP 5.4.0 – 8.2.34 / 8.3.35 / 8.4.26 / 8.5.11 This repository contains: | Component | Purpose | |-----------|---------| | `poc.py` | Full RCE exploit chain (session poison + LFI, log poison, FastCGI no-LFI, PEAR webshell) | | `lab-uaf/` | Docker lab that reproduces the UAF primitive on PHP 8.4.4-fpm | | `lab/` | Apache-based lab for testing the session-poison + LFI RCE chain | --- ## Vulnerability PHP's `ext/session/session.c` rfc1867 upload-progress handler caches raw `zval*` pointers into the session HashTable (`arData`) at lines 3292 and 3318. When a multipart upload stalls longer than `session.upload_progress.min_freq` (default 1 s), a second `FILE_DATA` event triggers `php_session_rfc1867_update()` → `php_session_initialize()` → `php_session_track_init()`, which **frees the HashTable** (lines 236–252). The cached pointers now reference freed `arData` slots. The next write at lines 3331–3332 (a `ZVAL_LONG` that stores `bytes_processed`) writes through those stale pointers — a classic heap use-after-free. ### Affected versions | Branch | Vulnerable through | Fixed in | |--------|-------------------|---------| | PHP 8.2 | 8.2.34 | **8.2.35** | | PHP 8.3 | 8.3.35 | **8.3.36** | | PHP 8.4 | 8.4.26 | **8.4.27** | | PHP 8.5 | 8.5.11 | **8.5.12** | | PHP ≤ 8.1 | all | no backport — EOL | ### Root cause (session.c) [code] --- ## UAF Lab Reproduces the stale-pointer write on stock PHP-FPM (no ASAN, no debug build). ### Requirements - Docker + Docker Compose - Python 3.8+ ### Quick start [code] Expected output: [code] ### PoC options [code] ### How the exploit works [code] ### Heap spray mode With `--spray N`, `N` dummy file parts with 231-character filenames are prepended. Each filename becomes a 256-byte `zend_string` (24-byte header + 231 chars + 1 null = 256 bytes), matching the size of the 8-entry session HashTable `arData` (8 × 32-byte `Bucket` = 256 bytes). Exhausting the ZendMM 256-byte bin forces the freed `arData` chunk into a different slab path, increasing the probability that the stale write corrupts a live allocation rather than silently hitting the re-allocated `arData`. [code] --- ## RCE Exploit (`poc.py`) Full exploit chain with multiple fallback paths. Requires a PHP web application running a vulnerable PHP version. ### Usage [code] ### Exploit chain (ordered by reliability) | Stage | Method | Requirements | |-------|--------|-------------| | 1 | Session poison + LFI | App has `include($_GET[...])` or similar | | 2 | Log poisoning + LFI | Apache/nginx write access log readable via LFI | | 3 | FastCGI direct (no LFI) | php-fpm port reachable (9000–9003) | | 4 | PEAR webshell drop | `/usr/share/php/pearcmd.php` accessible | ### Options [code] ### Lab (Apache + LFI) [code] Expected: [code] --- ## Mitigation ### Immediate (no patch required) [code] ### Patch Update PHP to the fixed release for