Guía de despliegue

Sitio WordPress de un cliente hackeado: procedimiento de agencia

Desplegar en un VPS Cloud →

Tutorial

Sitio WordPress de un cliente hackeado: procedimiento de agencia

Seguridad y monitorización12 min de lectura24 pasos

El cliente llama: su sitio redirige a los visitantes, el navegador muestra una advertencia o el alojamiento ha suspendido la cuenta. Sin un procedimiento escrito, la agencia improvisa durante la hora siguiente, y ahí se pierden las pruebas, se restaura una copia ya infectada o se promete al cliente una reparación que nada garantiza. Esta guía recorre un procedimiento genérico, independiente de cualquier vulnerabilidad concreta: aislar, comprobar, decidir con criterios escritos, reabrir con accesos renovados e informar al cliente con un mensaje fechado.

Contenido· Suena el teléfono: lo que se sabe y lo que se ignora1/14
  1. 01Suena el teléfono: lo que se sabe y lo que se ignora
  2. 02Seis reglas que fijar desde la llamada
  3. 03Aislar sin destruir las pruebas
  4. 04Comprobar la integridad, comando a comando
  5. 05Una búsqueda vacía no prueba nada
  6. 06Fechar la intrusión antes de elegir
  7. 07Limpiar, restaurar o reconstruir: la tabla de decisión
  8. 08Reabrir: actualización y rotación de secretos, en orden
  9. 09Comprobar antes de abrir al público
  10. 10El mensaje al cliente, en tres tiempos y con una sola voz
  11. 11Salir de la advertencia de Google tras la reapertura
  12. 12Cuando la salida no dice lo que parece decir
  13. 13Para ir más lejos
  14. 14La documentación oficial

Suena el teléfono: lo que se sabe y lo que se ignora

El cliente describe un síntoma, rara vez una causa: el sitio redirige a los visitantes, a veces solo en móvil; el navegador muestra «Sitio engañoso»; Google señala contenido pirateado; el alojamiento ha suspendido la cuenta. La documentación oficial de WordPress recuerda que «hackeo» es un término ambiguo: registre primero los indicadores de compromiso (sitio listado por un buscador, cuenta desactivada, usuarios que nadie ha creado). Anote la hora de la llamada, la zona horaria, las palabras del cliente y los últimos cambios conocidos: un plugin nuevo, un tema cambiado, un acceso dado a un proveedor. Es la primera línea del diario de incidente.

Seis reglas que fijar desde la llamada

  • Un responsable del incidente — una sola persona decide, escribe en el diario y habla con el cliente; los demás ejecutan.
  • Una sola voz hacia el cliente — el cliente no recibe dos versiones de los hechos.
  • Un diario fechado — cada acción se anota con la hora UTC, el autor, el comando lanzado y su resultado.
  • Nada se borra antes de copiarse — un archivo borrado ya no dice por dónde entró el atacante.
  • Ninguna corrección en caliente — se aísla, se analiza y después se decide.
  • Ninguna promesa sobre la causa o la duración — «reparado» solo se dice tras los controles de reapertura.

Aislar sin destruir las pruebas

  1. Abrir el diario de incidente (5 min)

    date -u +%Y-%m-%dT%H:%M:%SZ
    Anote esta hora, el síntoma comunicado, el nombre del sitio, el alojamiento y las personas que intervienen. Cada línea siguiente indica la hora UTC, la acción y su resultado. El archivo se entregará al cliente, así que se mantiene factual.

  2. Cortar el acceso público (10 min)

    Sirva una página de mantenimiento con el código HTTP 503 desde el servidor web o la CDN, o limite el acceso a la IP del equipo. No renombre aún carpetas de plugins o temas: cambiaría las fechas de modificación que querrá leer. Si el sitio difunde malware, el corte va antes de la copia.

  3. Copiar archivos y base de datos (15 min)

    mkdir -p ~/incidents/client-a/AAAA-MM-DD
    rsync -a /var/www/client-a/ ~/incidents/client-a/AAAA-MM-DD/archivos/
    wp db export ~/incidents/client-a/AAAA-MM-DD/base.sql --skip-plugins --skip-themes
    find ~/incidents/client-a/AAAA-MM-DD -type f -exec sha256sum {} + > ~/incidents/client-a/hashes-AAAA-MM-DD.txt
    chmod -R a-w ~/incidents/client-a/AAAA-MM-DD
    Las opciones --skip-plugins --skip-themes evitan cargar plugins y tema, pero el código del sitio sigue siendo sospechoso. Las huellas y la retirada de permisos de escritura permiten demostrar después que la copia no ha cambiado.

  4. Copiar los registros (5 min)

    Recupere los registros de acceso y de errores del servidor web y los del panel de alojamiento. Su conservación es corta en muchas ofertas: es la prueba que desaparece más rápido y la que permite fechar la intrusión.

  5. Cerrar los accesos no esenciales (10 min)

    Cambie las contraseñas del panel, de SFTP y de SSH, retire los accesos de los proveedores y sustituya las claves de sal de wp-config.php para invalidar las sesiones. Esta rotación es provisional: una puerta trasera puede devolver el control al atacante, así que se repite tras la limpieza.

  6. Avisar al alojamiento (5 min)

    En un servidor compartido, la infección puede ir más allá del sitio. Informe al soporte, pida que se conserven los registros y, si la cuenta está suspendida, un acceso de lectura en lugar de la reactivación. Pregunte si la IP del servidor figura en una lista de bloqueo de correo.

