Site WordPress infecté : contrôler le cron WordPress malveillant

Un site WordPress infecté ne se reconnaît pas toujours à l’écran. Parfois, les pages “normales” restent affichées, et le problème se cache ailleurs, dans le bruit technique. Le cron en fait partie. Un cron WordPress malveillant peut continuer à frapper la boutique ou le blog même quand personne ne touche au contenu, parce que WordPress relance ses tâches planifiées via wp-cron.php. Et si l’intrusion a créé ou modifié ces tâches, elle peut transformer WordPress en relais, en générateur de trafic, voire en point de contrôle pour d’autres charges.

Le piège, c’est qu’on cherche souvent un fichier modifié ou un plugin louche, sans regarder le mécanisme qui tourne en arrière-plan. Quand le faux cron se met en route, il peut produire des symptômes très concrets: des pics de charge CPU, des logs serveur saturés par des requêtes répétées, des tentatives d’accès à des URL internes, ou encore une succession d’appels POST vers des endpoints louches. Le site semble “infecté”, mais l’équipe se perd entre “il y a une attaque” et “mais on ne sait pas quoi faire dans WordPress”.

Ce guide propose une méthode pragmatique pour reprendre la main sur le cron. L’objectif n’est pas seulement de “stopper” en urgence, mais de comprendre ce qui déclenche les tâches et comment éviter que la reprise serve de tremplin à la même infection.

Comprendre le rôle de wp-cron, et pourquoi il est facile à abuser

WordPress n’utilise pas toujours un cron système. Par défaut, il déclenche wp-cron.php à chaque visite (ou presque, selon les paramètres). Concrètement, quand un visiteur arrive sur le site, WordPress vérifie les événements planifiés dans sa base de données et lance les callbacks qui sont “dus”. C’est pratique, mais ça signifie deux choses:

Première chose: si un attaquant a réussi à enregistrer des événements cron, ils tourneront à chaque afflux. Si personne ne visite, les tâches peuvent ralentir, puis s’accélérer au retour du trafic.

Deuxième chose: si le cron est exploité, on peut voir une cascade de requêtes qui n’ont pas forcément l’air “malveillante” au niveau navigateur. On voit surtout des appels serveur, des logs, et parfois des changements côté base de données.

image

Le cron malveillant se présente souvent sous forme d’événements enregistrés par un plugin ou une charge qui a déjà pris place. Dans beaucoup de cas observés sur des environnements WordPress compromis, les événements sont stockés dans la table d’options (et parfois d’autres tables selon les implémentations). Un mauvais acteur peut aussi détourner une fonctionnalité légitime, par exemple un plugin de newsletter, de spam protection, ou un outil d’automatisation, en lui injectant une logique qui planifie des exécutions régulières.

image

Ce point est important pour la suite: contrôler le cron ne suffit pas si la source du cron reste présente. Arrêter les exécutions sans enlever l’agent qui les enregistre, c’est parfois comme couper la sirène en laissant le feu brûler derrière le mur.

Les signes typiques d’un cron WordPress malveillant

Avant de toucher à quoi que ce soit, il faut confirmer que le problème vient bien des tâches programmées. Dans les incidents, j’ai vu des patterns assez répétitifs, pas identiques d’un site à l’autre, mais reconnaissables.

Sur le plan opérationnel, surveillez:

    les pics de trafic vers wp-cron.php ou vers des URL qui ressemblent à des endpoints d’exécution internes; l’augmentation soudaine du nombre de requêtes par minute dans les logs, même sans campagne marketing; des erreurs 502/503 corrélées à des boucles de tâches qui tentent de se relancer; des connexions sortantes ou des appels à des domaines inconnus, si votre environnement trace les flux sortants.

Sur le plan “WordPress”, le site peut continuer d’afficher des pages, tout en ayant des comportements bizarres en arrière-plan: création de comptes, changements d’URL, tentatives de sauvegardes ou de mises à jour qui échouent, ou insertion de spam dans la base. Le cron est souvent le mécanisme de déclenchement.

