php2shell-poc README

The project's README from github.com/ikow/php2shell-poc. As one markdown file: README.md.

php2shell

php2shell

CVE-2026-109618 & CVE-2026-109619 — PHP Pre-Auth RCE Exploit & Detection Toolkit

Stars CVSS 9.2 Affected Versions Fixed Versions Exploits

Exploits · Detection · Lab · Writeup


Five independent RCE chains exploiting PHP's session.upload_progress and the Zend engine's OOM bailout. 14 years of vulnerable code — PHP 5.4.0 (2012) through 8.5.11. Pre-auth. No application vulnerability required for some chains.

Impacts 78% of all websites — including WordPress (43%), Joomla, Drupal, Laravel, Magento, and every default PHP installation.

Author: Qi Deng  |  Writeup: Substack  |  Date: 2026-10-21

CVE Details

CVE GHSA CVSS Description
CVE-2026-109618 GHSA-w8hw-w9fx-j79w 9.2 OOM → longjmp() leaves Zend engine state invalid → RCE
CVE-2026-109619 GHSA-6wmf-4rv5-p3rp 9.2 Stale global state across FPM worker requests → UAF → RCE

Patch: Commit 3584a98 — 300 files changed across the Zend engine.

Attack Chains

Chain Vector Pre-auth Conditions SAPI
A Session injection + LFI Yes App has any LFI sink All
B var_destroy UAF → handler overwrite No App calls unserialize() All
C Handler mismatch → __destruct Yes Two dirs with different serialize_handler FPM
D OOM corruption → stale EG() Yes None — any endpoint mod_php
E FPM session OOM → stale BG() Yes Any session_start() endpoint FPM

Chain D is the most critical: zero-dependency pre-auth RCE against any Apache mod_php installation. No LFI, no app vulnerability, no authentication — just a single multipart POST.

Exploits

Three RCE exploits (Chains A, B, C) are included in exploit/:

File Chain What It Does
chain_a_session_lfi.py A Injects PHP code via upload filename → LFI includes session file → RCE
chain_b_uaf_rce.php B var_destroy UAF → discovers zif_system via EG() → overwrites var_dump handler via /proc/self/mem → RCE
chain_c_mismatch_rce.py C Pollutes FPM worker PS(serializer) → injects serialized object via filename → __destruct fires on decode failure → RCE

Chains D and E exploits are available to paid subscribers.

# Chain A: Session injection + LFI → RCE
python3 exploit/chain_a_session_lfi.py --host TARGET --port 80 --command 'id'

# Chain B: var_destroy UAF → RCE (run on target or via uploaded webshell)
php exploit/chain_b_uaf_rce.php

# Chain C: Handler mismatch → __destruct → RCE
python3 exploit/chain_c_mismatch_rce.py --host TARGET --port 80 --command 'id'

Detection Rules

Pre-built IDS / WAF / SIEM rules in detection/:

File Format Signatures
php2shell.rules Suricata / Snort 13 rules — request, response, and recon
php2shell.yaml Sigma 5 rules — web logs, process creation, file events
modsecurity.conf ModSecurity v2/v3 7 rules — drop-in for Apache/Nginx
php2shell.lua OpenResty Lua Lightweight reverse proxy module

Fastest mitigation: block PHP_SESSION_UPLOAD_PROGRESS in multipart POST bodies. Near-zero legitimate use, covers the primary attack vector for both CVEs.

Quick Start

git clone https://github.com/ikow/php2shell-poc.git && cd php2shell-poc

# Start the lab (PHP-FPM + nginx + Apache mod_php)
cd lab && docker compose up -d

# Verify each chain
python3 ../poc/verify_session_injection.py --target http://127.0.0.1:18080
python3 ../poc/verify_handler_mismatch.py --target http://127.0.0.1:18080
python3 ../poc/verify_oom_trigger.py --host 127.0.0.1 --port 18081
python3 ../poc/verify_fpm_stale_state.py --target http://127.0.0.1:18080

# Run an exploit
python3 ../exploit/chain_a_session_lfi.py --host 127.0.0.1 --port 18080 --command 'id'

Repository Structure

php2shell-poc/
├── exploit/
│   ├── chain_a_session_lfi.py        # RCE: session injection + LFI
│   ├── chain_b_uaf_rce.php           # RCE: var_destroy UAF → handler overwrite
│   └── chain_c_mismatch_rce.py       # RCE: handler mismatch → __destruct
├── detection/
│   ├── php2shell.rules               # Suricata / Snort IDS rules
│   ├── php2shell.yaml                # Sigma SIEM detection rules
│   ├── modsecurity.conf              # ModSecurity WAF rules
│   └── php2shell.lua                 # OpenResty / Nginx Lua WAF module
├── poc/
│   ├── verify_session_injection.py   # Verify Chain A
│   ├── verify_uaf_asan.php           # Verify Chain B (ASAN)
│   ├── verify_handler_mismatch.py    # Verify Chain C
│   ├── verify_oom_trigger.py         # Verify Chain D
│   └── verify_fpm_stale_state.py     # Verify Chain E
├── lab/
│   ├── docker-compose.yml            # PHP-FPM + nginx + Apache mod_php
│   ├── setup.sh                      # One-click lab setup
│   └── php.ini / php-apache.ini      # Vulnerable PHP configs
└── docs/
    ├── ANALYSIS.md                   # Full technical analysis
    └── substack_article.md           # Writeup source

