Ver todas las comprobaciones
Guía

¿El malware de WordPress vuelve una y otra vez? Aquí es donde se esconde

Borraste los archivos infectados, pasaste un escaneo de seguridad y salió limpio. A la mañana siguiente, el falso recuadro de «verifica que eres humano», la redirección de spam o el script inyectado han vuelto. Si el malware de WordPress vuelve, no es mala suerte: el malware moderno de WordPress está hecho para sobrevivir a una limpieza. Lo que eliminaste era la parte visible; la parte que lo vuelve a poner está en otro sitio. Esta guía recorre los ocho lugares donde se esconde, por qué un escáner que funciona dentro del sitio no los ve, en qué orden limpiarlos y cómo saber en menos de una hora si vuelve.

Por qué el malware de WordPress vuelve una y otra vez

Una reinfección casi nunca significa que el atacante haya vuelto a entrar. Significa que a la limpieza se le escapó una capa. El malware autorregenerable se reparte en piezas: un pequeño cargador que se ejecuta en cada petición, una copia de la carga útil guardada donde los escaneos de archivos no miran, y una vía para volver a entrar: una cuenta, una clave o una tarea programada. Borra los archivos que ves y el cargador los vuelve a escribir desde la copia guardada, a menudo en cuestión de minutos. Borra el cargador pero no la cuenta, y el atacante lo vuelve a instalar a mano.

Lo que ves —un CAPTCHA falso, una redirección a una web de farmacia, un skimmer en el checkout— es la carga útil. Es la parte menos importante de eliminar, y la única a la que apuntan la mayoría de las limpiezas. La infección es la combinación del cargador, la copia guardada y la vía para volver a entrar.

1. Un plugin must-use que se carga en cada petición

WordPress ejecuta todos los archivos PHP de wp-content/mu-plugins antes que los plugins normales, en cada petición, y los plugins must-use no se pueden desactivar desde wp-admin. Eso convierte esa carpeta en el sitio favorito para un cargador. Uno típico son unas pocas líneas con un nombre inofensivo (wp-cache-helper.php) que lee una cadena codificada de la base de datos y la evalúa. En el propio archivo no hay código malicioso que un escáner de firmas pueda reconocer.

Revisa cada archivo de mu-plugins y pregúntate de dónde ha salido. Los hostings y algunos plugins ponen archivos ahí de forma legítima; cualquiera que llame a eval, base64_decode o gzinflate sobre datos que vuelve a leer no es uno de ellos.

2. Una copia de la carga útil en la base de datos

El cargador necesita algo que cargar. Se guarda en wp_options, a menudo como un transient o una opción con nombre de sistema, en forma de una larga cadena base64 o de código PHP. Como es una fila de la base de datos y no un archivo, los escaneos y las restauraciones de archivos nunca la tocan; así que, cuando restauras los archivos desde una copia de seguridad, el cargador (si sobrevivió) o una tarea programada simplemente vuelve a escribir el malware.

Merece la pena revisar las opciones que contienen código PHP o un único bloque codificado grande. Algunos plugins legítimos guardan código o firmas ahí (los plugins de seguridad guardan sus firmas de malware en opciones), así que compruébalo antes de borrar; pero un nombre aleatorio que guarda 40 KB de base64 no es un ajuste.

3. wp-config.php, .htaccess y .user.ini

Estos tres archivos se ejecutan antes que WordPress y están fuera de wp-content, una zona que muchos escaneos se saltan. Una línea auto_prepend_file en .htaccess o .user.ini hace que PHP ejecute un archivo —a menudo uno disfrazado de imagen en uploads— antes de cada petición, sin excepción. Una línea AddHandler puede hacer que los archivos .png o .ico se ejecuten como PHP. Un par de líneas RewriteCond pueden enviar a una web de spam solo a los visitantes que llegan desde Google, de modo que el sitio parece normal cuando escribes tú mismo la dirección. Y wp-config.php puede incluir un archivo de uploads, o decodificar una cadena, en cada carga.