Il y a aussi une nuance, parfois oubliée: un cron “gênant” n’est pas forcément malveillant. Certains plugins font tourner des tâches lourdes trop fréquemment (synchronisations, exports, génération de caches). La différence se joue dans le contenu des événements, les callbacks réellement exécutés, et la présence d’un code injecté ou de paramètres suspects.

L’approche la plus sûre: réduire la pression avant d’analyser

Quand un site WordPress infecté commence à tourner comme une machine, l’urgence est de stabiliser l’exécution. Si vous patientez pendant que l’attaque continue, vous augmentez la surface d’instabilité et vous risquez aussi d’aggraver la base de données.

La logique que j’utilise en intervention ressemble à ceci: d’abord, limiter l’exécution automatique du cron via wp-cron.php, ensuite, analyser ce qui reste dans WordPress (et sur le système), puis seulement ensuite supprimer ce qui enregistre les événements.

WordPress offre des modes d’atténuation selon l’hébergement.

Si votre objectif est de stopper immédiatement les exécutions déclenchées par les visiteurs, vous pouvez désactiver wp-cron.php (ou en empêcher l’accès) et gérer ensuite les tâches via un cron système contrôlé. Sur certains hébergeurs, on peut aussi configurer un “vrai” cron au niveau serveur, à horaires maîtrisés. Le trade-off est clair: vous perdez l’automatisme “à la visite”. Les publications différées, les envois de emails, les mises à jour planifiées et certains mécanismes e-commerce peuvent être retardés.

Je préfère traiter ce compromis comme un thermostat: on coupe le flux principal le temps de reprendre le contrôle, puis on remet en place ce qui est légitime, avec un rythme raisonnable.

Stopper temporairement wp-cron pour reprendre la main

Voici une séquence de travail pragmatique. Elle suppose que vous avez accès à un plan B (sauvegarde, accès shell ou au moins accès base de données), et qu’un “arrêt complet” du site n’est pas souhaité.

    Créez une sauvegarde de la base de données et vérifiez que vous pouvez restaurer (même si vous ne le faites pas). Désactivez temporairement le déclenchement automatique de wp-cron.php (par exemple via configuration d’accès ou méthode d’empêchement au niveau applicatif), pour stopper les exécutions déclenchées par la visite. Forcez ensuite l’arrêt des tâches en cours en vidant ou en neutralisant les événements cron suspects, mais uniquement après identification rapide de ce qui est stocké dans WordPress. Inspectez les plugins et thèmes actifs, puis recherchez les modifications de fichiers récentes et les charges injectées (y compris dans les fichiers “inattendus” comme des includes ou des assets). Une fois le code source nettoyé, réactivez un cron contrôlé, soit via serveur, soit via une réactivation maîtrisée de WordPress, en surveillant les logs pendant 24 à 48 heures.

Cette approche a un avantage psychologique: vous cessez la pression du temps. Le cron malveillant peut continuer pendant que vous diagnostiquez, mais si vous coupez le déclencheur, vous gagnez des heures.

Méthodes concrètes, selon votre niveau d’accès

Selon votre infrastructure, vous n’aurez pas toujours la même latitude.

Sur un hébergement avec accès fichier et un minimum de contrôle HTTP, on peut bloquer l’exécution déclenchée par wp-cron.php au niveau serveur ou applicatif. L’idée n’est pas de “boucher” sans comprendre, mais de faire en sorte que WordPress ne lance plus les callbacks à la demande des visiteurs.

Si vous avez un accès shell, l’approche peut être plus https://gardewp.fr/nettoyage-malware-wordpress/ propre, en configurant un cron système qui appelle uniquement wp-cron.php quand vous décidez de relancer des événements. Dans ce cas, vous pouvez aussi filtrer le taux, réduire la fenêtre de risque, et aligner l’exécution sur une période de surveillance.

