PHP2Shell dejó de ser un aviso teórico. El 26 de octubre de 2026, el equipo de investigación de Dream publicó los artefactos de una campaña que encadenó las dos vulnerabilidades críticas de PHP parchadas el 21 de octubre (CVE-2026-109618 y CVE-2026-109619) con Fragnesia, un fallo del kernel de Linux, para obtener root en 25 servidores. Entre ellos hay tres de un entorno que Dream describe como afiliado al gobierno de Estados Unidos. Todo empezaba con una sola petición HTTPS, sin credenciales, contra la interfaz de administración de un firewall expuesta a internet. Si administras servidores con PHP o equipos con panel web, esta es la versión práctica de por qué no se pospone un parche.
Qué encontró Dream
Según el reporte, los investigadores hallaron el 25 de octubre el kit completo de la operación: un exploit propio de PHP2Shell (no una copia de los públicos), el exploit de Fragnesia (CVE-2026-46300), listas de objetivos, bitácoras de explotación y unos 40 scripts de post-explotación. Los equipos comprometidos corren versiones específicas del software de firewall de "un fabricante grande". Dream no revela la marca ni las versiones afectadas por seguridad, y dice que ya avisó al fabricante.
El sistema operativo de esos firewalls usa PHP 8.0.30, una rama que el proyecto PHP ya no mantiene, con un límite de memoria alto que, según Dream, facilita las etapas de corrupción de memoria. El servidor web de administración atiende peticiones sin autenticar, y ahí entra el ataque.
Cómo funciona la cadena
Dream describe cuatro etapas dentro del exploit de PHP:
- Agotar la memoria. El atacante manda peticiones multipart con nombres de archivo enormes y datos de progreso de sesión (
session.upload_progress) hasta llevar a PHP a unos 383 MB y forzar un acomodo de memoria predecible. - Filtrar una dirección. Una segunda petición provoca una lectura fuera de límites, y la cabecera
Set-Cookiede la respuesta devuelve un puntero con la dirección base delibphp.so. - Dejar una referencia colgada. Otra ronda de presión de memoria (unos 500 MB) deja una referencia a memoria ya liberada.
- Ejecutar. La última petición falsifica una entrada de tabla hash en esa memoria cuyo destructor apunta a la función
system()de PHP. Cuando PHP limpia la petición, ejecuta el comando del atacante como el usuarionobody.
Con eso no bastaba: SELinux impedía a ese proceso modificar archivos del sistema. Por eso el segundo eslabón es Fragnesia, una escalada local de privilegios en el subsistema XFRM ESP-in-TCP del kernel. Según Dream, el exploit escribe en la caché de páginas para reemplazar las reglas de /etc/pam.d/su por pam_permit.so, que acepta cualquier cosa. Después de eso, su root entra sin contraseña. De la conexión inicial al webshell con root pasan menos de 15 minutos.

