Alejandro Iglesia es fotógrafo profesional de publicidad, retrato, lifestyle y beauty. Su web en WordPress es su portfolio: el sitio donde agencias y marcas ven su trabajo. Un día dejó de cargar y mostraba el mensaje «Ha habido un error crítico en esta web».
Parecía un plugin roto. Resultó ser un hackeo que llevaba dos meses activo. Esta es la historia de cómo descubrimos qué había pasado, cómo lo eliminamos y cómo volvimos a poner la web online sin perder ni una foto. Si tu web WordPress ha sido hackeada, estos pasos te ayudarán a entender qué hacer (y qué no hacer).
Las señales de alarma
El error crítico fue el síntoma visible, pero al mirar con calma aparecieron más señales que deberían hacer saltar las alarmas en cualquier WordPress:
- Plugins que se reactivaban solos. Tras desactivar todos los plugins, uno de ellos volvía a estar activo a los pocos minutos.
- Administradores que nadie conocía. La web tenía 130 usuarios con permisos de administrador. Solo uno era real.
- Archivos ocultos con nombres aleatorios dentro de
wp-content: archivos que empezaban por punto y con nombres hexadecimales, como.e7d81efd.php. - Un tamaño anormal. La carpeta de plugins pesaba más de 2 GB, cuando lo normal son unos cientos de MB.
Paso 1: no tocar nada y hacer una copia
El primer impulso es empezar a borrar. Es un error: se pierden pruebas y, si no sabes cómo se reinstala el malware, vuelve. Hicimos una copia completa de los archivos y de la base de datos y la analizamos sin ejecutar nada: leyendo el código, no poniéndolo en marcha.
Esto es importante. Ejecutar una web infectada en tu propio ordenador (por ejemplo con Local o XAMPP) tiene riesgos: una puerta trasera en PHP puede leer tus archivos o usar tu conexión. La base de datos la analizamos dentro de un contenedor aislado y sin acceso a la red.
Paso 2: qué encontramos
La infección era grave y combinaba tres familias de malware distintas, todas pensadas para vender enlaces de spam desde la web del fotógrafo:
- Un plugin de inyección de enlaces (
wp-link-helper) que insertaba enlaces de spam y se conectaba a un servidor externo para recibir instrucciones. - Un falso plugin de caché (
bold-cache-vox) con código ofuscado, copias ocultas de sí mismo y archivos de estado. - Una puerta trasera escondida dentro de la carpeta de un plugin legítimo, codificada varias veces para que no se detectara.
A eso se sumaban las piezas que lo hacían tan difícil de eliminar:
- Mu-plugins (must-use plugins): WordPress los carga siempre y no se pueden desactivar desde el escritorio. Su propio código decía para qué servían: reinstalar y reactivar el malware principal si alguien lo borraba.
- Configuración en la base de datos: unas 45 entradas en
wp_optionsy tareas programadas (cron) para recuperar el malware aunque se borraran los archivos. - 129 administradores falsos, creados a lo largo de semanas.
- Una trampa en los comentarios: un comentario con código malicioso (XSS almacenado). Si un administrador abría la pantalla de Comentarios, el código se ejecutaba con su sesión e instalaba otro plugin malicioso por su cuenta.
- Unos 1.480 comentarios de spam.
Paso 3: cómo entraron
Los registros del servidor contaron la historia. No fue un fallo de software: entraron con una contraseña válida. Era la cuenta de administrador de otra web WordPress alojada en el mismo hosting compartido.
- En los días previos al ataque hubo 16 inicios de sesión correctos desde direcciones IP distintas, de varios países, y casi ningún intento fallido. Eso no es fuerza bruta: ya tenían la contraseña. Todo apunta a que ese acceso se vendía o se compartía entre grupos de spam.
- Tras varios intentos fallidos, el atacante consiguió subir y activar un plugin malicioso. Ocho segundos después, el malware ya se estaba copiando en las demás webs del hosting.
- Todas las webs compartían el mismo usuario del sistema, así que la infección pasó a todas, incluida una instalación antigua de WordPress de 2012 que nunca se había actualizado.
La lección: una web abandonada en el mismo hosting pone en peligro a todas las demás, y basta una contraseña reutilizada o filtrada.
Paso 4: por qué no servía restaurar una copia
El hosting solo guardaba 14 días de copias de seguridad. La intrusión era de hacía dos meses, así que todas las copias estaban infectadas. Restaurar cualquiera habría devuelto el mismo malware.
Paso 5: limpiar la base de datos sin perder contenido
El valor del fotógrafo está en su contenido, y estaba intacto. Revisamos la base de datos tabla por tabla:
- Limpio: los 3.862 registros de contenido (páginas, entradas, proyectos de portfolio, galerías), sin código inyectado.
- Eliminado: los 129 administradores falsos y sus datos, las 45 entradas del malware, sus tareas programadas, el comentario con el XSS y el spam.
Después de la limpieza volvimos a buscar en toda la base de datos las firmas del malware: cero resultados.
Paso 6: rescatar las fotos una a una
Una web de fotografía puede perder cualquier cosa menos sus fotos. Comprobamos los más de 11.800 archivos (1,9 GB) de la biblioteca de medios para asegurarnos de que eran imágenes de verdad y no archivos PHP camuflados como imágenes, un truco habitual. Dejamos fuera el código malicioso, los .htaccess y php.ini peligrosos y los restos de la demo del tema. Resultado: no faltaba ni una foto.
Paso 7: reconstruir sobre un WordPress limpio
No reaprovechamos ni una línea de código del servidor infectado:
- Núcleo de WordPress descargado de wordpress.org y verificado con sus sumas de comprobación oficiales.
- Plugins gratuitos reinstalados desde wordpress.org, también verificados.
- Tema y plugins premium descargados de las fuentes oficiales del autor, en una versión más reciente. El
functions.phpdel servidor tenía unas 490 líneas de más: el malware inyectado. - El mismo diseño que antes: comparamos la web reconstruida con una copia archivada de antes del ataque.
Paso 8: migrar a un servidor nuevo y blindar la seguridad
Llevamos la web a un servidor nuevo con su propio certificado SSL y actualizamos el DNS, incluido borrar unos registros IPv6 antiguos que seguían apuntando al hosting infectado, para que todo el tráfico llegara al servidor limpio. Después endurecimos WordPress:
- Ejecución de PHP bloqueada en la carpeta de subidas.
xmlrpc.phpbloqueado, un objetivo habitual de ataques.- Editor de temas y plugins desactivado en el escritorio.
- Registro de usuarios desactivado.
- Archivos sensibles (
wp-config.php,readme.html) protegidos y contraseña de administrador nueva. - Copias de seguridad diarias programadas en el servidor nuevo.
Checklist para proteger tu WordPress
Lo que aprendimos de este caso se aplica a casi cualquier web:
- Contraseñas únicas y largas para cada web, y verificación en dos pasos para los administradores.
- Borra las webs antiguas o de pruebas que ya no uses, sobre todo si comparten hosting con la principal.
- Mantén WordPress, el tema y los plugins actualizados, y elimina los que no uses.
- Revisa los usuarios de vez en cuando: un administrador que no conoces es una señal de alarma.
- Guarda copias de seguridad de más de un mes, fuera del servidor, y comprueba que se pueden restaurar.
- Monitoriza la web: muchos hackeos se descubren semanas después, cuando las copias ya están infectadas.
¿Tu WordPress ha sido hackeado?
Si tu web muestra un error crítico, redirige a otras páginas o tiene usuarios que no reconoces, no borres a ciegas ni restaures copias sin revisarlas. En HazmeWeb recuperamos webs hackeadas: analizamos cómo entraron, limpiamos la infección sin perder tu contenido y dejamos la web protegida.
Mira el caso de Alejandro Iglesia en nuestro porfolio, consulta nuestro servicio de soporte y mantenimiento web o escríbenos y lo revisamos.