Dans les environnements très verrouillés, la désactivation complète peut empêcher aussi le fonctionnement légitime. Le bon compromis est alors de neutraliser les événements suspects plutôt que de couper tous les événements.

Identifier les événements cron enregistrés dans WordPress

Une fois l’exécution mise au ralenti, l’analyse devient beaucoup plus lisible. La partie “WordPress” du cron malveillant réside dans les événements enregistrés.

Sans entrer dans une recette à copier-coller qui dépendrait de votre version exacte, retenez ceci: vous cherchez l’équivalent de “quels événements sont en attente, à quelle fréquence, et quel callback est exécuté”. Les appels malveillants utilisent souvent des callbacks qui n’ont rien à faire là, par exemple des actions qui ne correspondent pas à un plugin installé, ou des hooks créés de façon artificielle.

Dans la base, on retrouve typiquement des structures liées à cron. La méthode consiste à:

Récupérer la liste des événements planifiés; Filtrer ceux qui sont à la fois récents et inconnus; Remonter à l’origine, souvent via le plugin ou le fichier qui a enregistré le hook.

Sur des sites compromis, j’ai déjà vu des noms de hooks “cohérents” en apparence, mais dont le callback mène à une fonction absente du plugin officiel, ou à un code injecté dans un fichier qui ne devrait jamais contenir de logique d’exécution distante.

Si vous utilisez wp-cli, vous pouvez souvent investiguer plus vite, parce que vous évitez les manipulations manuelles. Si vous n’avez pas wp-cli, un accès à phpMyAdmin ou à un outil équivalent suffit, mais il faut travailler avec prudence. Modifier la table “cron” sans comprendre peut casser une partie du calendrier WordPress.

Le point important: ne vous focalisez pas seulement sur “l’événement le plus actif”. Un cron malveillant peut installer une boucle qui se recharge elle-même, et si vous supprimez un seul événement, l’agent réenregistrera le suivant. C’est pour ça que le nettoyage du code (plugins, fichiers, utilisateurs) reste indispensable.

Nettoyer la cause, pas juste le symptôme

Le cron malveillant est souvent le bras armé d’un agent déjà en place. Le vrai travail consiste à neutraliser ce qui enregistre les événements.

Dans la pratique, les causes fréquentes sont:

    plugin piraté ou plugin qui a été modifié (y compris par l’inclusion de quelques lignes discrètes); thème modifié (moins courant que les plugins, mais ça arrive); fichier uploadé en forme de webshell ou de charge “dormante”; compromission d’un utilisateur admin avec un compte utilisé pour réenregistrer des événements.

Si vous n’avez pas déjà trouvé le point d’entrée, partez du présent. Identifiez les plugins qui viennent d’être ajoutés, ceux dont les fichiers ont été modifiés récemment, et ceux qui contiennent des fonctions qui ne collent pas à leur rôle. Regardez aussi les dossiers “upload” et les fichiers temporaires ou cachés. Sur certains incidents, la charge ne vit pas dans le code PHP principal mais dans des inclusions appelées par des hooks.

Une règle d’expérience: quand vous voyez un cron qui déclenche des appels vers des URL externes, ou des appels à des endpoints internes très spécifiques, ce n’est pas un plugin de cache. Ce sont presque toujours des mécanismes de pilotage.

La difficulté est de ne pas faire d’“arbre” en espérant que l’agent se trouve au hasard. Si vous avez arrêté le cron au bon moment, vous avez gagné le temps pour inspecter sérieusement.

Rebuild maîtrisé: suppression, désactivation, puis restauration ciblée

Selon la gravité, vous aurez deux stratégies.

La stratégie “ciblée” consiste à désactiver les plugins et thèmes suspects, supprimer les fichiers manifestement modifiés, puis supprimer les événements cron associés. C’est rapide quand la cause est claire.

La stratégie “rebuild” est plus lourde mais plus sûre quand l’environnement est trop incertain. Elle ressemble à une restauration à partir d’une sauvegarde saine, puis à l’intégration contrôlée des modifications légitimes. Dans un site WordPress infecté où le cron malveillant s’inscrit dans une chaîne d’actions, un rebuild réduit le risque de laisser une petite bombe.

