En resumen: Si PHP-FPM, Apache u otro proceso del servidor web inicia una shell como sh o bash, es una de las señales de alerta más fuertes de una intrusión a través del sitio web. Revise el árbol de procesos, la línea de comandos y el directorio de trabajo de la shell antes de terminar nada. Algunas shells breves y aisladas pueden ser legítimas; las que se ejecutan mucho tiempo con herramientas de red casi nunca lo son.
Por qué este patrón dice tanto
Un servidor web responde a peticiones. PHP-FPM, el gestor de procesos que ejecuta los scripts PHP para el servidor web, normalmente no inicia para ello ningún otro programa. Una shell bajo el servidor web significa que el código PHP ha llamado deliberadamente a un programa. O bien la aplicación lo hace a propósito, o bien alguien ha inyectado código.
Para PHP2Shell no hay indicadores de compromiso publicados y confirmados, es decir, ninguna lista de rasgos de detección fijos. La detección se basa en el comportamiento. Según los informes de que disponemos, los procesos del servidor web o de PHP-FPM que inician una shell figuran entre las señales de alerta generales más fuertes. Vale para cualquier vulnerabilidad mediante la cual los atacantes ejecutan código en el servidor. Una visión de conjunto de otros indicios la ofrece ¿Ya estoy comprometido?.
¿Por qué es tan importante la shell para un atacante? Con una vulnerabilidad, al principio solo puede lanzar comandos sueltos a través del proceso de PHP. Una shell lo convierte en un puesto de trabajo cómodo: puede curiosear, descargar herramientas, leer credenciales de archivos de configuración e instalarse de forma permanente. Quien reconoce la shell, por tanto, reconoce a menudo al atacante en el momento en que pasa del primer acceso al propósito real.
PHP-FPM inicia bash: leer el árbol de procesos
Cada proceso en Linux tiene un proceso padre. La cuestión es si una shell se ejecuta como hija de un proceso del servidor web. Los siguientes comandos solo leen:
# Árbol de procesos con usuario, PID del padre y hora de inicio
ps -eo user,pid,ppid,lstart,cmd --forest | grep -B2 -A4 -E "[p]hp-fpm|[a]pache2|[h]ttpd|[l]sphp"
# Shells que se ejecutan bajo usuarios típicos del servidor web
ps -eo user,pid,ppid,lstart,cmd | grep -E "^(www-data|apache|nginx) " | grep -E "[ /](ba|da)?sh( |$)"
# Árbol a partir del proceso PHP-FPM más antiguo
pstree -alp "$(pgrep -o php-fpm)"
Si ha encontrado una shell sospechosa, las entradas bajo /proc ofrecen más indicios, también de solo lectura:
PID=12345 # PID de la shell sospechosa
tr '\0' ' ' < /proc/$PID/cmdline; echo # línea de comandos completa
ls -l /proc/$PID/cwd /proc/$PID/exe # directorio de trabajo y archivo del programa
ls -l /proc/$PID/fd 2>/dev/null | grep socket # conexiones de red abiertas
Los nombres de proceso en Debian y Ubuntu suelen ser php8.3-fpm o similares; adapte los patrones de búsqueda. Los directorios de trabajo en /tmp, /dev/shm o en carpetas de subida son una señal clara.
Excepciones legítimas y señales de alerta reales
Algunas aplicaciones llaman a programas mediante PHP. Con ello puede surgir brevemente una shell, por ejemplo cuando PHP entrega correo mediante sendmail_path o una aplicación procesa imágenes con una herramienta externa. Estas shells viven solo segundos y llaman siempre al mismo programa. Documente una vez con limpieza estos casos esperados; entonces cualquier desviación llama la atención de inmediato, en lugar de perderse en un aluvión de avisos conocidos.
| Observación | Más bien inofensiva si | Sospechosa si |
|---|---|---|
| Shell breve bajo PHP-FPM | inicia un programa conocido de la aplicación | destino y finalidad no están claros |
| Shell de larga duración | nunca | se ejecuta durante minutos u horas |
| Herramientas de red como proceso hijo | consulta conocida de actualización o API de la aplicación | siguen descargas a directorios temporales |
| Directorio de trabajo | carpeta del proyecto de la aplicación | /tmp, /dev/shm, carpetas de subida |
| Momento | encaja con una acción conocida, p. ej. envío de correo | de noche, sin actividad de usuarios, en rachas |
Si no sabe si su aplicación llama a programas, pregunte al desarrollador o busque en el código funciones como exec, shell_exec, system, passthru, proc_open y popen. Las coincidencias en el código propio son normales; en archivos desconocidos, no.
Vigilar de forma permanente en lugar de mirar una vez
Una instantánea con ps solo atrapa las shells que se están ejecutando en ese momento. Los procesos de vida corta se escapan. Es más fiable registrar de forma permanente los inicios de programas por parte del usuario del servidor web. En Linux lo logra el servicio de auditoría auditd con una regla para los inicios de programas del usuario del servidor web. La explotación se hace en modo lectura:
# Mostrar inicios de programas registrados bajo una clave de regla (clave como ejemplo)
sudo ausearch -k web_exec --start today -i | grep -E "exe=|proctitle="
Cómo es la regla depende de la distribución y del ID de usuario; pruébela primero, porque en servidores muy cargados se generan muchas entradas.
Dos complementos hacen la vigilancia sólida. Primero, los registros deberían ir además a un sistema central, porque un atacante con derechos de root puede borrar los logs locales. Segundo, hace falta una alarma: un inicio de programa del usuario del servidor web que no figure en una lista corta de programas esperados debería desencadenar un aviso, no solo una entrada de registro. Quien ya emplee una solución de detección en equipos o servidores puede reproducir allí la misma regla. Preventivamente, con disable_functions se puede bloquear lo que la aplicación no necesita. Eso no cierra ninguna vulnerabilidad del intérprete, pero dificulta el siguiente paso de un atacante. Los detalles figuran en Usar correctamente disable_functions.
Qué hacer si encuentra una shell bajo el servidor web
- Documentar: guardar la salida de
ps, la línea de comandos, el directorio de trabajo y las conexiones abiertas en un archivo fuera del directorio web. - No limpiar: no borrar archivos ni terminar procesos antes de haber asegurado las huellas.
- Aislar: sacar el servidor de la red o restringir mucho el acceso.
- Buscar la causa: revisar registros, archivos nuevos y persistencia como tareas cron, véase Encontrar procesos sospechosos en servidores Linux.
- Cambiar los accesos: todas las contraseñas y claves que estaban en el servidor se consideran conocidas.
Si la aplicación funciona en contenedores, rige el mismo principio a pequeña escala. Una shell en el contenedor de PHP es tan sospechosa como en un servidor clásico, y las imágenes de contenedor a menudo la incluyen solo porque la trae la imagen base. Antes de reiniciar el contenedor, asegure su estado, porque con el contenedor desaparecen también las huellas del sistema de archivos volátil.
Revise además el entorno. Un atacante con una shell en un servidor web suele intentar llegar desde allí a otros sistemas, como la base de datos, el almacenamiento de copias de seguridad o interfaces de administración internas. Las credenciales en archivos de configuración de la aplicación se lo ponen fácil.
Una shell de larga duración bajo PHP-FPM en un servidor con datos de clientes es un incidente de seguridad. Trátela como tal: asegurar, aislar, tratar de forma estructurada y hacer revisar las obligaciones de notificación.
¿Cómo ayuda PHP SOS en concreto?
- Valorar el hallazgo: revisamos el árbol de procesos, las líneas de comandos y las conexiones, y separamos el comportamiento de la aplicación de las huellas de intrusión.
- Asegurar huellas: aseguramos el estado del sistema de forma verificable antes de modificar nada.
- Gestionar el incidente: con la respuesta a incidentes guiamos desde la contención hasta el cierre documentado.
- Proteger de forma permanente: configuramos el registro de inicios de programas y limitamos las funciones de PHP a lo necesario. Cómo funciona PHP-FPM por dentro lo explica PHP-FPM explicado.
Preguntas frecuentes
¿Es un ataque toda shell bajo PHP-FPM?
No todas. Algunas aplicaciones llaman deliberadamente a programas mediante PHP, por ejemplo para el tratamiento de imágenes o el envío de correo, y con ello puede surgir brevemente una shell. Resulta sospechoso si la shell se ejecuta durante más tiempo, inicia herramientas de red o trabaja desde directorios atípicos.
¿Debo terminar de inmediato el proceso sospechoso?
Primero documentar, luego actuar. Anote los datos del proceso, la línea de comandos, el directorio de trabajo y las conexiones de red. Después aísle el servidor. Terminarlo con precipitación destruye huellas y no impide que el atacante vuelva.
¿Hay para PHP2Shell indicadores de detección confirmados?
No. No hay indicadores de compromiso publicados y confirmados. Las shells bajo el servidor web son una señal de alerta general de intrusiones a través de aplicaciones web, no específica de PHP2Shell.
¿Cómo evito que PHP llegue siquiera a iniciar shells?
Con disable_functions se pueden bloquear funciones como exec, shell_exec, system y proc_open si la aplicación no las necesita. Eso no cierra ninguna vulnerabilidad del intérprete de PHP, pero dificulta su explotación.