Fenrir SOCFenrir MDRGARM · gratisFenrir WP BridgeFenrir WP Central Cómo funciona Precios Compliance Blog
← Blog

2026-07-01 · Team Fenrir

Cómo reconocer una web shell en un sitio WordPress

Una web shell es la respuesta más corta a la pregunta “¿cómo volvió a entrar?”. No es el ataque inicial: es lo que el atacante deja después, para volver a voluntad. En WordPress casi siempre toma la forma de un archivo PHP escondido entre los tuyos. Reconocerla exige tres cosas: saber dónde mirar, con qué comandos, y qué buscar en los logs. Esta guía cubre las tres.

¿Qué es exactamente una web shell?

Es un script subido al servidor que expone una interfaz de comandos vía HTTP: el atacante abre una URL (o envía un POST) y el servidor ejecuta lo que se le pide — leer archivos, escribir más código, lanzar procesos. OWASP la sitúa entre las consecuencias directas de la subida de archivos sin filtrar: si una aplicación permite subir un archivo y ese archivo puede ejecutarse en el servidor, el resultado es ejecución de código arbitrario. MITRE ATT&CK la cataloga como T1505.003 (Server Software Component: Web Shell), una técnica de persistencia: su objetivo es sobrevivir al descubrimiento del ataque inicial.

La diferencia práctica respecto a otro malware: la web shell no “hace” nada por sí sola. Se queda quieta, invisible, hasta que el atacante la invoca. Por eso los síntomas clásicos (sitio lento, redirecciones extrañas, spam) a menudo faltan por completo.

¿Dónde se esconde en WordPress?

Las web shells acaban donde el código no debería estar, o donde nadie mira:

  • wp-content/uploads/ — el directorio de medios. Debería contener imágenes y documentos, nunca PHP. Es el escondite más común porque siempre es escribible por el servidor web.
  • Dentro de un plugin o tema legítimo — un archivo añadido (helper.php, class-cache.php) o unas pocas líneas inyectadas al final de un archivo real. El plugin sigue funcionando con normalidad, así que nadie se da cuenta.
  • wp-content/mu-plugins/ — los “must-use plugins” se cargan automáticamente y no aparecen en la lista de plugins activables. Poca gente sabe que este directorio existe: perfecto para una puerta trasera.
  • Nombres que imitan el corewp-conf.php, wp-sett.php, wp-cache.php en la raíz o en wp-includes/. A simple vista parecen archivos de WordPress; no lo son.

¿Qué señales la delatan?