Mitigation

; Immediate — reduces attack surface
session.upload_progress.enabled = Off
session.use_only_cookies = On

The only complete fix is patching PHP to 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12+. The OOM corruption (Chain D) is in the Zend engine core — no INI setting fixes it.

Downstream Impact

Wiz has demonstrated pre-auth RCE on stock container images:

Platform Vulnerable Notes
WordPress Yes Core doesn't use PHP sessions, but WooCommerce and many plugins do
Joomla Yes Uses native PHP sessions by default
Drupal Yes Uses native PHP sessions by default
Magento Yes Vulnerable even in maintenance mode
Laravel Yes PendingBroadcast is a known __destruct gadget

References

Disclaimer

This repository is for authorized security testing and educational purposes only. Exploit code for Chains D and E (zero-dependency RCE) is available to paid subscribers of the writeup.

License

MIT


Keywords: php2shell, CVE-2026-109618, CVE-2026-109619, PHP RCE, PHP exploit, session.upload_progress, pre-auth RCE, PHP vulnerability, PHP session injection, PHP deserialization, PHP OOM, PHP memory corruption, use-after-free, GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp, WordPress RCE, Joomla RCE, Drupal RCE, PHP security, WAF rules, Suricata rules, ModSecurity rules, IDS signatures, PHP 8.2.35, PHP 8.4.27, session upload progress, PHP session fixation, rfc1867, longjmp, zend_bailout, Snort rules, Sigma rules, detection rules, PHP patch, PHP critical vulnerability

php2shell-poc (ikow/php2shell-poc)

php-security
Searching Database…

What is this?This is a security research repository documenting five pre-auth remote code execution chains in PHP's session.upload_progress and Zend engine internals (CVE-2026-109618 and CVE-2026-109619), with proof-of-concept exploits and ready-made detection rules.
Is this a ready-to-use exploit kit or just a research write-up?It ships working Python/PHP proof-of-concept exploits for three of the five chains (A, B, C) plus Suricata, Sigma and ModSecurity detection rules; the two most dangerous zero-dependency chains (D and E) have their exploit code withheld and sold to paid subscribers of the writeup.
How do I run the exploits or deploy the detection rules?The three included PoCs (chain_a_session_lfi.py, chain_b_uaf_rce.php, chain_c_mismatch_rce.py) live in exploit/ and run directly against a target PHP app, while the Suricata, Sigma and ModSecurity files in detection/ can be dropped straight into an existing IDS/WAF/SIEM stack.
What conditions does a target need for each chain to work?Chain A needs an app with any LFI sink, Chain B needs the app to call unserialize(), Chain C needs two directories with different session.serialize_handler settings under PHP-FPM, and Chain D needs nothing beyond a stock Apache mod_php install; all chains affect PHP from 5.4.0 through 8.5.11.
Is there a real fix, and does the repo include the worst exploit?The only complete fix is upgrading PHP to 8.2.35/8.3.36/8.4.27/8.5.12+, since the Chain D flaw lives in the Zend engine core and no INI setting patches it; the public repo describes Chain D but doesn't include its exploit code.
What's the fastest way to block these attacks without patching PHP?Block the PHPSESSID upload_progress parameter in multipart POST request bodies at the WAF/proxy layer — it has almost no legitimate use and covers the primary attack vector for both CVEs.
Which real-world platforms are vulnerable?WordPress (via WooCommerce/plugins), Joomla and Drupal are vulnerable because they use native PHP sessions, Magento is vulnerable even in maintenance mode, and Laravel has a known destruct gadget; together these cover 78% of websites.
What makes Chain D the most dangerous?Chain D is a zero-dependency pre-auth RCE against any stock Apache mod_php install — no LFI, no app vulnerability and no authentication required, just a single multipart POST exploiting OOM-triggered Zend engine state corruption.
Who disclosed this and where's the full writeup?Researcher Qi Deng disclosed both CVEs on 2026-10-21 with a detailed writeup on Substack, and Wiz has independently confirmed pre-auth RCE against stock container images.
Creator
ikow
Size
2.7 MB
Stars
1.8K
Updated
CommitOct 22
Age
5d
Commits · 90 Days