PHP2Shell: así auditamos y reforzamos nuestros servidores PHP
Cómo abordamos en Zonsai una alerta crítica de PHP en servidores de producción: inventario, parcheo, verificación de procesos, auditoría retrospectiva y mejoras de seguridad.
El 21 de octubre de 2026 se publicaron actualizaciones extraordinarias para corregir dos vulnerabilidades críticas de PHP, CVE-2026-109618 y CVE-2026-109619, conocidas como PHP2Shell. Ambas podían permitir la ejecución remota de código sin autenticación en determinadas condiciones. No se trataba de un problema exclusivo de WordPress: afectaba al intérprete que ejecuta las aplicaciones PHP. Por eso, incluso una aplicación correctamente desarrollada podía estar expuesta si su entorno no estaba corregido.
En nuestro primer artículo sobre PHP2Shell explicamos las vulnerabilidades y las versiones afectadas. Esta vez queremos contar cómo hemos gestionado la respuesta técnica en una infraestructura heterogénea, qué hemos encontrado al revisar los servidores y por qué una actualización de paquetes es solo una parte del trabajo.
La intervención nos ha permitido comprobar algo que cualquier equipo de sistemas conoce bien: un parche instalado no es necesariamente un parche en ejecución; y un servidor actualizado no es, por ese solo hecho, un servidor investigado.
Cuando una alerta de seguridad afecta a varios entornos a la vez
En Zonsai administramos servicios web y aplicaciones con perfiles muy distintos. Hay alojamientos compartidos con múltiples dominios, VPS dedicados, aplicaciones desarrolladas a medida, instalaciones WordPress, entornos de pruebas y servicios cuya infraestructura depende de otros proveedores.
También conviven diferentes sistemas Linux, PHP-FPM, Apache con mod_php, varias ramas de PHP instaladas simultáneamente y aplicaciones heredadas que no pueden migrarse de versión sin pruebas. Esa diversidad obliga a descartar la idea de ejecutar un mismo comando de actualización en todas las máquinas.
Definimos una secuencia de trabajo con varios objetivos: identificar el software realmente expuesto, aplicar o verificar el parche adecuado, asegurar que los procesos activos lo estaban utilizando, comprobar que las aplicaciones seguían funcionando y revisar los indicadores de actividad anterior. Las mejoras que requerían un proyecto diferente —como sustituir sistemas operativos obsoletos— quedaron documentadas, sin confundirlas con la mitigación urgente.
1. Identificar el PHP que ejecuta cada aplicación, no solo el de la consola
Uno de los errores más habituales es ejecutar php -v y dar por identificado el PHP de todas las webs del servidor. En Plesk, el comando puede mostrar una rama distinta de la que utiliza cada dominio. Incluso es posible que no exista un PHP global en el PATH y, sin embargo, las aplicaciones funcionen normalmente con los intérpretes gestionados por el panel.
Por eso distinguimos entre las versiones instaladas en el sistema, los controladores registrados y el PHP asociado realmente a cada sitio o aplicación. En Plesk resultan útiles comandos como los siguientes:
plesk bin php_handler --list
plesk bin php_handler --get-usage -id IDENTIFICADOR
Esta comprobación permite evitar cambios innecesarios y detectar versiones antiguas instaladas que ya no están asociadas a ninguna web, pero que podrían seguir siendo utilizadas por tareas programadas o herramientas de mantenimiento. Antes de retirarlas, es imprescindible revisar esas dependencias.
2. Aplicar parches oficiales y verificar también los backports
El proyecto PHP publicó como primeras versiones oficiales corregidas las siguientes:
| Rama PHP | Primera versión corregida |
|---|---|
| 8.5 | 8.5.12 |
| 8.4 | 8.4.27 |
| 8.3 | 8.3.36 |
| 8.2 | 8.2.35 |
En entornos con Plesk tuvimos que comprobar tanto el panel como los paquetes PHP que distribuye por separado. Actualizar PHP desde la distribución Linux no garantiza que se haya actualizado también el intérprete utilizado por un dominio de Plesk. Además, su propio motor administrativo cuenta con versiones y correcciones específicas.
En ramas fuera de soporte ordinario, como PHP 7.4, 8.0 u 8.1, el criterio fue diferente. No bastaba con comprobar el número de versión: verificamos fecha de compilación, origen del paquete y, cuando estaba disponible, la referencia explícita a las dos CVE en la documentación o en el registro de cambios del proveedor.
Plesk documentó compilaciones extraordinarias corregidas para algunas ramas antiguas. Esto permitió resolver la urgencia en entornos heredados sin forzar una migración inmediata que podía romper aplicaciones de producción. No obstante, disponer de un parche concreto no devuelve a una versión obsoleta su soporte general de seguridad.
3. Comprobar que los procesos en memoria han cargado el código actualizado
Este fue uno de los controles más importantes de toda la intervención. Tras sustituir bibliotecas y binarios en disco, algunos procesos de Apache, PHP-FPM o MariaDB pueden continuar utilizando bibliotecas antiguas que permanecen cargadas en memoria. En Linux pueden aparecer referenciadas como (deleted).
Encontrar una biblioteca con esa marca no constituye por sí mismo un indicador de malware. Normalmente significa que el archivo ha sido sustituido o eliminado mientras un proceso anterior seguía utilizándolo. Pero sí nos dice que debemos verificar si ese proceso necesita reiniciarse para incorporar la nueva versión.
En los servidores afectados validamos primero la configuración, reiniciamos de forma controlada únicamente los servicios necesarios y comprobamos después su estado y las bibliotecas utilizadas. Cuando el componente era crítico para una aplicación en uso, se tuvo en cuenta el posible impacto sobre las sesiones y las operaciones en curso.
El objetivo no era conseguir que el gestor de paquetes mostrase «actualizado», sino confirmar que los procesos que atendían peticiones habían incorporado las correcciones.
4. Aprovechar la intervención para cerrar otros puntos de exposición
Una alerta importante suele revelar aspectos de seguridad que no están directamente relacionados con la CVE original, pero que merece la pena resolver cuando se detectan.
Servicios de base de datos accesibles desde el exterior
En una de las comprobaciones identificamos una configuración de MariaDB que permitía conectividad externa donde no era necesaria. No nos conformamos con revisar la configuración: realizamos una prueba de conectividad desde fuera, aplicamos la restricción correspondiente y repetimos la prueba para confirmar que la conexión dejaba de ser posible.
Este ejemplo muestra por qué es importante combinar inventario de puertos, configuración efectiva y pruebas de verificación. Una base de datos debe exponerse únicamente cuando existe una necesidad justificada y con controles adecuados.
Tráfico automatizado contra XML-RPC en WordPress
El análisis de los registros permitió identificar, en determinadas instalaciones, volúmenes relevantes de solicitudes automatizadas a xmlrpc.php. Cuando la aplicación no necesitaba esa interfaz, se restringió el acceso y se comprobó la respuesta del servidor. También se revisaron variantes de la ruta para verificar que el bloqueo no se eludía por una normalización diferente de la URL.
Es importante no confundir estos intentos con una explotación confirmada de PHP2Shell: son indicadores de actividad contra otra superficie de WordPress. Su presencia justifica revisar controles, pero no permite concluir que alguien haya accedido con éxito.
Autenticación, WAF y componentes heredados
Revisamos además los accesos SSH, las protecciones de Fail2Ban, el estado de ModSecurity y las reglas disponibles en cada instalación. Donde aparecieron versiones antiguas de sistema operativo o de PHP, las registramos como deuda técnica y definimos una actuación posterior.
No aplicamos bloqueos indiscriminados ni cambiamos versiones mayores en aplicaciones antiguas sin comprobar previamente sus dependencias. La seguridad también consiste en evitar que una corrección precipitada provoque una caída de servicio.
5. Una revisión retrospectiva: mirar qué pudo ocurrir antes del parche
Un servidor puede estar actualizado hoy y haber permanecido expuesto durante días anteriores. Por eso, nuestro procedimiento incorporó una auditoría retrospectiva de indicadores sobre los registros disponibles y otras fuentes del sistema.
Revisamos, según las características de cada servidor, eventos de Apache y Nginx, solicitudes POST y rutas inusuales, errores de servicios, autenticaciones SSH, cuentas privilegiadas, archivos PHP recientes en ubicaciones sensibles, cambios en tareas programadas, procesos y conexiones de red, así como la configuración disponible de los mecanismos de protección.
La revisión se realizó mediante scripts Bash desarrollados y adaptados para diferentes generaciones de Debian, entornos CentOS y servidores con o sin Plesk. Estos scripts permitieron normalizar comprobaciones, conservar informes privados y aplicar un criterio consistente a entornos que, de otro modo, habrían requerido inspecciones manuales difícilmente comparables.
Los informes contenían información sensible —rutas, usuarios, versiones y datos de actividad—, por lo que se trataron como documentación interna. Las comprobaciones se diseñaron para no incorporar contraseñas, cookies ni contenidos de formularios a los resultados.
Una precisión necesaria: esta revisión es un triaje técnico retrospectivo, no un análisis forense integral. Los logs pueden estar incompletos, la rotación puede haber eliminado parte de los registros y algunos ataques no dejan un rastro concluyente en los accesos convencionales. La ausencia de indicadores no demuestra por sí sola la ausencia absoluta de compromiso. Si surgen evidencias serias, lo adecuado es preservar la información y activar una respuesta específica a incidentes.
6. Validar el funcionamiento después de intervenir
Después del parcheo y los reinicios, comprobamos el estado de los servicios y las respuestas web correspondientes. Esta verificación permite detectar problemas de arranque, configuraciones inválidas o fallos evidentes de disponibilidad.
Para completar la validación de una aplicación no basta con obtener un código HTTP 200. En función de su criticidad, recomendamos probar accesos autenticados, formularios, descargas, procesos de compra, integraciones y otras funcionalidades esenciales. Estas pruebas requieren una selección cuidadosa de casos y, en ocasiones, coordinación con el cliente.
Del mismo modo, documentamos cada excepción que no era razonable resolver durante la ventana urgente: versiones heredadas, limitaciones de proveedores externos, cambios de plataforma pendientes y mejoras de observabilidad.
7. Copias de seguridad y capacidad de recuperación: parte de la estrategia, no una garantía automática
La gestión responsable de un incidente de seguridad también exige pensar en la recuperación. En nuestra operativa de alojamiento contemplamos las copias externas, incluido almacenamiento compatible con Amazon S3 según el servicio, y las políticas de retención correspondientes.
Ahora bien, disponer de copias no equivale a haber demostrado que todos los sistemas son recuperables. La comprobación de la cobertura real, la integridad de los respaldos y las pruebas de restauración controladas deben formar parte del seguimiento periódico. Tampoco se debe restaurar a ciegas una copia potencialmente comprometida: primero hay que valorar su estado y la causa del incidente.
La seguridad de sistemas requiere prevención, capacidad de detección y un plan realista de recuperación. Ninguna de esas tres dimensiones sustituye a las otras.
8. Un ejemplo de comprobación que cualquier administrador puede adaptar
Parte del trabajo puede ilustrarse con una consulta sencilla, genérica y de solo lectura. Este ejemplo identifica procesos habituales que todavía tengan cargadas bibliotecas compartidas marcadas como eliminadas:
for nombre in apache2 php-fpm mariadbd mysqld; do
for pid in $(pgrep -x "$nombre" 2>/dev/null); do
if grep -qE '\.so.*\(deleted\)' "/proc/$pid/maps" 2>/dev/null; then
printf 'Revisar proceso: %s (PID %s)\n' "$nombre" "$pid"
fi
done
done
El resultado requiere interpretación. No debe reiniciarse automáticamente todo lo que aparezca en pantalla: antes hay que conocer el servicio, comprobar su configuración, identificar usuarios afectados y disponer de un procedimiento de verificación posterior.
Los scripts de auditoría completos que utilizamos internamente son más extensos y están adaptados a nuestras necesidades operativas. No es necesario distribuirlos para compartir las lecciones técnicas de esta intervención.
Checklist para responsables técnicos
Esta es la versión resumida de las comprobaciones que recomendamos realizar ante una alerta grave que afecte al intérprete PHP:
Inventario y preparación
- Identificar servidores, aplicaciones, versiones y controladores PHP realmente utilizados.
- Localizar sistemas operativos y ramas PHP fuera de soporte.
- Comprobar disponibilidad de copias y definir el plan de reversión antes de intervenir.
- Acordar el alcance y las ventanas de actuación con los responsables de cada servicio.
Parcheo y efectividad
- Instalar las versiones corregidas o comprobar el backport de las dos CVE.
- Verificar las versiones PHP gestionadas por Plesk, además de las del sistema.
- Validar configuraciones y reiniciar únicamente los servicios afectados.
- Comprobar que los procesos han dejado de utilizar bibliotecas anteriores.
Configuración y control de exposición
- Revisar, cuando proceda,
session.upload_progress.enabled, límites de recursos y de subida de archivos. - Verificar reglas WAF, Fail2Ban y exposición de puertos y bases de datos.
- Revisar SSH y accesos administrativos, evitando credenciales compartidas.
- Documentar excepciones de software heredado y medidas compensatorias.
Indicadores y continuidad
- Conservar registros y analizar actividad anterior a la publicación del parche.
- Investigar archivos y tareas nuevos sin asumir que todo cambio es malicioso.
- Probar los flujos esenciales de cada aplicación tras la intervención.
- Comprobar cobertura de copias y ensayar la recuperación periódicamente.
- Priorizar migraciones y establecer mecanismos de seguimiento y alerta.
La checklist debe adaptarse a cada infraestructura. No reemplaza una investigación forense cuando existen indicios sólidos de compromiso.
Lo que nos ha enseñado PHP2Shell como administradores de sistemas
En esta intervención, la parte más exigente no ha sido ejecutar actualizaciones, sino relacionar versiones, procesos, configuraciones, actividad anterior y continuidad del servicio sin aplicar recetas indiscriminadas.
Nos quedamos con cuatro principios:
Visibilidad: saber qué está instalado y, sobre todo, qué está ejecutándose de verdad.
Verificación: no dar un parche por efectivo hasta comprobar los procesos, las conexiones y los servicios.
Trazabilidad: conservar evidencias, explicar el alcance de las conclusiones y documentar las decisiones.
Continuidad: separar la respuesta urgente del mantenimiento estructural, con backups y planes de actualización que puedan demostrarse.
En Zonsai entendemos la administración de sistemas como una parte esencial del desarrollo y mantenimiento de aplicaciones. Es un trabajo que muchas veces no se ve desde el navegador, pero que determina si una plataforma puede seguir operando con fiabilidad cuando aparece una alerta de seguridad crítica.
Una infraestructura no es más segura porque nunca tenga incidencias, sino porque existe capacidad técnica para detectarlas, priorizarlas, corregirlas y verificar el resultado.