Del escaneo masivo a Active Directory
La campaña siguió un embudo muy claro, siempre según el reporte:
| Etapa | Cantidad |
|---|---|
| Firewalls del fabricante expuestos, encontrados con el buscador chino FOFA | ~19,000 |
| Respondieron con su versión | ~5,000 |
| Filtrados a EE. UU., Japón, Taiwán y Corea del Sur y a versiones con perfil de exploit | 240 |
| Firewalls con root tras el lote automático | 24 |
| Servidor interno de administración comprometido después | 1 (25 en total) |
El exploit necesita direcciones de memoria distintas para cada versión del sistema del firewall. Dream encontró 11 perfiles de versión en JSON, extraídos del libphp.so de cada una, y señala que el atacante tenía perfiles para nueve versiones explotables.
En 22 de los 24 firewalls el atacante solo dejó un webshell de 103 bytes y se fue. Dream los llama "owned and parked": comprometidos y estacionados para volver cuando quiera. Los otros dos pertenecían a la misma organización. La configuración extraída del primero mostraba autenticación con tarjeta CAC, nombres de equipo con estilo gubernamental y la topología interna completa: controladores de dominio, servidor central de administración de firewalls, Keycloak, GitLab y VPN. Ese primer firewall se cayó poco después, probablemente por los ~900 MB de tráfico del exploit. El segundo cayó el 24 de octubre a las 10:09 UTC.
A partir de ahí, según el reporte, el atacante montó un túnel SSH inverso de ocho puertos que sobrevive a reinicios, usó ese túnel para lanzar la misma cadena contra el servidor interno que administra todos los firewalls de la organización (11:35 UTC, menos de 90 minutos después) y desde ahí atacó Active Directory. Descifró la contraseña de la cuenta de servicio LDAP guardada en la configuración, enumeró usuarios y grupos e hizo password spraying contra todas las cuentas. El dominio tenía lockoutThreshold=0, o sea, sin bloqueo por intentos fallidos. También intentó crear cuentas de usuario y de máquina como puerta trasera y sacar la llave de firma SAML de Keycloak. Dream no pudo confirmar si estos últimos ataques funcionaron, porque los resultados se quedaron en el servidor comprometido.
Atribución y la IA en el kit
Dream no atribuye la operación a un grupo concreto, pero enumera indicios de un origen ligado a China: los cuatro países objetivo, el uso de FOFA y de la herramienta de túneles iox, relojes en UTC+8 y mensajes en chino en las bitácoras de una plataforma de pentesting llamada aiscan configurada con DeepSeek y Kimi. En la infraestructura también había Claude Code instalado. Dream aclara que no tiene evidencia directa de que la IA escribiera el exploit. Lo sugiere por la estructura y la consistencia de los ~40 scripts, y dice que no parece un ataque totalmente autónomo.
Mi lectura: el detalle de la IA es lo que más ruido va a hacer, pero no es lo que tumbó a nadie. Lo que tumbó a estas organizaciones fue un panel de administración abierto a internet, con un PHP fuera de soporte, y un dominio sin bloqueo de cuentas. Son fallas de higiene de hace veinte años.
Qué dice PHP y qué hacer
El 21 de octubre, el proyecto PHP publicó PHP 8.5.12, 8.4.27, 8.3.36 y 8.2.35 y pidió actualizar de inmediato. Su aviso dice que están en riesgo "todas las instalaciones de PHP que sirven peticiones web", incluidas PHP-FPM, Apache con mod_php, php-cgi, FrankenPHP y LiteSpeed, y que el riesgo es mayor con mod_php. El advisory de CVE-2026-109618 aclara que con LSAPI (LiteSpeed) los exploits dependientes de la aplicación son "probables pero no validados". Para PHP 8.1 y anteriores no hay versiones oficiales, pero el equipo de seguridad publicó backports mínimos en código fuente para 7.4, 8.0 y 8.1. Ese es justo el caso de los firewalls con 8.0.30: depende del fabricante.
Si no puedes actualizar hoy, PHP propone mitigaciones parciales y deja claro que "no hacen segura una instalación":
- CVE-2026-109618 (corrupción por falta de memoria):
memory_limit=-1impuesto a nivel administrador, unpost_max_sizebajo (8M si no hay subidas, 32M si las hay) y límites de tamaño de petición, campos y partes multipart en el servidor web o proxy. - CVE-2026-109619 (estado global obsoleto):
session.upload_progress.enabled=0enphp.inio en la configuración del pool, reiniciando todos los workers. No sirve hacerlo conini_set()ni con.user.ini. En PHP 8.5, además,fatal_error_backtraces=0.
El 23 de octubre, PHP añadió un aviso informativo sobre un tercer fallo, CVE-2026-115560, que solo aplica si la aplicación cambia session.serialize_handler a php en tiempo de ejecución con upload progress activo. Lo arreglará en la siguiente versión regular y recomienda desactivar upload progress mientras tanto.
Sobre Fragnesia: se divulgó en mayo con una prueba de concepto pública. Ubuntu le da prioridad alta ("trivial local privilege escalation") y publicó kernels corregidos desde junio. Red Hat la califica como Important porque requiere acceso local. Esta campaña muestra por qué "requiere acceso local" no tranquiliza a nadie: el acceso local se lo dio PHP. Si no puedes reiniciar con un kernel nuevo, Ubuntu remite a la misma mitigación de Dirty Frag, que consiste en bloquear los módulos esp4, esp6 y rxrpc.
La lista corta para quien opera servidores:
- Confirma la versión de PHP de cada SAPI (CLI, FPM, LSAPI), no solo la de la terminal, y reinicia los workers después de actualizar.
- Actualiza el kernel y reinicia de verdad. Un parche instalado sin reinicio no protege.
- Saca de internet las interfaces de administración de firewalls, NAS, routers y paneles: VPN, lista blanca de IPs o red privada.
- Pregúntale a tu proveedor de appliances qué versión de PHP trae su firmware y cuándo llega el parche.
- Revisa en Active Directory el umbral de bloqueo de cuentas y
MachineAccountQuota.
Fuentes
- Chained PHP2Shell Exploit Roots 25 Servers, including US Government Servers — Dream Research
- Security advisory: Critical remote code execution vulnerabilities, update now — PHP.net
- GHSA-w8hw-w9fx-j79w (CVE-2026-109618) — php-src
- GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) — php-src
- Informational advisory: Session upload progress — PHP.net
- CVE-2026-46300 — Ubuntu Security
- CVE-2026-46300 — Red Hat
- Fragnesia FAQ — Tenable