Cuatro indicadores concretos, por orden de fiabilidad:

  1. Archivos PHP donde no debería haber ninguno. Un .php en uploads/ es sospechoso por definición.
  2. Código ofuscado. eval(, base64_decode(, gzinflate(, str_rot13( encadenados son la firma clásica: el payload va codificado para eludir los escáneres y se decodifica y ejecuta al vuelo.
  3. Archivos del core o de plugins que no coinciden con los checksums oficiales. Es el control más fiable: no mira cómo está escrito el código, sino si es el que distribuyó WordPress.org.
  4. Timestamps incoherentes. Un archivo “core” modificado después de la última actualización es una anomalía. Ojo: los atacantes saben falsificar fechas (touch), así que un timestamp limpio no prueba inocencia — uno sucio es solo un indicio más.

¿Cómo la busco desde la línea de comandos?

Cuatro comandos, del más simple al más fiable:

# 1. PHP en el directorio de medios: no debería haber nada
find wp-content/uploads -name '*.php'

# 2. Patrones de ofuscación en los archivos del sitio
grep -rEl "eval\(|base64_decode\(|gzinflate\(" wp-content/

# 3. Integridad del core contra los checksums oficiales de WordPress.org
wp core verify-checksums

# 4. Integridad de los plugins (solo los del repositorio oficial)
wp plugin verify-checksums --all

El comando 3 es el más valioso: wp core verify-checksums compara cada archivo del core con los checksums publicados por WordPress.org y señala tanto los archivos modificados como los inesperados que no deberían existir. El comando 2 produce falsos positivos (algunos plugins legítimos usan base64_decode): trata su salida como una lista de candidatos a examinar, no como un veredicto.

¿Qué busco en los logs del servidor web?

La web shell se usa vía HTTP, así que deja rastros en los logs de acceso. MITRE señala precisamente la monitorización de logs y archivos entre los métodos de detección de esta técnica. Los patrones típicos:

  • POST repetidos hacia un único archivo PHP que no es un endpoint conocido (admin-ajax.php y wp-cron.php reciben POST legítimos; wp-content/uploads/2026/01/img.php no).
  • Peticiones con parámetros largos e ilegibles — a menudo el comando a ejecutar, codificado en base64.
  • Una sola IP que llama siempre al mismo archivo, a horas anómalas, sin referrer y sin tocar nunca el resto del sitio: un visitante real navega, una puerta trasera no.
  • Respuestas 200 en URLs que no reconoces. Si un archivo PHP que nunca instalaste responde 200, el problema está confirmado.

Un grep útil como punto de partida:

grep 'POST' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20

Si en lo alto de la lista hay un archivo que no reconoces, has encontrado el hilo del que tirar.

¿Cómo la elimino sin destruir las pruebas?

El instinto dice “bórrala ya”. Resiste: la web shell es el punto de reentrada, no la causa. Si la eliminas sin entender por dónde entró el atacante, la volverás a encontrar mañana.

En orden:

  1. Conserva las pruebas — copia el archivo sospechoso y las líneas de log que lo mencionan fuera del servidor (las necesitas para reconstruir el punto de entrada, y ante posibles obligaciones de notificación).
  2. Reconstruye la entrada — la primera petición hacia ese archivo en los logs, y qué pasó justo antes: ¿una subida? ¿un login? ¿el exploit de un plugin?
  3. Cierra el agujero — actualiza o elimina el componente vulnerable, rota todas las credenciales (admin de WordPress, base de datos, FTP/SSH), invalida las sesiones.
  4. Solo ahora elimina — borra la web shell y restaura los archivos modificados desde fuentes limpias (los checksums del paso anterior te dicen exactamente cuáles).
  5. Re-verifica — un wp core verify-checksums limpio, logs bajo vigilancia los días siguientes: si el atacante tenía una segunda puerta trasera, la usará.

¿Cómo evito que vuelva?

La guía oficial de hardening de WordPress converge en pocos puntos de alto rendimiento:

  • Bloquea la ejecución de PHP en uploads/ — la contramedida individual más eficaz: aunque se suba un PHP, el servidor web se niega a ejecutarlo. En nginx: location ~* /uploads/.*\.php$ { return 403; }.
  • Actualiza core, plugins y temas — la mayoría de los compromisos de WordPress entran por componentes vulnerables conocidos y ya corregidos.
  • Menos componentes, menos superficie — cada plugin desactivado-pero-instalado es código atacable que no necesitas: elimínalo.
  • Permisos mínimos — los archivos no deben ser escribibles por el servidor web donde no haga falta; nada de 777.
  • Verificación de integridad recurrentewp core verify-checksums en cron es un detector de web shells casi gratuito.

¿Por qué importa la monitorización continua?

Todo lo anterior tiene un límite estructural: es manual y puntual. Una web shell encontrada con el grep del sábado por la mañana es una web shell que llevaba una semana de ventaja. La clave no es el comando aislado, sino tener algo que observa archivos y logs de forma continua y te avisa cuando aparece un PHP donde no debería, cuando un archivo del core cambia de checksum, cuando una IP empieza a martillear un endpoint que no existe.

Es exactamente lo que hace Fenrir SOC en los servidores y Fenrir para WordPress en los sitios: integridad de archivos, correlación de logs y una respuesta que se dispara antes de que abras el terminal. Tú duermes, el sitio se defiende solo — y la web shell la lees en el informe de la mañana, ya bloqueada.

Preguntas frecuentes

¿Qué es una web shell?

Un script (en WordPress casi siempre PHP) subido por el atacante para ejecutar comandos en el servidor de forma remota, normalmente vía peticiones HTTP. Es una puerta trasera persistente: MITRE ATT&CK la cataloga como técnica de persistencia T1505.003.

¿Basta un antivirus para encontrarla?

No siempre: las web shells ofuscadas eluden las firmas. Hacen falta también controles de comportamiento sobre los archivos (integridad contra los checksums oficiales, timestamps) y el análisis de los logs de acceso del servidor web.

¿Cómo verifico si un archivo del core de WordPress fue modificado?

Con WP-CLI: `wp core verify-checksums` compara cada archivo del core con los checksums oficiales de WordPress.org y lista los archivos modificados o inesperados. Para los plugins del repositorio oficial existe `wp plugin verify-checksums`.

¿Basta con borrar el archivo de la web shell?

No. La web shell es el punto de reentrada, no la causa: si no encuentras y cierras la vía de entrada (plugin vulnerable, credenciales robadas, subida sin filtrar), el atacante la recreará. Antes de borrar, conserva el archivo y los logs como prueba.

Fuentes