Cuando un sitio WordPress es comprometido, muchas veces no basta con eliminar archivos sospechosos: los scripts maliciosos suelen regenerarse automáticamente gracias a puertas traseras ocultas en el servidor. En este artículo documentamos un proceso técnico completo de limpieza y refuerzo, dividido en dos fases: forense en servidor (SSH) y endurecimiento en WordPress y WAF.
1. Detección inicial
- Aparición de redirecciones a sitios externos.
- Archivos como
.htaccess
regenerándose solos con reglas sospechosas. - Carpetas ocultas con nombres aleatorios (
/e0a8cc
,/fecf2
, etc.). - Procesos PHP inusuales ejecutándose de manera persistente.
- Resultados alterados en buscadores (Google mostrando títulos en otros idiomas).
Para confirmar, se buscaron patrones comunes de malware:
grep -R --line-number --color "base64_decode\|gzinflate\|shell_exec\|system\|eval" public_html
2. Limpieza en servidor (SSH con PuTTY)
2.1. Identificación y eliminación de procesos maliciosos
ps -u "$(whoami)" -o pid,etime,cmd | grep -E 'php|bash|sh|wget|curl'
ps -u "$(whoami)" -o pid | xargs -r kill -9
2.2. Desbloqueo y borrado de carpetas que se regeneran
for dir in .tmb contactos e0a8cc fecf2 images permisos tawk; do
chattr -i public_html/$dir 2>/dev/null || true
chmod -R 777 public_html/$dir 2>/dev/null || true
rm -rf public_html/$dir 2>/dev/null || true
done
2.3. Neutralización de .user.ini
y .htaccess
find public_html -type f -name '.user.ini' -exec sh -c '
chattr -i "$1" 2>/dev/null || true
echo "[neutralizado]" > "$1"
chmod 644 "$1"
' sh {} \;
Se regeneró un .htaccess
limpio:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
2.4. Reinstalación del core de WordPress
wget https://wordpress.org/latest.zip
unzip -q latest.zip
mv public_html/wp-admin ~/quarantine/wp-admin_$(date +%F_%H%M)
mv public_html/wp-includes ~/quarantine/wp-includes_$(date +%F_%H%M)
cp -a wordpress/wp-admin wordpress/wp-includes public_html/
3. Refuerzo en WordPress (wp-admin)
3.1. Plugins de seguridad
Se instaló y configuró All In One WP Security (AIOS):
- Bloqueo de
wp-login.php
con slug personalizado. - Deshabilitar editor de archivos desde
wp-config.php
:
define('DISALLOW_FILE_EDIT', true);
- Lista negra de IPs sospechosas.
- Protección contra fuerza bruta (renombrar login + honeypot).
3.2. Permisos correctos de archivos
find public_html -type d -exec chmod 755 {} \;
find public_html -type f -exec chmod 644 {} \;
chmod 600 public_html/wp-config.php
3.3. Borrado de spam en base de datos
DELETE FROM wp_comments WHERE comment_approved = 'spam';
DELETE FROM wp_comments WHERE comment_content LIKE '%http%';
4. Refuerzo en Cloudflare
Aunque el plan gratuito no incluye WAF completo, se aplicaron medidas:
- Reglas personalizadas de firewall para bloquear países con actividad sospechosa.
- Bot Fight Mode activado para detener scrapers.
- Rate Limiting configurado para proteger
wp-login.php
yxmlrpc.php
.
Ejemplo de regla:
(http.request.uri.path contains "/wp-login.php")
Acción: Block o Challenge.
5. Lecciones aprendidas
- Nunca dejar credenciales débiles: contraseñas simples fueron la causa inicial.
- Los atacantes suelen instalar plugins falsos para mantener persistencia.
- La limpieza debe ser en capas: servidor, core de WordPress, base de datos, plugins y capa de red (Cloudflare).
- Monitorear constantemente con:
find public_html -mmin -5 -ls
Conclusión
Un ataque a WordPress no se soluciona borrando archivos manualmente: requiere un proceso forense completo, reinstalación de componentes limpios, bloqueo de persistencia y endurecimiento en varios niveles.
Con esta metodología, cualquier administrador puede detectar, limpiar y reforzar un sitio comprometido.