Wordfence y NinjaFirewall usan auto_prepend_file de forma legítima para sus cortafuegos; cualquier otra cosa que anteponga un archivo tiene que tener una explicación.

4. Un archivo escondido entre los de WordPress

Un archivo PHP colocado en wp-includes/images o wp-admin/includes parece estar en su sitio entre miles de archivos del núcleo. Reinstalar WordPress no lo elimina: como señalan las propias preguntas frecuentes de WordPress.org sobre sitios hackeados, los instaladores sobrescriben los archivos que incluyen, y los hackeos suelen añadir archivos nuevos. WordPress publica una suma de comprobación para cada archivo que distribuye, así que una comprobación de checksums del núcleo detecta un archivo del núcleo modificado; uno añadido no está en ninguna lista de checksums, así que hay que buscarlo aparte.

En wp-admin y wp-includes solo debe haber WordPress. Cualquier archivo PHP ahí que WordPress no distribuya es una puerta trasera mientras no se demuestre lo contrario.

5. La carpeta de plugins: añadidos, ocultos o desactivados

Aquí pasan tres cosas. El atacante copia un plugin como archivos en lugar de instalarlo, así que ninguna instalación aparece en ningún registro. Lo oculta de la pantalla Plugins con el filtro all_plugins, así que nunca sale en la lista que revisas. Y renombra la carpeta de tu plugin de seguridad —wordfence pasa a ser wordfence.disabled_1712—, lo que hace que WordPress lo desactive sin decir nada. No hay desactivación, así que no salta ningún aviso de desactivación, y para WordPress el plugin de seguridad simplemente deja de existir.

Si el panel de tu plugin de seguridad se quedó en silencio justo cuando empezaron los problemas, comprueba el nombre de su carpeta en el disco.

6. Cuentas y contraseñas de aplicación

La vía de vuelta más duradera ni siquiera es código. Un administrador nuevo, o una cuenta de cliente existente a la que se le ha dado en silencio el rol de administrador, sobrevive a cualquier limpieza de archivos. Y lo mismo pasa con una contraseña de aplicación: desde WordPress 5.6, un administrador puede tener contraseñas de aplicación que inician sesión directamente en la API REST, sin pasar por el formulario de acceso, así que la verificación en dos pasos, los límites de intentos de acceso y un cambio de contraseña nunca les afectan.

Revisa cada administrador (Usuarios → filtra por Administrador) y, en el perfil de cada uno, la sección Contraseñas de aplicación. Revoca todo lo que no hayas creado tú.

7. Tareas programadas y rutas REST

WP-Cron permite ejecutar código con un temporizador. Un cargador que registra una tarea programada puede volver a descargar o a escribir el malware cada hora, mucho después de que hayas borrado los archivos que escribió. Una ruta REST hace lo mismo bajo demanda: un endpoint público al que el atacante llama para subir una copia nueva. Ambas parecen un hook más; lo que las delata es dónde vive su código: evaluado desde una cadena, creado en tiempo de ejecución o metido en la carpeta uploads, en lugar de en un plugin que tú instalaste.

Plugins como WP Crontrol listan las tareas programadas; la pregunta para cada una que no reconozcas es qué archivo la define.

8. Los navegadores de tus visitantes

Hay dos cosas que viven en el lado del visitante. Un service worker es un script que el navegador instala para un sitio y mantiene en marcha entre visitas; ve todas las peticiones que hace el sitio y puede responderlas él mismo. Uno registrado por código inyectado se queda en los navegadores de tus visitantes después de limpiar el sitio: el único lugar al que una limpieza del servidor no llega. Y ClickFix, el falso recuadro de «verifica que eres humano» que pide a los visitantes pulsar Win+R y pegar un comando, instala malware en los ordenadores de tus visitantes, no en tu servidor; así que el daño continúa hasta que desaparece la propia inyección.

