
CVE-2026-109618/109619 — 5 chaînes RCE + règles de détection (Suricata, Sigma, ModSecurity). Recherche sur l'exploitation pre-auth de PHP session.upload_progress.
CVE-2026-109618 & CVE-2026-109619 — Toolkit d'exploitation et de détection RCE pre-auth PHP
Exploits · Détection · Lab · Analyse
Cinq chaînes RCE indépendantes exploitant session.upload_progress de PHP et le bailout OOM du moteur Zend. 14 ans de code vulnérable — de PHP 5.4.0 (2012) à 8.5.11. Pre-auth. Aucune vulnérabilité applicative requise pour certaines chaînes.
Touche 78 % de tous les sites web — y compris WordPress (43 %), Joomla, Drupal, Laravel, Magento, et toute installation PHP par défaut.
Auteur : Qi Deng | Analyse : Substack | Date : 2026-10-21
| CVE | GHSA | CVSS | Description |
|---|---|---|---|
| CVE-2026-109618 | GHSA-w8hw-w9fx-j79w | 9.2 | OOM → longjmp() laisse l'état du moteur Zend invalide → RCE |
| CVE-2026-109619 | GHSA-6wmf-4rv5-p3rp | 9.2 | État global obsolète entre les requêtes des workers FPM → UAF → RCE |
Correctif : Commit 3584a98 — 300 fichiers modifiés dans le moteur Zend.
| Chaîne | Vecteur | Pre-auth | Conditions | SAPI |
|---|---|---|---|---|
| A | Injection de session + LFI | Oui | L'application possède un sink LFI quelconque | Toutes |
| B | UAF var_destroy → écrasement de handler | Non | L'application appelle unserialize() | Toutes |
| C | Incohérence de handler → __destruct | Oui | Deux répertoires avec des serialize_handler différents | FPM |
| D | Corruption OOM → EG() obsolète | Oui | Aucune — n'importe quel endpoint | mod_php |
| E | OOM de session FPM → BG() obsolète | Oui | Producteur : tout endpoint session_start() ; Consommateur : tout endpoint | FPM |
La chaîne D est la plus critique : RCE pre-auth sans dépendance contre toute installation Apache mod_php.
La chaîne E est presque aussi étendue sur FPM : le producteur nécessite tout endpoint qui appelle session_start() (quasi universel — WordPress, Laravel, Joomla, Drupal le font tous), et le consommateur peut être n'importe quel endpoint PHP — le handler upload_progress rfc1867 s'exécute au démarrage du SAPI avant le code applicatif. Vérifié : nosession.php (aucun session_start() dans le code) déclenche un crash 502 en consommant un état BG(unserialize) obsolète.
Trois exploits RCE (chaînes A, B, C) sont inclus dans exploit/ :
| Fichier | Chaîne | Ce qu'il fait |
|---|---|---|
chain_a_session_lfi.py | A | Injecte du code PHP via le nom de fichier uploadé → le LFI inclut le fichier de session → RCE |
chain_b_uaf_rce.php | B | UAF var_destroy → découvre zif_system via EG() → écrase le handler var_dump via /proc/self/mem → RCE |
chain_c_mismatch_rce.py | C | Pollue PS(serializer) du worker FPM → injecte un objet sérialisé via le nom de fichier → __destruct se déclenche à l'échec de décodage → RCE |
Les exploits des chaînes D et E sont disponibles pour les abonnés payants.
# 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'
Règles IDS / WAF / SIEM prêtes à l'emploi dans detection/ :
| Fichier | Format | Signatures |
|---|---|---|
php2shell.rules | Suricata / Snort | 13 règles — requête, réponse et reconnaissance |
php2shell.yaml | Sigma | 5 règles — journaux web, création de processus, événements de fichiers |
modsecurity.conf | ModSecurity v2/v3 | 7 règles — prêtes à l'emploi pour Apache/Nginx |
php2shell.lua | OpenResty Lua | Module de proxy inverse léger |
Atténuation la plus rapide : bloquer PHP_SESSION_UPLOAD_PROGRESS dans les corps de requêtes POST multipart. Usage légitime quasi nul, couvre le vecteur d'attaque principal des deux CVE.
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'
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
; Immediate — reduces attack surface
session.upload_progress.enabled = Off
session.use_only_cookies = On
La seule correction complète consiste à corriger PHP vers 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12+. La corruption OOM (Chaîne D) se trouve dans le cœur du moteur Zend — aucun paramètre INI ne la corrige.
Wiz a démontré une RCE pré-authentification sur des images de conteneurs standard :