Le compromis, c’est le temps. Sur un site e-commerce, retarder l’intégration de versions peut casser des fonctionnalités. C’est pour ça que je préfère, quand c’est possible, commencer par une désactivation ciblée et un nettoyage “propre”, puis évoluer vers une restauration complète si l’agent résiste.

Contrôler le cron après nettoyage: quoi surveiller dans les logs

Une fois la suppression faite, ne remettez pas le site en mode “croire sur parole”. Vous devez vérifier que le cron ne redémarre pas comme avant.

Le contrôle se fait en deux axes: ce qui se déclenche, et à quel rythme.

Sur votre journal web (Nginx, Apache, hébergeur), cherchez les requêtes vers wp-cron.php. Le but n’est pas zéro requête, mais un rythme normal et lié au fonctionnement attendu. Sur un site actif, il est plausible d’avoir des exécutions régulières, mais elles ne devraient pas devenir un torrent.

Ensuite, surveillez les événements côté WordPress. L’important est que les hooks suspects aient disparu et que les fonctions exécutées correspondent à des plugins que vous connaissez.

image

Enfin, surveillez des signaux indirects: CPU qui remonte, emails qui partent, erreurs étranges, ou création de comptes nouveaux sans action.

Voici un mini-check des points à valider après mise à jour ou réactivation du cron:

    Les requêtes vers wp-cron.php redeviennent compatibles avec la volumétrie du site. Les événements cron récents suspects ne réapparaissent pas après quelques heures. Les plugins et thèmes actifs ne contiennent plus de modifications inattendues. Aucun nouveau compte administrateur n’a été créé sans justification. Les logs ne montrent plus d’appels sortants anormaux liés à des hooks cron.

Cinq points, et vous avez déjà une bonne lecture. Si un seul point déraille, je considère que le nettoyage n’est pas terminé.

Éviter que le cron malveillant revienne

Contrôler le cron, c’est aussi fermer la porte qui permet de l’infecter à nouveau.

La prévention la plus efficace que j’ai vue ne se limite pas à “mettre à jour”. Elle combine durcissement, hygiène d’accès, et surveillance.

Renforcez les comptes: mots de passe uniques, suppression des comptes inutiles, et vérification des rôles. Si une intrusion a touché un compte admin, le site peut rester “contaminable” même après suppression des plugins et fichiers.

Durcissez l’accès aux zones d’administration: limitations d’IP quand c’est possible, protection contre la force brute, et validation des formulaires. Beaucoup d’attaques reposent sur une séquence d’accès qui finit par installer un plugin modifié, puis enregistre des événements cron.

Côté serveur, surveillez les fichiers uploadés, les permissions, et le contrôle de l’exécution PHP dans certains dossiers. Les attaques cron aiment parfois se cacher dans des emplacements où l’on ne regarde jamais, surtout dans des dossiers “uploads”.

Et surtout, mettez en place une surveillance simple. Pas besoin d’outils extravagants. Un suivi régulier des requêtes vers wp-cron.php, des changements de fichiers, et des nouveaux utilisateurs peut suffire à détecter le retour d’un agent en quelques heures, pas en quelques jours.

Particularités: quand “désactiver wp-cron” casse des choses

Le contrôle du cron ne doit pas aveugler sur les conséquences. Beaucoup de sites utilisent des tâches planifiées pour des fonctions importantes. Couper wp-cron peut:

    retarder des publications programmées; empêcher des mises à jour de statut dans certains plugins; bloquer des envois automatiques (newsletter, emails transactionnels) selon l’intégration; ralentir la génération de certaines mises en cache.

Un scénario fréquent: vous coupez wp-cron pour stopper une attaque, et le lendemain, l’équipe marketing vous alerte que des emails n’ont pas été envoyés. Le site n’est pas “cassé”, mais les processus sont en attente. Si le cron malveillant était en parallèle, le plus urgent reste la sécurité, mais il faut communiquer en interne.

L’astuce pratique consiste à garder une “fenêtre de pilotage”. Vous pouvez planifier un cron système à rythme réduit, le temps de faire une stabilisation. Ensuite, vous remontez progressivement vers le comportement normal, en surveillant que les événements légitimes fonctionnent.

Cas typiques d’erreurs lors du traitement

Il y a quelques erreurs qui reviennent, et qui font perdre des heures.

Première erreur: croire que supprimer les fichiers malveillants suffit. Si l’agent a déjà enregistré des événements cron, il peut continuer à tenter des actions pendant que le code malveillant est temporairement absent. Ou bien, un plugin légitime a été modifié pour réintroduire l’événement à chaque relance.

Deuxième erreur: supprimer un événement cron “principal” sans chercher le plugin source. Résultat, l’agent réenregistre une nouvelle variante, parfois avec un nom différent.

Troisième erreur: réactiver wp-cron trop tôt, avant nettoyage complet. C’est souvent le moment où l’infection regagne du terrain, parce que WordPress revoit tout, relance les hooks, et l’agent repart.

Quatrième erreur: réinstaller WordPress “par dessus” sans examiner les plugins. Le core est rarement la cible principale. Si votre plugin a été modifié, la réinstallation du core ne corrige pas la cause.

La bonne posture est simple: stabiliser, analyser, supprimer la cause, puis seulement après, remettre un cron normal avec une surveillance resserrée.

Un mot sur la “preuve” et la confiance opérationnelle

Pendant un incident, il y a souvent une question qui revient: “comment être sûr qu’il n’y a plus rien ?”. Sur un site WordPress infecté, la confiance ne se construit pas sur un ressenti, elle se construit sur des signaux convergents.

Quand le cron malveillant est la cause, un bon indicateur est la disparition durable des callbacks suspects, et surtout l’absence de réapparition des événements après une période de surveillance.

Un autre indicateur est la stabilité des logs: pas seulement “ça ne crashe plus”, mais “les mêmes requêtes ne reviennent pas sous la même forme”. Si le pattern d’accès à wp-cron.php et les appels internes associés reviennent identiques, il y a de bonnes chances que la cause soit toujours là.

Enfin, vérifiez la cohérence du site: pages, formulaires, utilisateurs, et plugins. Un cron malveillant s’inscrit souvent dans un ensemble de modifications, même si l’interface reste “quasi normale” au premier regard.

Ce que vous pouvez faire dès maintenant (sans attendre la prochaine panne)

Si vous gérez plusieurs WordPress et que vous voulez réduire votre risque, vous pouvez appliquer une stratégie simple dès aujourd’hui, sans tomber dans le sur-équipement.

La priorité est de rendre le cron moins exploitable et de raccourcir le temps entre détection et correction. Désactivez l’exécution non nécessaire si vous pouvez gérer vos tâches planifiées via serveur. Mettez en place une surveillance des pics de requêtes vers wp-cron.php. Et gardez un historique des changements, en particulier sur les plugins.

Dès que vous voyez une anomalie de rythme (requêtes répétées, CPU qui explose, logs “trop bavards”), traitez cela comme un symptôme, pas comme un hasard. Un cron WordPress malveillant donne rarement des signes subtils pendant longtemps, il finit souvent par se matérialiser dans les logs et la charge.

Si vous voulez un résumé mental: stabiliser d’abord, comprendre ce que WordPress exécute, neutraliser la source qui programme le cron, puis valider par surveillance. Le reste, c’est du nettoyage de détails.

Si vous me décrivez votre contexte (hébergement, accès shell ou non, version de WordPress, et ce que vous voyez dans les logs autour de wp-cron.php), je peux vous proposer un plan de contrôle plus ciblé, adapté à votre configuration, avec les décisions à prendre selon votre niveau de risque et vos contraintes de continuité de service.