Comprobar la integridad, comando a comando

  1. Archivos del núcleo (5 min)

    wp core verify-checksums --include-root
    Compara los archivos instalados con las sumas de comprobación de WordPress.org. Un mensaje «File doesn't verify against checksum» señala un archivo modificado y «File should not exist» uno añadido; --include-root extiende el control a la raíz.

  2. Plugins (5 min)

    wp plugin verify-checksums --all
    Mismo principio para los plugins del repositorio de WordPress.org. Un plugin premium o un tema a medida no tienen suma publicada: compárelos con una copia limpia del editor.

  3. PHP donde no debe haberlo (10 min)

    find wp-content/uploads -name '*.php'
    find . -type f -name '*.php' -mtime -30
    La carpeta de medios no contiene código: cualquier PHP allí es sospechoso. El segundo comando lista los PHP modificados en los últimos treinta días; sustituya 30 por la antigüedad estimada de la intrusión. Una fecha de modificación puede falsificarse: orienta, no prueba.

  4. Patrones de código sospechosos (10 min)

    grep -rEl 'eval\(|base64_decode\(|gzinflate\(' wp-content
    eval, base64_decode y gzinflate sirven para ocultar código, pero plugins legítimos también los usan: lea cada resultado. Una búsqueda sin resultados no prueba la ausencia de compromiso.

  5. Cuentas y ajustes (10 min)

    wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
    wp option get siteurl
    wp option get home
    wp option get users_can_register
    wp option get default_role
    Busque un administrador desconocido, una fecha de creación cercana a la intrusión, un siteurl o un home modificados (causa frecuente de redirecciones), un registro abierto con un rol por defecto demasiado alto. Estos datos están en las tablas wp_users, wp_usermeta y wp_options; el prefijo puede diferir.

  6. Tareas programadas y archivos de arranque (10 min)

    wp cron event list
    crontab -l
    ls -la wp-content/mu-plugins
    find . -name '.htaccess'
    Una tarea programada desconocida puede recrear el archivo malicioso cada noche. Los plugins de uso obligatorio (mu-plugins) se cargan sin activación. El .htaccess se modifica a menudo: reglas reservadas a móviles o a visitantes procedentes de un buscador explican por qué el cliente no ve nada desde su puesto. Puede haber otros en subcarpetas.

  7. Contenido de la base de datos (10 min)

    wp db search '<script' --all-tables-with-prefix
    wp option get active_plugins --format=json
    Busque etiquetas de script inyectadas en entradas, widgets y opciones, y relea la lista de plugins activos: una entrada desconocida salta a la vista.

Una búsqueda vacía no prueba nada

El código malicioso suele estar ofuscado, fragmentado o cargarse desde la base de datos. Las sumas de comprobación solo cubren el núcleo y los plugins del repositorio oficial: un tema a medida o un archivo añadido en la carpeta de contenido se les escapan. Trate estos resultados como indicios para la decisión siguiente, nunca como un certificado de limpieza.

Fechar la intrusión antes de elegir

El cliente pregunta «¿limpiamos o restauramos?», y la respuesta depende de una fecha: la de la intrusión. Restaurar elimina el síntoma visible, pero una copia que ya contiene la puerta trasera repite la infección, y restaurar sin corregir el fallo deja volver al atacante por el mismo camino. Limpiar a mano suele dejar un archivo olvidado. Para fechar la intrusión, cruce al menos dos fuentes: el archivo sospechoso más antiguo, la fecha de creación de la cuenta desconocida (user_registered), la primera petición anómala en los registros de acceso, la fecha de instalación de un plugin vulnerable. Conserve la fecha más antigua que pueda demostrar y réstele un margen. La fecha de la última copia sana se compara después con ella.

Limpiar, restaurar o reconstruir: la tabla de decisión

Desplace la tabla

SituaciónDecisiónMotivo
Última copia sana anterior a la intrusión, poco contenido escrito desde entoncesRestaurar y luego corregir el falloLa vuelta atrás es corta y verificable con los controles de integridad
Copia sana antigua, pero pedidos o contenidos escritos desde entonces (tienda, formularios)Restaurar o reconstruir y recuperar los datos recientes de la copia preservadaSe recuperan las tablas útiles, no los archivos dudosos; la selección se valida con el cliente
Fecha de intrusión desconocida, o la propia copia es sospechosaReconstruir: núcleo y plugins reinstalados limpios, contenido y medios importados tras la selecciónNingún punto de partida fiable: solo se reutiliza lo que se puede verificar
Un solo archivo modificado, causa identificada, copia limpia del núcleo disponibleLimpiar sustituyendo por archivos oficialesEl perímetro está acotado y las sumas de comprobación lo confirman
Varios archivos modificados fuera del núcleo, cuentas desconocidas, plugin de uso obligatorio desconocidoReconstruirEl número de puntos de entrada posibles supera lo que una revisión manual puede garantizar
Plugin vulnerable aún instalado, sin parche publicadoRetirarlo o sustituirlo, sea cual sea la vía elegidaSi no, el atacante vuelve por la misma puerta

Reabrir: actualización y rotación de secretos, en orden

  1. Actualizar el núcleo y los plugins

    wp core update
    wp plugin update --all
    Hágalo en un sitio limpio, tras la restauración o la limpieza. Retire también los temas y plugins sin uso.

  2. Panel de alojamiento, SFTP y SSH

    Contraseñas nuevas, largas y únicas, guardadas en una bóveda compartida. Elimine las claves desconocidas de ~/.ssh/authorized_keys. Se empieza por estos accesos: permiten reescribir los archivos, así que el resto no sirve de nada mientras estén comprometidos.

  3. Base de datos

    Contraseña nueva para el usuario de la base de datos y actualización en wp-config.php. La documentación oficial sugiere cambiar también el nombre de ese usuario.

  4. Claves de sal de wp-config.php

    Genere un juego nuevo en https://api.wordpress.org/secret-key/1.1/salt/ y sustituya los valores: las sesiones abiertas se cierran. Repítala ahora: la rotación inicial pudo haber sido eludida.

  5. Cuentas de WordPress

    Restablezca las contraseñas de todos los administradores y editores, elimine las cuentas no reconocidas, active la doble autenticación y revise los roles con el comando wp user list --role=administrator.

  6. Claves de API y servicios de terceros

    Pagos, SMTP, CDN, almacenamiento de objetos, antispam: regenere cada clave en el proveedor, no solo en el sitio.

  7. Tokens de gestión remota

    Herramientas de gestión multisitio, copia en línea, supervisión: revoque los tokens antiguos y vuelva a conectar el sitio con otros nuevos.

Comprobar antes de abrir al público

  • Sumas de comprobación limpias — wp core verify-checksums y wp plugin verify-checksums --all ya no devuelven avisos; los plugins ajenos al repositorio se comparan con una copia reciente del editor.
  • Cuentas inventariadas — la lista de administradores se revisa con el cliente, línea por línea, y cada cuenta se asocia a una persona.
  • Ningún PHP en la carpeta de medios — find wp-content/uploads -name '*.php' no devuelve nada.
  • Análisis complementario — un escáner de plugin y un escáner remoto, porque la documentación oficial recuerda que ninguna herramienta ve por sí sola todos los casos.
  • Vigilancia reforzada durante un periodo fijado — por ejemplo catorce días, con los controles de integridad repetidos a diario y la lectura de los registros de conexión; la fecha de fin se escribe en el diario de incidente.
  • Una copia sana fechada — la copia hecha justo tras la reapertura pasa a ser el nuevo punto de referencia para la próxima decisión.

El mensaje al cliente, en tres tiempos y con una sola voz

  1. La constatación, en la hora siguiente

    Escribe la agencia, no el alojamiento ni el equipo técnico. Modelo: «Su sitio presenta signos de compromiso: [síntoma observado]. Lo hemos puesto fuera de línea a las [hora UTC] para proteger a sus visitantes. La causa aún no se conoce.» Ninguna causa supuesta, ningún plazo prometido.

  2. La acción, una vez hecho el aislamiento

    Modelo: «Se ha conservado una copia completa. Estamos verificando los archivos, las cuentas y la base de datos. Antes de las [hora], le diremos si limpiamos, restauramos o reconstruimos, y por qué.» Si hay pedidos recientes en juego, dígalo: el cliente decide lo que acepta perder.

  3. El seguimiento, en la reapertura

    Modelo: «El sitio está reabierto desde el [fecha]. Los accesos se han renovado y lo vigilamos durante [duración]. Le pedimos que cambie la contraseña de sus cuentas y que nos señale cualquier comportamiento inusual.» Escriba «corregido» solo para lo que los controles han verificado de verdad.

  4. El diario de incidente, entregado al cliente

    Adjunte el diario con marcas de tiempo: constatación, acciones, decisión y motivo, reapertura, periodo de vigilancia. Se mantiene factual y no atribuye ninguna culpa.

Salir de la advertencia de Google tras la reapertura

Si el navegador mostraba «Sitio engañoso» o los resultados señalaban contenido pirateado, la salida pasa por Search Console. El informe de problemas de seguridad (Security issues) lista las páginas afectadas. La documentación de Google pide solicitar la revisión solo cuando todos los problemas estén corregidos en todas las páginas: una solicitud prematura puede alargar el plazo de la siguiente, o incluso hacer que el sitio se clasifique como reincidente. La solicitud describe el problema, las medidas tomadas y el resultado. El plazo anunciado va de unos días a varias semanas: dé ese margen al cliente en lugar de una fecha. Corrija también el fallo: si no, el sitio volverá a infectarse.

Cuando la salida no dice lo que parece decir

  • «File should not exist» en la raíz — el archivo no figura en la lista oficial, así que se añadió. No todos son hostiles (un archivo de verificación de propiedad, por ejemplo), pero cada uno debe explicarse.
  • «File doesn't verify against checksum» en readme.html o wp-config-sample.php — a menudo inofensivo si el idioma o la versión difieren. Compare --locale y --version con lo que muestra la pantalla Actualizaciones del escritorio antes de concluir.
  • Falla la descarga de las sumas de comprobación — quizá el servidor no tenga acceso saliente. No añada --insecure en una máquina sospechosa: la opción desactiva la validación del certificado y expone a una interceptación.
  • Plugin ausente del control — no está en el repositorio oficial. Compare sus archivos con una copia limpia del editor en lugar de declararlo sano.
  • El sitio sigue redirigiendo tras la limpieza — pruebe como un visitante: curl -sI -A 'Mozilla/5.0 (iPhone)' https://your-domain.com/ y después curl -sI -e https://www.google.com/ https://your-domain.com/. Una redirección visible solo así procede de una regla .htaccess, de una caché del servidor o de la CDN: liste todos los .htaccess y purgue las cachés.

Para ir más lejos

  • Un incidente fechado de un plugin de copias — /blog/updraftcentral-cles-volees-backdoors-wordpress-sauvegarde describe una restauración limpia en un caso concreto; esta guía da el procedimiento general.
  • Demostrar la restauración antes de necesitarla — /blog/tester-restauration-sauvegarde-vps-client-agence-procedure explica cómo probar una copia fuera de cualquier incidente.
  • Revisar el parque cada mes — /blog/checklist-audit-securite-mensuel-vps-clients-agence previene parte de las situaciones descritas aquí.

La documentación oficial

FAQ «My site was hacked» de WordPress: https://wordpress.org/documentation/article/faq-my-site-was-hacked/

Endurecimiento de WordPress: https://wordpress.org/documentation/article/hardening-wordpress/

Comando wp core verify-checksums: https://developer.wordpress.org/cli/commands/core/verify-checksums/

Comando wp plugin verify-checksums: https://developer.wordpress.org/cli/commands/plugin/verify-checksums/

Comando wp db search: https://developer.wordpress.org/cli/commands/db/search/

Informe de problemas de seguridad de Google Search Console: https://support.google.com/webmasters/answer/9044101

Restaurar el sitio de un cliente sin tocar los demás

En una infraestructura donde cada cuenta está aislada y las copias son diarias en todas las ofertas Agency, restaurar un sitio no afecta a los demás. Con ServOrbit.com, el cliente sigue acudiendo a usted, y restaurar una cuenta se hace sobre una infraestructura ya compartimentada.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva