Arreglar un sitio web hackeado

head file infected

Cuando nos hackean nuestra web, debido a una falta de mantenimiento adecuado de la instalación, puede deberse a muchas causas.

La solución no siempre es igual de fácil, si nuestra web es un sitio web estático y tenemos una copia que sabemos que está limpia, lo más fácil es restaurar, pero cuidado con el tipo de restauración. Si simplemente se vuelcan los nuevos archivos sobre los anteriores, no se eliminarán archivos que puede haber creado el hackeo y seguir con el problema. También puede ser que el problema esté en un archivo fuera del WordPress y aunque restauremos, el problema continúe.

Si la web es más dinámica, como por ejemplo un WooCommerce, no podremos restaurar una copia de hace una semana y eliminar los últimos pedidos. Intentar combinar una copia con los últimos registros, en el 99 % de los casos, será un problema tras otro.

Hay muchos tipos de hackeos y diversas formas de repararlo, no hay una única manera. Si no tienes totalmente claro como hacerlo, lo mejor es que contrates un profesional que te ayude en la recuperación de instalación, pero mucho mejor será prevenir con una buena seguridad y mantenimiento adecuado, que a la larga será mucho más barato.

Dicho todo esto, aquí voy a mostrar algunas posibles herramientas que nos ayuden en la labor de restauración y búsqueda de los problemas.

WP Cli al rescate: verificar el core

WP CLI es una herramienta imprescindible en la caja de herramientas de todo administrador WordPress. Para utilizarla deberemos tener acceso SSH al servidor.

Recordad que si accedemos como root, deberemos o bien cambiar a otro usuario o añadir al final de nuestros comandos --allow-root

Lo primero que hacemos es entrar en la raíz de nuestra instalación WordPress y el primer comando será comprobar que los archivos de nuestra instalación WordPress son los correctos y que ninguno está cambiado, falta o hay alguno de más, para eso ejecutamos el siguiente comando:

wp core verify-checksums
WP Cli verify core

Si nos dice que todo está correcto continuamos a la siguiente sección. Si nos faltan archivos o alguno «está modificado» descargamos una copia limpia de los archivos mediante el siguiente comando y forzamos a que sobrescriba los antiguos, además de ignorar los temas y plugins por defecto (como Hello Dolly):

wp core download --skip-content --force

Si nuestro WordPress es una versión diferente de la última, podemos forzar a descargar dicha versión, por ejemplo la 6.1:

wp core download --version=6.1 --force

Si hay archivos añadidos deberemos eliminarlos (Consejo: descárgalo primero para mirar el código añadido y ver posibles consecuencias del hackeo). Un caso bastante frecuente en algunos servidores es el que añadan un archivo php.ini dentro de cada directorio, por lo que nos encontraremos cantidad de estos archivos «sospechosos». Si los queremos eliminar de una sola vez, primero los buscamos:

 find . -name "php.ini" -type f

Si el resultado que vemos es el que queremos eliminar, ejecutamos lo siguiente:

 find . -name "php.ini" -type f -delete

Comprobar plugins

El siguiente paso es comprobar los plugins con el siguiente comando:

wp plugin verify-checksums --all

En lugar del parámetro --all también podemos escribir el nombre del plugin y realizar la comprobación solo para ese plugin.

La mala noticia aquí, es que solo comprobará plugins del repositorio oficial, por lo que todos los demás plugins tendremos que realizar un trabajo «más manual».

Al igual que con el core, si tenemos archivos añadidos, los eliminamos. Si faltan o están modificados, descargamos una copia limpia (al igual que con el core, también podemos indicar la versión):

wp plugin install bbpress --force

Plugins de fuera del repositorio oficial

Con los plugins que no están en el repositorio oficial, la mejor técnica es borrar el directorio para asegurarnos de que no queda «ningún archivo añadido» y descargar una copia limpia desde su web oficial.

Creo que no es necesario recordar que las webs que ofrecen estos plugins de «forma gratuita» o mediante suscripciones por todos los plugins (barra libre de plugins para todos), en muchos casos son la fuente de estos hackeos, ya sea de forma premeditada o por falta de actualizaciones y las mínimas medidas de seguridad. Acabarás viendo como esos 100 euros que te ahorraste en ese plugin que necesitabas para tu tienda online, te acaba repercutiendo en gastarte unos miles de euros en pérdidas y reparaciones de tu tienda.

Temas de WordPress

Para los temas de WordPress no tenemos un comando que verifique su integridad, pero si uno para descargar una copia limpia si se trata de temas del repositorio oficial de WordPress.

Si tu tema no está en el repositorio oficial, borra el directorio y descarga una copia limpia del mismo.

Si está en el repositorio oficial, igualmente, borra el directorio y descargar la copia directamente desde WP-CLI:

