"Analizar, detectar y limpiar malware PHP en sitios WordPress alojados en servidores Linux (CWP/cPanel). Cubre el ciclo completo: triage, backup, escaneo heurístico, clasificación de hallazgos, limpieza quirúrgica de código inyectado, eliminación de archivos 100% maliciosos, restauración de WordPress core, validación post-limpieza y hardening. WHEN: malware en WordPress, limpiar sitio hackeado, código ofuscado PHP, webshell, backdoor, hacklink, archivos sospechosos en uploads, eval base64_decode, archivo PHP inyectado, limpiar servidor comprometido, cuarentena malware, restaurar WordPress core."
Resources
19Install
npx skillscat add maitret/wordpress-malwarescanner Install via the SkillsCat registry.
WordPress Malware Remediation
GUÍA OPERATIVA — Ciclo completo de detección y limpieza de malware PHP en WordPress sobre servidores Linux (CWP/cPanel).
Triggers
Activar este skill cuando el usuario necesite:
- Analizar un servidor o sitio WordPress comprometido con malware
- Limpiar archivos PHP con código inyectado (hacklinks, webshells, backdoors)
- Eliminar archivos completamente maliciosos (droppers, loaders, shells)
- Clasificar hallazgos del scanner (MALWARE / LIKELY_MALWARE / SUSPICIOUS)
- Crear o actualizar firmas/reglas de detección
- Restaurar WordPress core desde copia limpia
- Validar que la limpieza fue efectiva
- Investigar código PHP ofuscado (base64, hex, goto spaghetti, char-index)
Reglas Fundamentales
- NUNCA limpiar sin backup previo — Respaldar BD y archivos antes de cualquier acción destructiva.
- Escaneo inicial siempre en modo solo-reporte — Usar
--no-quarantineen la primera pasada. - Revisar falsos positivos — Plugins legítimos (Wordfence, Guzzle, wp-migrate-db) pueden disparar firmas.
- Dos tipos de limpieza — Distinguir entre archivos que se limpian (extraer líneas maliciosas) vs. archivos que se eliminan completos.
- Documentar cada IOC confirmado — Agregar a
signatures/local_iocs.jsonpara futuras detecciones. - Re-escanear después de limpiar — Validar que no queden remanentes.
Herramientas del Toolkit
Cada fase del flujo operativo se apoya en herramientas específicas ya implementadas. La columna Estado indica el nivel de madurez.
| Herramienta | Función principal | Estado |
|---|---|---|
malware_scanner.py |
Motor heurístico: 6 capas de firmas, scoring, entropía, análisis ZIP, reportes (JSON/texto/rm scripts), cuarentena, --clean, --disable, --validate-wp |
✅ Producción |
wp_backup_db.sh |
Autodescubre wp-config.php, extrae credenciales DB, dump MySQL + gzip. Lock anti-ejecución simultánea. |
✅ Producción |
wp_reemplaza.sh |
Restaura wp-admin/wp-includes vía rsync desde copia limpia. Backup previo de BD + core (tar.gz). Detecta versión WP y Multisite. Restaura permisos y ownership. | ✅ Producción |
fix_permissions.sh |
Corrección recursiva: dirs 755, archivos 644, wp-config.php 600, home 711, public_html 750. Modo --dry-run, --verbose, por usuario o --all. Compatible CWP/cPanel. |
✅ Producción |
malware_scan.sh |
Triage rápido por grep/find: firmas básicas, PHP en uploads, archivos recientes, nombres sospechosos, permisos 777. | ✅ Triage |
wp_security_scan.sh |
Cuarentena básica: mueve archivos sospechosos a quarantine/, valida WP core con diff, detecta archivos recientes. | ✅ Triage |
signatures/*.json |
Firmas externas: internal_knowledge (6), community (6), local_iocs (9), yara_fallback (5). | ✅ Extensible |
signatures/yara/*.yar |
Reglas YARA curadas (5 reglas). Requiere yara-python o yara-x opcional. | ✅ Opcional |
malware_refs/ |
Muestras de referencia de malware conocido para pruebas. | ✅ Referencia |
Flujo Operativo Completo
Fase 1 — Preparación y Backup
Herramienta: wp_backup_db.sh | Estado: ✅ Implementado
# 1. Crear estructura de directorios
mkdir -p /home_D0/fixes/{logs,quarantine,backups,wordpress}
# 2. Respaldar todas las bases de datos WordPress
./wp_backup_db.sh /home
# Solo un sitio:
./wp_backup_db.sh /home/user/public_html
# 3. Verificar que los dumps se crearon
ls -lh /home_D0/fixes/backups/*.sql.gzLo que hace wp_backup_db.sh:
- Busca todos los
wp-config.phpbajo el directorio indicado - Extrae
DB_NAME,DB_USER,DB_PASSWORD,DB_HOSTcon regex - Prueba conexión MySQL antes del dump (timeout 10s)
mysqldump --single-transaction --quick+ gzip (timeout 120s)- Genera archivo temporal de credenciales con
chmod 600, lo elimina después - Lock con
flockpara evitar ejecuciones simultáneas - Log detallado en
/home_D0/fixes/logs/backup_db_*.log - Output:
/home_D0/fixes/backups/db_{slug}_{timestamp}.sql.gz
Punto de decisión: Si el backup de BD falla, NO continuar hasta resolverlo.
Fase 2 — Escaneo y Triage
Herramienta: malware_scanner.py | Estado: ✅ Implementado
# Escaneo completo, solo reporte (sin mover archivos)
python3 malware_scanner.py --scan /home --no-quarantine --report both
# Más sensible (más hallazgos, más falsos positivos)
python3 malware_scanner.py --scan /home --no-quarantine --threshold 40
# Solo un sitio específico
python3 malware_scanner.py --scan /home/user/public_html --no-quarantine --report bothLo que hace malware_scanner.py en modo escaneo:
- Recorre recursivamente buscando archivos PHP (
.php,.phtml,.php3-7,.phar,.inc) - Ignora archivos > 5MB y rutas whitelisted (
/proc,/sys,.git,node_modules) - Aplica 6 capas de detección en orden:
- 70 firmas core embebidas (regex compilados)
- 6 firmas internas curadas (
signatures/internal_knowledge.json) - 6 firmas comunidad (
signatures/community.json) - 9 IOC locales (
signatures/local_iocs.json) - 5 reglas YARA (
signatures/yara/*.yar) — requiere yara-python o yara-x - 5 regex fallback (
signatures/yara_fallback.json) — si YARA no está disponible
- Calcula entropía Shannon (0-8) y suma puntos si > 5.2
- Analiza estructura PHP: gotos excesivos, líneas largas, funciones peligrosas, base64→PHP
- Detecta y extrae PHP embebido dentro de archivos ZIP (magic bytes
PK\x03\x04) - Aplica deducción de falsos positivos (hasta -80pts para wp-core, vendors, plugins conocidos)
- Calcula SHA256 de cada archivo
Archivos de salida generados:
| Archivo | Contenido |
|---|---|
scan_*_files.txt |
Triage rápido: [VERDICT][SCORE][SOURCES] /path/to/file |
scan_*.json |
JSON estructurado: score, entropy, SHA256, matches con línea y snippet |
scan_*.log |
Log legible con contexto completo de cada hallazgo |
scan_*.rm_ALL.txt |
Script bash con rm -f para TODOS los archivos detectados |
scan_*.rm_FIRMA.txt |
Un script rm por cada tipo de firma (ej: rm_BACKDOOR_HEX_ENCODED_CURL_FETCH.txt) |
Para triage rápido preliminar (antes del scanner completo):
./malware_scan.sh # grep rápido: firmas, PHP en uploads, recientes, nombres, permisos 777Clasificación de veredictos:
| Veredicto | Score | Acción |
|---|---|---|
MALWARE |
≥90 | Actuar de inmediato — alta confianza |
LIKELY_MALWARE |
80-89 | Revisar manualmente, confirmar y actuar |
SUSPICIOUS |
60-79 | Investigar contexto antes de decidir |
CLEAN |
<60 | Sin acción (no se reporta) |
Fase 3 — Análisis y Clasificación de Hallazgos
Herramienta: malware_scanner.py (campo cleanable en JSON) | Estado: ⚠️ Parcial
El scanner ya marca cada hallazgo con "cleanable": true/false en el JSON, pero el criterio actual es limitado: solo considera "limpiable" las firmas de hacklink (HACKLINK_KNOWN_DOMAIN, HACKLINK_WP_HOOK_FOOTER, HACKLINK_STATIC_GUARD, IOC_TELEGRAM_COMMENT) con score < 90.
Para cada archivo detectado, aplicar criterio humano adicional:
3a. Archivos a ELIMINAR completamente
Criterios para eliminación total:
- El archivo entero es malware (webshell, dropper, loader)
- Archivos PHP en
/uploads/(no deberían existir) — el scanner ya suma +70pts porLOCATION_PHP_IN_UPLOADS - Archivos con nombres sospechosos (
wp-developer.php,about.phpsuelto) — firmaSUSPICIOUS_FILENAME+50pts - Entropy > 6.5 + score ≥ 90 (archivo cifrado/comprimido) — firma
ENTROPY_HIGH+50pts - Binarios disfrazados de PHP (header
%PDF-) — firmaOBFUSC_PDF_HEADER_SPOOF+85pts
Patrones que el scanner detecta como 100% maliciosos (≥90pts):
- ZIP droppers:
LOADER_ZIP_WRAPPER_INCLUDE(97pts) - GLOBALS hex dispatch:
OBFUSC_GLOBALS_HEX_DISPATCH(90pts) - Malware conocido:
MALWARE1_MONARX_FAKEyMALWARE1_ICWDOMAIN(99pts) - PHP embebido en ZIP:
CONTAINER_ZIP_EMBEDDED_PHP(90pts)
3b. Archivos a LIMPIAR (remover solo líneas inyectadas)
Criterios para limpieza parcial:
- Archivos legítimos de WordPress con código inyectado al inicio o final
wp-settings.php,wp-config.php,index.phpdel tema con líneas extra- Inyecciones de hacklinks (bloques
add_action('wp_footer', ...)maliciosos) - Prepend/Append de
@includeorequireapuntando a archivos maliciosos - Comentarios tipo Telegram (
// t.me/...) seguidos de código malicioso
Patrones que --clean puede remover automáticamente (3 CLEAN_PATTERNS):
/* Telegram : ... */ if(!function_exists('wp_core_check')){...} ← hacklink Telegram
if(!function_exists(...)){...hacklinkmarket...} ← hacklink market
<?php [1-5 líneas] <?php ← bloque PHP prepend✅ Patrones ahora cubiertos por --clean automático (v1.2.0):
@include "\x2f..."; ← include ofuscado al inicio del archivo
eval(base64_decode("...")); ← eval inyectado como primera línea
Inyecciones append al final (después del ?> de cierre)
@include desde /tmp/, /var/tmp/, /dev/shm/🔧 Patrones que aún requieren limpieza MANUAL:
Bloques eval/base64 insertados en medio de archivos core de temas
Inyecciones multi-línea complejas intercaladas con código legítimoProcedimiento de limpieza quirúrgica (manual):
- Abrir el archivo y localizar las líneas inyectadas
- Verificar que el código restante es WordPress legítimo
- Remover SOLO las líneas maliciosas
- Validar que el archivo funciona:
php -l archivo.php
Fase 4 — Ejecución de Limpieza
Herramienta: malware_scanner.py | Estado: ✅ Implementado (3 modos)
# Opción A: Cuarentenar (mover a /home_D0/fixes/quarantine/)
python3 malware_scanner.py --scan /home --report both
# Opción B: Auto-limpieza de hacklinks + cuarentena del resto
python3 malware_scanner.py --scan /home --clean --report both
# Opción C: Deshabilitar in-situ (chmod 000 + renombrar .DISABLED)
python3 malware_scanner.py --scan /home --disable --report bothLo que hace cada modo:
| Modo | Flag | Acción | Backup previo | Log |
|---|---|---|---|---|
| Cuarentena | (default) | Mueve archivo a quarantine/{timestamp}_{filename} |
No (se mueve completo) | scan_*.log |
| Auto-limpieza | --clean |
Aplica 3 regex CLEAN_PATTERNS, si match → reescribe archivo limpio; si no → cuarentena | ✅ quarantine/backup_{ts}_{file} |
scan_*.log |
| Deshabilitar | --disable |
chmod 000 + renombra a .DISABLED |
No (archivo queda in-situ) | scan_*.log + /home/{user}/malware_disabled_log.txt |
Limitación de --clean: Solo cubre 3 patrones de hacklink. El resto de inyecciones (eval/base64 prepend, includes ofuscados) requieren limpieza manual o restauración de core (Fase 5).
Para eliminación selectiva por tipo de firma:
# Revisar un grupo antes de ejecutar
cat logs/scan_*.rm_BACKDOOR_HEX_ENCODED_CURL_FETCH.txt
# Ejecutar solo si confirmado (PRECAUCIÓN: verificar falsos positivos)
bash logs/scan_*.rm_LOCATION_PHP_IN_UPLOADS.txtFase 5 — Restauración de WordPress Core
Herramientas: wp_reemplaza.sh + malware_scanner.py --validate-wp | Estado: ✅ Implementado
# 1. Asegurar copia limpia en /home_D0/fixes/wordpress/
# (descargada de wordpress.org, versión correcta)
# 2. Restaurar todos los sitios WP encontrados
./wp_reemplaza.sh
# 3. Validar integridad post-restauración
python3 malware_scanner.py --scan /home --validate-wp --report bothLo que hace wp_reemplaza.sh:
- Busca todos los
wp-config.phpbajo/home - Por cada sitio encontrado:
- Valida estructura WP (requiere wp-admin/ y wp-includes/)
- Detecta versión WP instalada vs versión de la copia limpia (advierte si mismatch)
- Detecta Multisite (advierte pero continúa)
- Lee credenciales DB del wp-config.php
- Backup de BD (mysqldump + gzip) — aborta si falla
- Backup de core (tar.gz de wp-admin, wp-includes, *.php raíz)
- Rsync desde copia limpia con
--delete --checksum - Excluye
wp-content/ywp-config.phpdel rsync - Restaura permisos (755 dirs, 644 files) y ownership original
- Lock con
flockanti-ejecución simultánea - Log:
/home_D0/fixes/logs/repair_wp_*.log
Lo que hace --validate-wp en el scanner:
- Compara MD5 de cada archivo en
wp-admin/ywp-includes/contra la copia limpia - Reporta
[MISSING](archivo no existe) y[MODIFIED](hash diferente) - Solo compara, NO restaura — para restaurar usar
wp_reemplaza.sh
La restauración preserva:
wp-config.php(credenciales del sitio)wp-content/completo (plugins, temas, uploads)- Ownership original del usuario de hosting
Fase 6 — Validación Post-Limpieza
Herramienta: malware_scanner.py (re-ejecución manual) | Estado: ⚠️ Manual
# Re-escanear para confirmar limpieza
python3 malware_scanner.py --scan /home --no-quarantine --report both
# Comparar con escaneo anterior
diff <(grep '^\[MALWARE\]' logs/scan_ANTERIOR_files.txt) \
<(grep '^\[MALWARE\]' logs/scan_NUEVO_files.txt)✅ Implementado: Flag --verify re-escanea automáticamente post-limpieza y reporta remanentes.
Checklist de validación:
- Cero hallazgos MALWARE en re-escaneo
- LIKELY_MALWARE restantes son falsos positivos confirmados
- Sitios WordPress cargan correctamente en navegador
- Login de admin funciona
- No hay archivos PHP en
/uploads/ - Permisos restaurados correctamente
Fase 7 — Hardening y Permisos
Herramienta: fix_permissions.sh | Estado: ✅ Implementado
# Corregir todos los usuarios
./fix_permissions.sh --all
# Solo usuarios específicos
./fix_permissions.sh -u juan -u pedro
# Simular sin cambios
./fix_permissions.sh --dry-run --all
# Con salida detallada
./fix_permissions.sh --verbose --allLo que hace fix_permissions.sh:
- Recorre cada usuario en
/home/ - Ignora directorios del sistema (
lost+found,fixes,clamav)
| Recurso | Permisos aplicados |
|---|---|
| Propietario | user:user recursivo |
| Directorios | 755 |
| Archivos regulares | 644 |
wp-config.php |
600 |
.htaccess |
644 |
/home/user (base) |
711 |
public_html |
750 |
Motor de Detección — Arquitectura
6 capas de firmas (implementadas en malware_scanner.py)
| Capa | Fuente | Archivo | Cantidad | Confianza |
|---|---|---|---|---|
| 1 | Core embebidas | malware_scanner.py (SIGNATURES[]) |
70 regex | Muy alta |
| 2 | Internas curadas | signatures/internal_knowledge.json |
6 | Alta |
| 3 | Comunidad | signatures/community.json |
6 | Media-Alta |
| 4 | IOC locales | signatures/local_iocs.json |
9 | Variable |
| 5 | YARA nativas | signatures/yara/*.yar |
5 reglas | Alta |
| 6 | YARA fallback | signatures/yara_fallback.json |
5 regex | Media |
Motor YARA (prioridad de backends)
- yara-x (Rust, Python ≥ 3.9) — preferido
- yara-python (clásico) — fallback
- Sin YARA — usa regex de
yara_fallback.json
Entropía Shannon (implementada)
| Entropía | Puntos | Interpretación |
|---|---|---|
| > 6.5 | +50 | Casi seguro cifrado/comprimido |
| 5.8 – 6.5 | +30 | Probable ofuscación |
| 5.2 – 5.8 | +10 | Moderadamente sospechoso |
| ≤ 5.2 | 0 | Normal |
Solo se aplica si el archivo ya tiene ≥20pts por firmas (evita FP en datos aleatorios legítimos).
Análisis estructural (implementado)
Bonos dinámicos que el scanner agrega automáticamente:
| Patrón | Firma generada | Puntos |
|---|---|---|
| ≥10 gotos consecutivos | STRUCT_GOTO_EXCESSIVE |
Variable |
| Línea > 5000 chars | STRUCT_LONG_LINE |
Variable |
| base64 que decodifica a PHP | STRUCT_B64_PHP_PAYLOAD |
Variable |
| ≥8 funciones peligrosas distintas | STRUCT_MANY_DANGEROUS_FUNCS |
Variable |
Deducción de falsos positivos (implementada)
El scanner reduce automáticamente el score cuando detecta contextos legítimos:
| Contexto | Deducción | Condición |
|---|---|---|
| WordPress core (wp-includes/, wp-admin/) | -30pts | Siempre |
| Plugins/temas con ≥50 líneas | -15pts | Siempre |
| Archivos test/debug/example/sample | -10pts | Por nombre |
| vendor/ o node_modules/ | -40pts | Siempre |
| Plugins FP conocidos (Guzzle, Wordfence, SimplePie, PHPMailer, AWS SDK) | -50pts | Sin firmas graves |
| Archivos .l10n.php (traducciones) | -60pts | Siempre |
| WP core labeled goto (html-api parser) | -80pts | Archivo específico |
| Solo HEX_STRING match (constante criptográfica) | -70pts | Única firma |
| Solo SUSPICIOUS_FILENAME | -50pts | Única firma |
| Solo LARGE_BASE64_STRING en archivo >100KB | -70pts | Única firma |
| index.php en uploads/ <100 bytes sin código peligroso | -70pts | Archivo específico |
Extracción de PHP en ZIPs (implementada)
El scanner detecta archivos con magic bytes ZIP (PK\x03\x04), extrae cualquier archivo .php contenido y lo escanea contra todas las firmas. Agrega CONTAINER_ZIP_EMBEDDED_PHP (90pts).
Reconocimiento de Código Ofuscado
Técnicas de ofuscación detectadas por el scanner
| Técnica | Ejemplo | Firma | Score |
|---|---|---|---|
| Base64 largo | eval(base64_decode("aWYoaX...")) |
OBFUSC_LARGE_BASE64_STRING |
65 |
| Hex strings | "\x65\x76\x61\x6c" (≥20 escapes) |
OBFUSC_HEX_STRING |
70 |
| Char-index | ("create_function")[0].("eval")[2]... |
OBFUSC_CHAR_INDEX_FUNCTIONS |
80 |
| Comment+Char-index | /*\x00\x01*/("ab")[0]. combo |
OBFUSC_COMMENT_FUNC |
85 |
| Goto spaghetti | goto a; b: ... goto c; a: ... (≥10) |
OBFUSC_GOTO_SPAGHETTI |
70 |
| URL decode alphabet | urldecode("%65%76%61%6c") |
OBFUSC_URLDECODE_ALPHABET |
80 |
| Curly brace index | $var{0}.$var{1}.$var{2} |
OBFUSC_CURLY_BRACE_CHARINDEX |
75 |
| GLOBALS hex | $GLOBALS["\x00\x01"]["\x02"]() |
OBFUSC_GLOBALS_HEX_DISPATCH |
90 |
| PDF spoof | %PDF-1.0 <?php eval(...) |
OBFUSC_PDF_HEADER_SPOOF |
85 |
| Noop camouflage | Bloques de código muerto alrededor del payload | OBFUSC_NOOP_CAMOUFLAGE |
Variable |
| Single-line packed | Todo el código en una línea enorme | OBFUSC_SINGLELINE_PACKED |
Variable |
| Eval anidado | eval($var($var(...))) |
EVAL_NESTED_VAR_CALL |
85 |
| Junk variable padding | Variables sin uso intercaladas | OBFUSC_JUNK_VARIABLE_PADDING |
Variable |
| Variable function call | $var = "eval"; $var(...) |
OBFUSC_VARIABLE_FUNCTION |
Variable |
| String split construct | $a="ev"."al"; $a(...) |
OBFUSC_STR_SPLIT_CONSTRUCT |
Variable |
Decodificación manual de payloads
Para investigar código ofuscado específico:
- Base64:
echo "payload" | base64 -d - Hex:
echo -e "\x65\x76\x61\x6c"ophp -r 'echo "\x65\x76\x61\x6c";' - URL encode:
php -r 'echo urldecode("%65%76%61%6c");' - Anidado: Decodificar capa por capa, desde la más externa hacia adentro
- ZIP embebido:
unzip -l archivo.phpsi tiene header PK
Gestión de Firmas
Agregar un nuevo IOC observado
Editar signatures/local_iocs.json:
{
"name": "NOMBRE_DESCRIPTIVO_MAYUSCULAS",
"pattern": "regex_del_patron",
"score": 80,
"description": "Descripción breve del comportamiento malicioso"
}Guía de scoring:
- 40-59: Sospechoso pero ambiguo (podría ser legítimo)
- 60-79: Probablemente malicioso, requiere contexto
- 80-89: Malware probable, limpieza automática activable (score ≥
AUTO_CLEAN_THRESHOLD) - 90-99: Malware confirmado, alta confianza
Umbrales configurados en el scanner:
SCORE_THRESHOLD = 60— Puntuación mínima para reportarAUTO_CLEAN_THRESHOLD = 80— Para limpieza automática con--cleanMAX_FILE_SIZE = 5MB— Archivos más grandes se ignoran
Falsos Positivos Conocidos
Componentes legítimos que disparan firmas frecuentemente (el scanner ya aplica deducción automática para la mayoría):
| Componente | Firma disparada | Razón | Deducción automática |
|---|---|---|---|
| Guzzle HTTP | BACKDOOR_HEX_ENCODED_CURL_FETCH |
cURL con opciones hex legítimas | -50pts (KNOWN_FP_PLUGIN_PATHS) |
| Wordfence | COMMUNITY_AUTO_PREPEND_BACKDOOR |
auto_prepend_file para WAF |
-50pts (plugin conocido) |
| wp-migrate-db | OBFUSC_LARGE_BASE64_STRING |
Serializa datos en base64 | -70pts si >100KB y es la única firma |
| Starter Templates | STRUCT_LONG_LINE |
Inline CSS/JS genera líneas largas | -15pts (plugin legítimo) |
| WP Rocket | BACKDOOR_HEX_ENCODED_CURL_FETCH |
Código deprecated con patrones cURL | -50pts |
| WP HTML Processor | OBFUSC_GOTO_SPAGHETTI |
Usa goto legitimamente en parser | -80pts (WP_CORE_LABELED_GOTO_FILES) |
| Google API Client | Varias firmas cURL | SDK legítimo | -50pts (KNOWN_FP_PLUGIN_PATHS) |
| AWS SDK PHP | BACKDOOR_HEX_ENCODED_CURL_FETCH |
HTTP client legítimo | -50pts |
| SimplePie / PHPMailer | Patrones de funciones peligrosas | Uso legítimo de funciones PHP | -50pts |
Regla práctica: Si un archivo está en un plugin conocido (wp-content/plugins/[nombre-oficial]/) Y tiene score < 90 después de deducciones, probablemente es falso positivo.
Paths whitelisted en el scanner (KNOWN_FP_PLUGIN_PATHS):/wp-mail-smtp, /vendor_prefixed/, /vendor/, /guzzlehttp/, /google/auth/, /google/apiclient/, /aws/aws-sdk-php/, /psr/log/, /symfony/polyfill, /SimplePie/, /PHPMailer/, /all-in-one-wp-migration/
Comandos de Referencia Rápida
# ── BACKUP ──
./wp_backup_db.sh /home # Backup de todas las BD
./wp_backup_db.sh /home/user/public_html # Backup de un sitio
# ── TRIAGE RÁPIDO (grep, antes del scanner) ──
./malware_scan.sh # Firmas grep, PHP uploads, recientes, permisos 777
./wp_security_scan.sh # Cuarentena básica + diff WP core
# ── ESCANEO HEURÍSTICO ──
python3 malware_scanner.py --scan /home --no-quarantine --report both # Solo reporte
python3 malware_scanner.py --scan /home/user/public_html --threshold 40 # Más sensible
python3 malware_scanner.py --scan /home --validate-wp --report both # Con validación WP
# ── LIMPIEZA ──
python3 malware_scanner.py --scan /home --report both # Cuarentena
python3 malware_scanner.py --scan /home --clean --report both # Auto-limpieza (3 patterns)
python3 malware_scanner.py --scan /home --disable --report both # chmod 000 + .DISABLED
# ── RESTAURACIÓN ──
./wp_reemplaza.sh # Restaurar WordPress core (con backup previo)
./fix_permissions.sh --all # Restaurar permisos (todos los usuarios)
./fix_permissions.sh --dry-run --all # Simular sin cambios
./fix_permissions.sh -u juan -u pedro # Solo usuarios específicosEstructura del Proyecto
| Componente | Rol | Líneas/Tamaño |
|---|---|---|
malware_scanner.py |
Motor principal: 6 capas, scoring, entropía, ZIP, reportes, cuarentena, clean, disable, validate-wp | ~1300 líneas Python |
signatures/internal_knowledge.json |
6 firmas internas de alta confianza (incidentes reales) | JSON |
signatures/community.json |
6 firmas comunitarias (ZIP dropper, cookie exec, auto_prepend) | JSON |
signatures/local_iocs.json |
9 IOC locales observados (volovot.ru, fire2013, charindex) | JSON |
signatures/yara_fallback.json |
5 regex fallback cuando YARA no está disponible | JSON |
signatures/yara/php_webshells_curated.yar |
5 reglas YARA curadas | YARA |
wp_backup_db.sh |
Backup BD MySQL: autodescubre wp-config, dump+gzip, lock, logs | Bash |
wp_reemplaza.sh |
Restauración WP core: backup BD+core, rsync, permisos, detección versión | Bash |
fix_permissions.sh |
Permisos: 755/644/600/711/750, dry-run, verbose, por usuario, CWP/cPanel | Bash |
malware_scan.sh |
Triage rápido: grep firmas, PHP uploads, recientes, nombres, permisos 777 | Bash |
wp_security_scan.sh |
Cuarentena básica: mueve sospechosos, diff WP core, archivos recientes | Bash |
wp_db_scan.sh |
Escaneo BD: inyecciones wp_options, SEO spam wp_posts, admins maliciosos, transients | Bash |
cron_check.sh |
Detección crontabs maliciosos: wget/curl reinstalación, 16 patrones, --fix |
Bash |
remediate.sh |
Orquestador pipeline: 7 fases backup→scan→db→cron→clean→restore→verify→permisos | Bash |
malware_refs/ |
Muestras de referencia (archive.php, index.php) para testing | PHP |
logs/ |
Output de escaneos: JSON, texto, scripts rm | Generado |
Mejoras Pendientes (Roadmap)
v1.2.0 — Completadas
| Mejora | Impacto | Estado |
|---|---|---|
| Alto | ✅ Implementado | |
--verify para re-escaneo automático post-limpieza |
Medio | ✅ Implementado |
concurrent.futures) |
Alto | ✅ Implementado |
KNOWN_GOOD_HASHES) |
Medio | ✅ Implementado |
| Bajo | ✅ Implementado | |
| Medio | ✅ Implementado |
v1.3.0 — Prioridad Alta
| # | Mejora | Impacto | Estado |
|---|---|---|---|
| 1 | wp_db_scan.sh: detectar inyecciones en wp_options (siteurl/home), SEO spam/iframes en wp_posts, usuarios admin maliciosos, transients sospechosos |
Alto | ✅ Implementado |
| 2 | .htaccess maliciosos — detectar redirecciones condicionales (User-Agent/referer spam), php_value auto_prepend_file, ErrorDocument 404 a scripts maliciosos |
Alto | ✅ Implementado |
| 3 | crontab -l -u $user, /var/spool/cron/, /etc/cron.d/ buscando wget/curl de reinstalación |
Alto | ✅ Implementado |
| 4 | remediate.sh: encadena backup→scan→classify→clean→restore→verify→permissions en un solo comando |
Alto | ✅ Implementado |
v1.4.0 — Prioridad Media
| # | Mejora | Impacto | Estado |
|---|---|---|---|
| 5 | Reporte HTML cliente — resumen ejecutivo, gráficas de severidad, lista de acciones tomadas | Medio — comunicación al cliente | 🔲 Pendiente |
| 6 | Test suite automatizado — pytest contra malware_refs/ + archivos limpios, validar firmas y FP |
Medio — evitar regresiones | 🔲 Pendiente |
| 7 | Notificaciones — email/webhook cuando escaneo programado detecta malware nuevo | Medio — monitoreo periódico | 🔲 Pendiente |
| 8 | Rotación credenciales — regenerar salts wp-config.php, forzar password reset admins, rotar MySQL | Medio — post-brecha obligatorio | 🔲 Pendiente |
| 9 | Historial SQLite — persistir hallazgos, tendencias, reinfecciones recurrentes por servidor | Medio — análisis longitudinal | 🔲 Pendiente |
v1.5.0 — Prioridad Baja
| # | Mejora | Impacto | Estado |
|---|---|---|---|
| 10 | Escaneo plugins/temas vulnerables — comparar versiones vs API WPScan/Wordfence CVEs | Bajo — vector de reinfección | 🔲 Pendiente |
| 11 | Modo watch (inotify) — monitoreo en tiempo real de cambios filesystem post-limpieza | Bajo — daemon temporal | 🔲 Pendiente |
| 12 | Integración ClamAV — complementar con detección de binarios/malware no-PHP | Bajo — complementario | 🔲 Pendiente |
Anti-Patrones (NO hacer)
- NO ejecutar
--cleanen la primera pasada sin revisar hallazgos - NO eliminar archivos sin backup de BD previo (
wp_backup_db.shprimero) - NO confiar ciegamente en
scan_*.rm_ALL.txt— revisar falsos positivos antes - NO ignorar hallazgos SUSPICIOUS — podrían ser malware sofisticado con baja firma
- NO restaurar WP core sin verificar la versión correcta del sitio (el script advierte mismatch)
- NO olvidar re-escanear después de la limpieza
- NO dejar permisos 777 después de la remediación (
fix_permissions.sh --all) - NO ejecutar
wp_reemplaza.shsin confirmar que la copia limpia existe en/home_D0/fixes/wordpress/