Las inyecciones de este tipo suelen saltarse a los administradores con sesión iniciada, así que el sitio puede parecerte perfectamente normal. Compruébalo en una ventana privada, sin iniciar sesión.

Por qué un escáner dentro del sitio no lo ve

Un plugin de seguridad se ejecuta dentro del sitio que protege, así que el malware que controla el sitio puede controlar lo que ve el plugin: renombra su carpeta y queda apagado, oculta un plugin de la lista y deja de estar, guarda la carga útil en la base de datos y no hay archivo que comparar. Además, el escaneo por firmas busca código malicioso conocido, y un cargador que evalúa una cadena de la base de datos no contiene ninguno.

Por eso Relvato está construido al revés. El plugin de Relvato solo informa de lo que hay en el sitio —huellas, nombres y ubicaciones, nunca contenidos—, y la línea base que aprobaste y el veredicto viven en los servidores de Relvato, donde el malware de tu sitio no puede editarlos. Las comprobaciones que más importan para este tipo de infección miran tu sitio como lo hace un visitante, desde fuera. Y si el propio plugin deja de responder —desactivado, borrado o bloqueado—, Relvato lo detecta en un máximo de cinco minutos y marca el sitio como crítico en tus notificaciones y en el resumen por correo.

Límpialo en este orden, o se vuelve a escribir solo

El orden importa porque cada capa restaura a las demás. Pon el sitio en modo mantenimiento y haz primero una copia de seguridad, aunque esté infectada: te hará falta para averiguar cómo entraron.

Después: elimina el cargador (mu-plugins, cualquier cosa que evalúe código fuera de un plugin), luego la carga útil guardada (las opciones y transients que lee), luego los archivos (reinstala el núcleo de WordPress desde una descarga nueva, borra los archivos PHP que el núcleo no incluye, reinstala plugins y temas desde su origen) y luego las vías para volver a entrar (administradores desconocidos, contraseñas de aplicación, tareas programadas). Devuelve su nombre a la carpeta de tu plugin de seguridad y vuelve a ejecutar su escaneo. Luego cambia todas las contraseñas —WordPress, hosting, SFTP, base de datos— y genera nuevas claves de seguridad en wp-config.php para cerrar todas las sesiones existentes. WordPress.org aconseja volver a cambiar las contraseñas una vez que estés seguro de que el sitio está limpio, y ese es el momento adecuado.

Por último, limpia lo que conservan los visitantes: elimina cualquier service worker que el sitio no necesitara y el código que lo registró.

Vigila las próximas 48 horas

Si se escapó una capa, lo sabrás pronto: el malware autorregenerable suele volver en horas, no en semanas. Una comprobación diaria puede tardar un día en verlo, así que tras una limpieza merece la pena revisar los mismos sitios cada hora durante los dos días siguientes.

Relvato lo hace por su cuenta. Cuando la integridad de archivos, la integridad del tema o la lista de administradores han encontrado algo y la siguiente ejecución sale limpia, se inicia una vigilancia de reinfección: esas comprobaciones se ejecutan cada hora durante 48 horas, y una limpieza durante la vigilancia la prolonga. También puedes iniciar una tú mismo desde la página «Security» del sitio. Las comprobaciones cada hora forman parte de los planes con ejecuciones programadas.

Dónde se esconde el malware autorregenerable y qué lo detecta

Dónde se escondeCómo trae de vuelta la infecciónQué comprueba Relvato
mu-pluginsUn cargador se ejecuta en cada petición y no se puede desactivar desde wp-adminUn archivo nuevo en mu-plugins; patrones de malware en él; el código que evalúa
La base de datosUna copia codificada vuelve a escribir los archivos borradosOpciones que contienen código PHP o un único bloque codificado grande
wp-config.php, .htaccess, .user.iniUn archivo que se ejecuta antes de cada petición; imágenes ejecutadas como PHP; visitantes de buscadores redirigidosUna huella de cada archivo y los nombres de los patrones de malware que contienen
wp-admin y wp-includesUna puerta trasera junto a los archivos del núcleo sobrevive a una reinstalación del núcleoArchivos PHP que WordPress no distribuye
La carpeta de pluginsUn plugin copiado como archivos y oculto; la carpeta del plugin de seguridad renombradaPlugins no instalados a través de WordPress, plugins ocultos, plugins de seguridad renombrados
CuentasUn admin de más o elevado; una contraseña de aplicación que se salta el acceso y la 2FAAdmins nuevos y elevados, y las contraseñas de aplicación de cada admin
Tareas programadas y rutas RESTVuelven a escribir el malware con un temporizador o bajo demandaCódigo que se ejecuta desde donde no lo puso ningún plugin, tema ni WordPress
Navegadores de los visitantesUn service worker que sobrevive a la limpieza; un CAPTCHA falso (ClickFix)Service workers que instalan las páginas; avisos de verificación falsos

Preguntas, respondidas

¿Por qué mi WordPress vuelve a estar hackeado después de limpiarlo?

Normalmente no te han vuelto a hackear: a la limpieza se le escapó una capa. El malware autorregenerable mantiene un cargador (a menudo en mu-plugins), una copia de sí mismo en la base de datos y una vía para volver a entrar (una cuenta de administrador, una contraseña de aplicación o una tarea programada). Si eliminas solo los archivos visibles, alguna de las otras piezas los vuelve a poner, a menudo en cuestión de horas.

¿Reinstalar WordPress elimina el malware?

No todo. Una reinstalación sobrescribe los archivos que distribuye WordPress, pero un archivo PHP añadido a wp-includes o wp-admin se queda, y no se toca nada de wp-content, wp-config.php, .htaccess ni la base de datos. Reinstala el núcleo, luego busca archivos que WordPress no distribuye y limpia las demás capas.

¿Qué es la ventana falsa de «verifica que eres humano» que aparece en mi web?

Es ClickFix: un código inyectado muestra un CAPTCHA falso que pide a los visitantes pulsar Win+R (o abrir Terminal), pegar y pulsar Intro. Un script ya les ha puesto un comando en el portapapeles, así que instalan malware en su propio ordenador. Es una infección de tu sitio, no un cortafuegos, y a menudo se oculta a los administradores con sesión iniciada: comprueba el sitio sin iniciar sesión.

¿Puede detectarlo mi plugin de seguridad?

En parte. Un plugin de seguridad se ejecuta dentro del sitio, así que el malware que controla el sitio puede renombrar la carpeta del plugin (lo que lo apaga sin que haya desactivación), ocultarse de la pantalla Plugins y guardar su carga útil en la base de datos, donde los escaneos de archivos no miran. Mantén el plugin de seguridad y añade una comprobación cuyo registro y veredicto vivan fuera del sitio.

¿Tengo que cambiar las contraseñas y las claves de seguridad?

Sí, y después de que el sitio esté limpio, no solo cuando descubres el hackeo. Cambia las contraseñas de WordPress, del hosting, de SFTP y de la base de datos, revoca las contraseñas de aplicación que no hayas creado y genera nuevas claves de seguridad en wp-config.php para cerrar todas las sesiones existentes.

¿Cuánto tiempo debo vigilar el sitio después de una limpieza?

Al menos 48 horas, y con más frecuencia que una vez al día: el malware autorregenerable suele volver en cuestión de horas. La vigilancia de reinfección de Relvato vuelve a ejecutar las comprobaciones de integridad cada hora durante 48 horas tras una limpieza, en los planes con ejecuciones programadas.

Fuentes

Lecturas relacionadas
Guía

Entérate en menos de una hora si vuelve.

Relvato vigila los lugares donde se esconde el malware autorregenerable —desde fuera del sitio, donde no puede editar el registro— y vuelve a comprobarlos cada hora tras una limpieza.