wp theme install twentysixteen --force

Otros comandos útiles de WP-CLI

Desde https://developer.wordpress.org/cli/commands/ podemos ver los comandos disponibles de WP-CLI. Entre los que no pueden ser de utilidad ante un hackeo y para obtener información de la instalación, están:

# Ver todos los usuarios administradores.
wp user list --role=administrator

# Crear un usuario administrador para entrar en el panel de control de WordPress.
wp user create carlos [email protected] --role=administrator

# Borrar un usuario y reasignar sus entradas al usuario con ID 69.
wp user delete fakeuser --reassign=69

# Borrar los datos transitorios caducados.
wp transient delete --expired

# Borrar todos los datos transitorios.
wp transient delete --all

# Cambiar una cadena por otra en la Base de Datos (prueba sin ejecución).
wp search-replace 'http://tabernawp.com' 'https://nueva-tabernawp.com' --dry-run

# Cambiar una cadena por otra en la Base de Datos.
wp search-replace 'http://tabernawp.com' 'https://nueva-tabernawp.com'

# Mostrar la lista de reglas de re-escritura.
wp rewrite list

# Mostrar la lista de reglas de re-escritura en formato csv 
# para copiar y pegar en una hoja de cálculo.
wp rewrite list --format=csv

# Recargar las reglas de re-escritura.
wp rewrite flush

# Borrar la caché.
wp cache flush

# Listar todos los comentarios SPAM.
wp comment list --status=spam

# Borrar los comentarios SPAM.
wp comment delete $(wp comment list --status=spam --format=ids)

# Generar nuevos Salts.
wp config shuffle-salts

# Ejecuta la actualización de BD.
wp core update-db

# Comprobar que las tareas cron se ejecutan correctamente.
wp cron test

# Mostrar las programaciones cron disponibles.
wp cron schedule list

# Mostrar las tareas cron programadas.
wp cron event list

# Comprueba la Base de Datos.
wp db check

# Optimiza la Base de datos.
wp db optimize

# Reparar la Base de Datos.
wp db repair

# Muestra el prefijo de la Base de Datos.
wp db prefix

# Mostrar las tablas
wp db tables

# Exportar la Base de Datos con la sentencia Drop Table.
wp db export --add-drop-table

# Importa un volcado de Base de Datos desde archivo.
wp db import wordpress_dbase.sql

# Buscar una cadena en la Base de Datos, en todas las tablas, aunque no tengan el prefijo.
wp db search "Carlos Longarela" --all-tables

# Buscar una cadena en la Base de Datos, en todas las tablas con el prefijo de WordPress.
wp db search "Carlos Longarela" --all-tables-with-prefix

# Buscar en la Base de Datos utilizando expresiones regulares.
wp db search 'https?://' --regex

# Mostrar el tamaño de las tablas de la Base de Datos.
wp db size --tables --human-readable

# Mostrar el tamaño total de la Base de Datos con dos deciamles.
wp db size --human-readable --decimals=2

# Ejecutar código PHP, por ejemplo, para mostrar el directorio de contenidos.
wp eval 'echo WP_CONTENT_DIR . "\r\n";'

# O mostrar la URL del sitio web.
wp eval 'echo home_url() . "\r\n";'

# Mostrar los tamaños de imagen registrados.
wp media image-size

# Regenerar todas las miniaturas sin confirmación.
wp media regenerate --yes

# Regenerar las miniaturas del tamaño de imagen large.
wp media regenerate --image_size=large

# Regenerar las miniaturas para los tres IDs de adjunto dados.
wp media regenerate 68 69 70

# Importa todos los jpgs del directorio "Carlos", que no estén adjuntos a ningún post.
wp media import ./Carlos/**\/*.jpg

# Obtener la URL del sitio web actual.
wp option get siteurl

# Obtener el tamaño total de todas las opciones de autocarga.
wp option list --autoload=on --format=total_bytes

# Mostrar las opciones que comienzan con woo
wp option list --search="woo_*"

# Actualizar el email de administración de WordPress.
wp option update admin_email [email protected]

# Comprobar si está activado el modo mantenimiento.
wp maintenance-mode status

# Activar el modo mantenimiento.
wp maintenance-mode activate

# Desactivar el modo mantenimiento.
wp maintenance-mode deactivate

WP Cli Doctor

Pero además de los comandos de WP-CLI, también podemos instalar extensiones que realizar diversas tareas, o alguno de los plugins que hayamos instalado, pueden añadir sus propios comandos.

Un plugin que realiza varias tareas de comprobación es WP Doctor que podemos instalar con el siguiente comando:

wp package install wp-cli/doctor-command:@stable

Y después podemos ejecutar todas las tareas de comprobación con:

wp doctor check --all

O ir ejecutando individualmente cada una de las comprobaciones que podemos ver con wp doctor list.

Podemos comprobar archivos conflictivos que contengan `eval\(.*base64_decode\(.*.` con el siguiente comando:

wp doctor file-eval

Pero además de las comprobaciones por defecto, podemos crear nuestro propio archivo yaml modificando dichas comprobaciones o añadiendo otras nuevas y ejecutar alguna de las mismas o todas desde nuestro archivo.

Si tenemos el siguiente archivo YAML de configuración y lo nombramos como doctor.yml:

core-verify-checksums:
	check: Core_Verify_Checksums
autoload-options-size:
	check: Autoload_Options_Size
	options:
		threshold_kb: 1024
constant-savequeries-falsy:
	check: Constant_Definition
	options:
		constant: SAVEQUERIES
		falsy: true
constant-disallow-file-edit-true:
	check: Constant_Definition
	options:
		constant: DISALLOW_FILE_EDIT
		value: true
plugin-file-manager-uninstalled:
	check: Plugin_Status
	options:
		name: file-manager
		status: uninstalled
plugin-fileorganizer-uninstalled:
	check: Plugin_Status
	options:
		name: fileorganizer
		status: uninstalled
plugin-filebird-uninstalled:
	check: Plugin_Status
	options:
		name: filebird
		status: uninstalled

Podemos ejecutar todas las comprobaciones con:

wp doctor check --all --config=doctor.yml

Con el siguiente resultado:

WP Doctor

O ejecutar uno solo de los comandos personalizados:

wp doctor check autoload-options-size --config=doctor.yml

O podemos crear un archivo de configuración que busque en nuestra instalación una serie de patrones de posibles archivos hackeados:

file-remote-contents:
  check: File_Contents
  options:
    regex: .*(file_put_contents|file_get_contents|curl_exec).*
    only_wp_content: false
file-rot13:
  check: File_Contents
  options:
    regex: .*(str_rot13|ignore_user_abort).*
    only_wp_content: false
 file-eval:
  check: File_Contents
  options:
    regex: .*(base64|eval).*
    only_wp_content: false

Comandos en la consola

Además, tenemos multitud de comandos en la consola de Linux que nos pueden ayudar a recuperar un sitio web infectado o encontrar la causa de la misma.

Todos los comandos de Linux podrán ayudarnos en nuestra labor, por poner un par de ejemplos. Si queremos buscar todos los archivos que se han modificado entre las 3 de la mañana y las 4:15 de la mañana del día 17 de abril a partir del directorio en el que nos encontramos, deberíamos ejecutar:

find -type f -newermt "2023-04-16 03:00:00" -not -newermt "2023-04-16 04:15:00"

En el comando anterior, si solo queremos buscar dentro del directorio de contenidos, podemos o bien entrar en el mismo y ejecutar el mismo comando o modificarlo a:

find wp-content/ -type f -newermt "2023-04-16 03:00:00" -not -newermt "2023-04-16 04:15:00"

Comprobar que no hay archivos ejecutables de PHP en el directorio uploads de nuestra instalación:

find wp-content/uploads -type f -name "*.php"

Podemos buscar un texto dentro de los archivos, por ejemplo, si sabemos que el hackeo inserta en los archivos la cadena $goweb = str_rot13(urldecode($xmlname)); podremos buscarla en todos los archivos con el siguiente comando:

grep -rni "$goweb = str_rot13(urldecode($xmlname));"

Mostraremos los archivos del directorio actual, incluyendo los ocultos con su fecha, permisos, dueño:

ls -la --color=auto

Mostrar el contenido de determinado archivo (o modificarlo con nano o vim):

cat wp-includes/css/wp-in-auth-check.css

O eliminar un archivo porque resulta que no debería existir al ser un archivo hackeado:

rm wp-includes/css/wp-in-auth-check.css

Mostrar el tamaño del directorio actual:

du -h --max-depth=1 | sort -h

Y multitud de comandos más de la consola de Linux que nos ayudarán en la búsqueda y reparación de nuestra instalación WordPress.

Pero recordad que lo principal es evitar la infección. Lo más importante es mantener la instalación actualizada, para lo que un buen plan de mantenimiento será algo imprescindible, bien lo hagamos nosotros mismos o lo encarguemos a un profesional. Además, deberemos tener muy en cuenta la seguridad de WordPress.

Pero, sobre todo, ante un problema de hackeo, mantener la calma y realizar los pasos adecuados para no borrar los rastros de la infección y tener mucho cuidado de los pasos a dar. Si no entendéis perfectamente los comandos y utilidades mostrados anteriormente, NO HAGÁIS NADA y contactad lo antes posible a un profesional o podréis empeorar más la situación.

Deja un comentario