
CVE-2026-109618/109619 — 5 cadenas de RCE + reglas de detección (Suricata, Sigma, ModSecurity). Investigación de explotación pre-autenticación de PHP session.upload_progress.
CVE-2026-109618 & CVE-2026-109619 — Kit de explotación y detección de RCE pre-autenticación en PHP
Exploits · Detección · Laboratorio · Análisis
Cinco cadenas de RCE independientes que explotan session.upload_progress de PHP y el bailout por OOM del motor Zend. 14 años de código vulnerable — desde PHP 5.4.0 (2012) hasta 8.5.11. Pre-autenticación. Algunas cadenas no requieren ninguna vulnerabilidad en la aplicación.
Afecta al 78% de todos los sitios web — incluyendo WordPress (43%), Joomla, Drupal, Laravel, Magento y toda instalación de PHP por defecto.
Autor: Qi Deng | Análisis: Substack | Fecha: 2026-10-21
| CVE | GHSA | CVSS | Descripción |
|---|---|---|---|
| CVE-2026-109618 | GHSA-w8hw-w9fx-j79w | 9.2 | OOM → longjmp() deja el estado del motor Zend inválido → RCE |
| CVE-2026-109619 | GHSA-6wmf-4rv5-p3rp | 9.2 | Estado global obsoleto entre peticiones de workers FPM → UAF → RCE |
Parche: Commit 3584a98 — 300 archivos modificados en el motor Zend.
| Cadena | Vector | Pre-auth | Condiciones | SAPI |
|---|---|---|---|---|
| A | Inyección de sesión + LFI | Sí | La aplicación tiene cualquier sink LFI | Todas |
| B | UAF en var_destroy → sobrescritura de handler | No | La aplicación llama a unserialize() | Todas |
| C | Desajuste de handler → __destruct | Sí | Dos directorios con serialize_handler diferente | FPM |
| D | Corrupción por OOM → EG() obsoleto | Sí | Ninguna — cualquier endpoint | mod_php |
| E | OOM de sesión en FPM → BG() obsoleto | Sí | Productor: cualquier endpoint con session_start(); Consumidor: cualquier endpoint | FPM |
La cadena D es la más crítica: RCE pre-autenticación sin dependencias contra cualquier instalación de Apache mod_php.
La cadena E es casi igual de amplia en FPM: el productor necesita cualquier endpoint que llame a session_start() (casi universal — WordPress, Laravel, Joomla y Drupal lo hacen), y el consumidor puede ser cualquier endpoint PHP — el handler de upload_progress rfc1867 se ejecuta durante el arranque del SAPI antes del código de la aplicación. Verificado: nosession.php (sin session_start() en el código) provoca un crash 502 al consumir el estado obsoleto de BG(unserialize).
Tres exploits de RCE (cadenas A, B, C) están incluidos en exploit/:
| Archivo | Cadena | Qué hace |
|---|---|---|
chain_a_session_lfi.py | A | Inyecta código PHP mediante el nombre de archivo subido → LFI incluye el archivo de sesión → RCE |
chain_b_uaf_rce.php | B | UAF en var_destroy → descubre zif_system vía EG() → sobrescribe el handler de var_dump vía /proc/self/mem → RCE |
chain_c_mismatch_rce.py | C | Contamina PS(serializer) del worker FPM → inyecta objeto serializado mediante el nombre de archivo → __destruct se dispara al fallar la decodificación → RCE |
Las explotaciones de las cadenas D y E están disponibles para suscriptores de pago.
# 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'
Reglas IDS / WAF / SIEM preconstruidas en detection/:
| Archivo | Formato | Firmas |
|---|---|---|
php2shell.rules | Suricata / Snort | 13 reglas — solicitud, respuesta y reconocimiento |
php2shell.yaml | Sigma | 5 reglas — registros web, creación de procesos, eventos de archivos |
modsecurity.conf | ModSecurity v2/v3 | 7 reglas — listas para usar en Apache/Nginx |
php2shell.lua | OpenResty Lua | Módulo ligero de proxy inverso |
Mitigación más rápida: bloquear PHP_SESSION_UPLOAD_PROGRESS en cuerpos POST multipart. Uso legítimo casi nulo, cubre el vector de ataque principal para ambas 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 única solución completa es parchear PHP a 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12+. La corrupción por OOM (Cadena D) está en el núcleo del motor Zend — ninguna configuración de INI lo soluciona.
Wiz ha demostrado RCE pre-autenticación en imágenes de contenedor estándar: