Désinfection WordPress : vérifier les tâches planifiées compromises
Quand on parle de désinfection WordPress, on pense souvent au “classique” : plugin malveillant, thème modifié, utilisateur inconnu, fichiers PHP injectés à la va-vite. C’est logique, mais ce n’est pas toute l’histoire. Sur des sites réellement attaqués, il y a un autre levier qui revient, souvent discret au début, puis très coûteux après : les tâches planifiées compromises.
Ces tâches peuvent exécuter du code à intervalles réguliers, déposer de nouvelles charges utiles, réécrire des fichiers, envoyer du trafic vers des pages frauduleuses, ou maintenir une porte dérobée. Tant qu’elles existent et qu’on ne les a pas mises hors service, la désinfection a un goût de “chirurgie sans retirer la cause”.
Je me suis déjà retrouvé sur un WordPress “net” en apparence, avec une base de données propre et des fichiers suspects supprimés, mais qui rechutait dès le lendemain. Le vrai coupable ne se voyait pas dans la liste des plugins installés, ni dans le thème. Il était dans un mécanisme planifié, nourri par les mêmes identifiants que l’attaquant avait obtenus. La réparation a commencé le jour où on a cessé de raisonner en “une fois” et qu’on a basculé sur “contrôler ce qui peut encore s’exécuter”.
Le piège des tâches planifiées : elles survivent à la désinfection
Une compromission WordPress suit souvent une logique d’endurance. L’attaquant veut que la plateforme reste utilisable pour lui, même si vous nettoyez les fichiers visibles. Une tâche planifiée est une forme de persistance, un “pilote automatique” qui rend le site à nouveau vulnérable, ou qui relance l’infection à chaque exécution.
Dans WordPress, les tâches planifiées existent sous plusieurs formes. Certaines sont gérées côté WordPress, via un système d’événements et de Cron interne. D’autres dépendent du serveur, par exemple des tâches planifiées au niveau du système (cron Linux) ou via un planificateur d’hébergement. Selon la configuration, un acteur malveillant peut cibler l’un ou l’autre, parfois les deux.
Ce qui rend le sujet piégeux, c’est que les symptômes peuvent être “diffus”. Vous voyez parfois des URLs ajoutées dans le site, des redirections, des pages qui changent sans que vous compreniez pourquoi. Parfois, c’est plus concret : pics de CPU, requêtes répétées, génération de contenu automatique, modifications de fichiers à répétition. Et parfois, c’est “silencieux”, jusqu’au moment où un moteur de recherche ou un prestataire sécurité signale une infection.
Comprendre où regarder, avant même de toucher au site
Avant de désactiver quoi que ce soit, j’ai pris l’habitude de cartographier les sources possibles d’exécution automatique. Sur WordPress, il faut distinguer :
la planification au niveau WordPress, typiquement via son mécanisme interne, la planification au niveau serveur, qui peut lancer des scripts PHP ou appeler des URL ciblées, les mécanismes “hors calendrier” mais déclenchables, comme des plugins qui réécrivent des événements ou qui modifient le comportement au prochain chargement.
Le point clé est simple : si vous ne cherchez que ce que WordPress liste nativement, vous risquez de rater un planificateur serveur. À l’inverse, si vous ne regardez que le serveur, vous pouvez manquer un Cron interne manipulé.
Dans une désinfection WordPress sérieuse, je recommande de traiter le site comme un système où l’exécution peut venir de plusieurs chemins. Sinon, vous éliminez la partie visible, mais pas la relance.
Les signaux qui doivent vous faire suspecter des tâches planifiées
Il y a des indices qui reviennent très souvent. Aucun n’est une preuve à lui seul, mais l’accumulation de signaux doit vous pousser à investiguer.
Un premier signal, ce sont les comportements “cycliques”. Le site est normal, puis il se déforme à heures fixes ou à intervalle régulier. Par exemple, vous remarquerez que des pages ajoutées apparaissent, puis disparaissent, puis réapparaissent. Ou que des redirections agressives se déclenchent uniquement à certains moments.
Un deuxième signal : des logs applicatifs ou d’accès qui montrent des requêtes répétées vers des endpoints inhabituels. Vous pouvez voir des appels à des scripts, des requêtes “directes” sans navigation humaine, ou des URL qui n’ont aucune raison d’être dans votre usage.
Un troisième signal : des modifications de fichiers qui reviennent, même après nettoyage. Si le système continue à recréer des fichiers, ce n’est pas un coup de chance. C’est une automatisation.
Enfin, il existe des signaux plus “administratifs” : comptes créés puis supprimés, tâches recréées, paramètres changés sans intervention légitime. Même si vous ne voyez pas tout, ces changements répétitifs indiquent une présence persistante.
Vérifier les tâches planifiées côté WordPress (Cron interne)
WordPress utilise un système de planification, souvent appelé WP-Cron. Dans beaucoup d’hébergements, il est déclenché par des visites, car le système dépend de l’activité côté web. Cela n’empêche pas qu’un attaquant puisse l’utiliser. Au contraire, il peut créer des événements qui seront déclenchés à la prochaine requête, ou à une fenêtre où il “s’assure” d’un volume de visites artificielles.
Pour vérifier, il faut regarder l’état des événements planifiés stockés dans la base de données, et vérifier s’ils correspondent à ce que vous utilisez réellement.
Concrètement, sur WordPress, les événements de Cron interne sont stockés en base de données (table dédiée). Une désinfection WordPress efficace consiste à :
Lister les événements planifiés, Repérer ceux qui ne correspondent à aucun usage connu, évaluer qui les a créés (souvent indirectement), Supprimer ou désactiver ce qui est malveillant, Empêcher que ça revienne (en fermant la persistance initiale).
Le point délicat, c’est que WP-Cron n’est pas seulement rempli par vous. Des plugins légitimes créent des événements : sauvegardes, mises à jour, nettoyage de cache, optimisation, statistiques, etc. Si vous supprimez trop agressivement, vous risquez de casser des fonctionnalités ou de déclencher des effets secondaires (par exemple, empêcher la publication planifiée d’un plugin de publication, ou interrompre des tâches de maintenance).
Mon approche consiste à utiliser la logique et le contexte : je compare la liste à l’état actuel du site. Si un événement mentionne un hook ou une fonction qui n’existe pas, ou si le code cible des fichiers que vous n’avez pas installés, c’est un drapeau rouge. Si le hook correspond à un plugin que vous n’utilisez plus, ou à un pattern typique d’attaque (par exemple des actions qui écrivent dans des répertoires inhabituels), je traite cela comme suspect.
Identifier les événements réellement “compromettants”
Une erreur fréquente consiste à vérifier “il y a une tâche”. En réalité, ce n’est pas la présence qui est inquiétante, c’est la nature de ce que la tâche exécute.
Dans les événements WP-Cron, vous trouverez des informations du type hook appelé, paramètres, fréquence, prochain exécution. Les événements malveillants ont souvent des caractéristiques communes :
ils déclenchent des hooks dont le nom n’est pas aligné avec vos plugins connus, ils appellent des fonctions ou méthodes absentes du code actuel, ils passent des paramètres qui font référence à des chemins inhabituels, à des URLs externes, ou à des noms de fichiers “bizarres”, ils apparaissent en grand nombre ou se répètent à des intervalles trop fréquents pour un usage normal.
Le piège, c’est l’interprétation. Un plugin marketing peut utiliser des hooks qui semblent “génériques”. À l’inverse, un attaquant peut copier des noms pour brouiller les pistes, ou utiliser un style de nommage proche d’un plugin légitime. C’est pour cela que je recommande de recouper systématiquement avec le code.
Quand vous suspectez un événement, ouvrez le code qui implémente le hook et voyez ce qu’il fait. Je ne conseille pas de se contenter d’une suppression aveugle. Parfois, la fonction cible ne fait rien de mal, mais l’événement sert seulement à déclencher un processus de mise en cache. Et parfois, au contraire, c’est exactement là que se trouve la charge utile.
Désactivation temporaire : protéger pendant l’enquête
Sur une compromission active, la tentation est forte de tout supprimer tout de suite. J’ai appris à faire une distinction entre deux phases : contenir et enquêter. La désinfection WordPress devient beaucoup plus facile quand vous réduisez le nombre d’exécutions automatiques pendant que vous analysez.
Selon votre capacité d’accès, vous pouvez mettre le site en maintenance, ou limiter le déclenchement du Cron, ou isoler l’exécution. Le but n’est pas de “réparer”, mais de stopper l’accélération du problème.
Une méthode courante consiste à désactiver temporairement le déclenchement du WP-Cron, ou à empêcher son exécution via la configuration. Ensuite, vous analysez la base de données et les événements. Cette approche limite les effets “en boucle” qui peuvent sinon retenter la charge utile plusieurs fois pendant vos manipulations.
Attention, si votre site dépend de tâches critiques pour fonctionner (par exemple, un plugin e-commerce qui synchronise des stocks), une désactivation complète peut causer des écarts visibles. En pratique, la maintenance courte le temps de vérifier les tâches est souvent préférable à laisser le site se réinfecter pendant que vous “regardez”.
Vérifier les tâches planifiées au niveau serveur (cron Linux, planificateur d’hébergement)
WP-Cron est fréquent, mais les attaquants ne s’arrêtent pas là. Un planificateur serveur a l’avantage de ne pas dépendre de la fréquentation du site. Il exécute un script à heure fixe, ce qui peut accélérer la persistance.
Sur certains hébergements, surtout mutualisés ou VPS avec accès à l’interface, vous pouvez avoir accès à la section “Cron Jobs” dans le panneau. Sur d’autres, vous devez passer par SSH et vérifier la crontab. Dans tous les cas, la démarche reste la même : repérer des entrées qui appellent des scripts PHP, des URL internes, ou des commandes système suspectes.
Les tâches malveillantes peuvent appeler directement un fichier dans votre répertoire web, ou déclencher un endpoint WordPress pour réinjecter du code via HTTP. Elles peuvent aussi appeler des commandes qui déplacent ou modifient des fichiers. Si une tâche serveur existe depuis peu, surtout créée après la période d’infection, elle devient un candidat majeur.
Ce point change le sens de la désinfection. Si vous nettoyez WordPress, mais que le serveur lance encore un script à chaque nuit, vous ne ferez que retarder l’échéance.
Quand les tâches ne sont pas “visibles” dans les interfaces
Parfois, vous pensez avoir regardé partout, et pourtant ça continue. Deux raisons reviennent souvent.
La première, c’est que la persistance n’est pas forcément un Cron classique affiché dans votre panneau. L’attaquant peut avoir abusé d’un autre mécanisme : des hooks au démarrage d’un conteneur, une tâche système indirecte, ou un script déclenché par un autre service. La seconde, c’est qu’il peut avoir modifié le code d’un plugin ou d’un thème pour qu’il crée de nouveaux événements Cron à chaque chargement.
Dans cette situation, vous aurez parfois l’impression que les tâches “repartent de zéro” juste après votre suppression. Ce n’est pas magique : c’est parce qu’un morceau de code régénère des événements.
C’est pour cela que, lors de la désinfection WordPress, je préfère aussi analyser ce qui se charge en premier côté WordPress. Un seul fichier modifié à un endroit stratégique peut reprogrammer le futur.
Recouper avec les utilisateurs et les droits : la source d’autorisation
Les tâches planifiées sont un résultat. La cause, c’est souvent un compte compromis ou des identifiants volés. Même si vous supprimez les événements, l’attaquant peut les recréer dès qu’il a une session active, ou qu’il revient avec un nouvel accès.
Je regarde donc :
les comptes récents, les connexions suspectes si les logs existent, les rôles anormaux, et surtout, les traces de modifications de fichiers et de base de données.
Quand vous limitez l’accès pendant que vous nettoyez, vous réduisez la probabilité de régénération. Quand vous ne le faites pas, vous avez une sorte de course contre le temps, et vous finissez par “jouer” contre quelqu’un qui connaît vos actions.
Sur un site déjà infecté, la désinfection WordPress doit aller de pair avec un verrouillage : changement des mots de passe, suppression des comptes douteux, invalidation des sessions, et mise en place de mesures de durcissement si c’est votre rôle.
Une méthode pragmatique pour vérifier sans casser le site
Voici comment j’aborde la vérification des tâches planifiées de façon pragmatique, surtout quand le site doit rester accessible ou quand vous avez peu de temps.
Je commence par un inventaire. Dans WordPress, je récupère la liste des événements planifiés et je cherche ceux qui pointent vers des hooks ou des fichiers inattendus. Ensuite, je compare avec vos plugins actuels et vos besoins. Si l’événement cible un hook qui n’existe dans aucun plugin actif, je le mets de côté pour analyse.
En parallèle, je vérifie le serveur. Même si je suis certain que WP-Cron est manipulé, je préfère vérifier cron côté système, car ça arrive plus souvent qu’on ne le croit. Après tout, un attaquant n’a pas besoin d’une seule porte pour garder l’accès.
Une fois les suspects identifiés, je fais une phase de test. Selon l’environnement, je peux :
désactiver temporairement l’exécution du cron, supprimer le suspect, recharger le site sur un intervalle court, vérifier si les événements reviennent.
Cette approche réduit les risques. Elle permet aussi de repérer les cas où la persistance régénère des événements, ce qui change la cible finale de la désinfection.
Mini-checklist terrain (sans se perdre dans les détails) Vérifier la liste des événements Cron internes et repérer les hooks inattendus Contrôler la base de données pour les entrées qui se répètent avec les mêmes cibles Rechercher des Cron serveur (panneau hébergeur ou crontab) exécutant des scripts ou des URLs Mettre le site en maintenance ou limiter temporairement l’exécution pendant l’enquête Recontrôler après suppression, pour voir si les tâches sont régénérées Nettoyer les tâches compromises : suppression, neutralisation, ou correction ?
Le mot “désinfection” fait penser à une suppression totale. Sur WordPress, je nuancerais. Parfois, la suppression est la bonne décision. D’autres fois, on doit neutraliser sans casser les tâches légitimes.
Si l’événement exécute un hook lié à du code malveillant, la suppression est généralement correcte. Mais il faut s’assurer que le code cible n’est pas lui-même régénéré. Si le fichier malveillant reste présent, il peut réintroduire de nouveaux événements, et vous aurez l’impression que la suppression n’a servi à rien.
Dans d’autres cas, l’attaque n’ajoute pas un hook complètement nouveau, elle détourne un événement existant. Par exemple, un attaquant peut exploiter un hook de maintenance pour exécuter autre chose. Vous devez alors corriger la source du détournement, pas seulement le calendrier.
https://gardewp.fr/ https://gardewp.fr/
C’est la raison pour laquelle je recommande de traiter les tâches planifiées comme une partie d’un ensemble. Les événements compromettants https://gardewp.fr/nettoyage-malware-wordpress/ https://gardewp.fr/nettoyage-malware-wordpress/ peuvent vous conduire vers le fichier modifié ou vers le plugin altéré qui rend l’attaque possible.
Cas fréquent : quand le WP-Cron est “bizarre” mais pas forcément malveillant
Il existe des situations où la liste d’événements semble anormale sans être une attaque directe. Par exemple :
un plugin de cache ou d’optimisation qui planifie des tâches de nettoyage souvent, un site à fort trafic qui déclenche davantage d’événements, des environnements où le cron est reconfiguré pour fonctionner de façon différente.
Le diagnostic ne se fait pas “à la fréquence” uniquement. Un intervalle court peut être légitime si le plugin a été conçu pour le faire. Le vrai critère, c’est la cohérence : hook appelé, paramètres, code cible et présence de modifications récentes.
Dans mon expérience, l’élément le plus discriminant reste l’examen du code exécuté par le hook. Si le hook appelle une fonction qui contient des écritures de fichiers, des téléchargements externes, des instructions de base qui n’ont aucun rapport avec votre plugin légitime, alors vous êtes face à une charge utile.
Exemple concret d’une rechute : la tâche serveur ignorée
Sur un site d’une petite équipe, l’infection était sporadique. Les pages infectées réapparaissaient environ une fois par nuit. Les fichiers PHP “visibles” avaient été nettoyés, et la base de données semblait propre après la première passe.
Le responsable a voulu refaire une deuxième désinfection, mais le problème revenait encore. La vraie cause venait d’une tâche serveur ajoutée dans la nuit précédente. Elle appelait un endpoint interne qui utilisait l’environnement WordPress pour réintroduire une partie du script. Tant que la tâche serveur existait, la désinfection “tombait” à chaque cycle.
Ce genre d’exemple marque : quand on découvre des tâches planifiées compromises côté WordPress, on doit aussi vérifier côté serveur. Sinon, vous passez votre temps à retirer des conséquences, pas la cause.
Durcir après la désinfection : empêcher la réinfection par le calendrier
Une fois les tâches compromises supprimées, la question suivante est simple : comment éviter qu’un nouvel accès recrée le même scénario ?
La désinfection WordPress ne s’arrête pas à “nettoyer”. Si un attaquant a déjà eu un accès administrateur, il a probablement aussi exploré des vecteurs : extensions faibles, mots de passe réutilisés, absence de protection, failles applicatives, configuration trop permissive.
Je traite généralement trois leviers :
fermer les accès (mots de passe forts, suppression des comptes inutiles, limitation des rôles sensibles), réduire l’exploitation (mises à jour, suppression des plugins inutiles, durcissement de la configuration), surveiller les signaux (logs, contrôle des fichiers, alertes sur modifications).
Pour la partie calendrier, un durcissement utile consiste aussi à limiter ce qui peut créer des événements sans validation. Selon votre stack et vos contraintes, vous pouvez filtrer certains comportements, ou mettre en place une surveillance.
Plan d’action court après découverte (quand il faut agir vite) Couper temporairement l’exécution du cron pendant l’analyse Supprimer les événements WP-Cron manifestement liés à des hooks inattendus Désactiver ou supprimer les cron serveur qui déclenchent des scripts suspects Vérifier que les fichiers et plugins responsables ne sont pas toujours présents Recontrôler les tâches après 24 heures pour confirmer l’absence de régénération Pièges et décisions : quoi faire quand vous hésitez
Il y a toujours des zones grises. Par exemple, certains événements s’affichent comme “bizarres” mais aucun fichier correspondant n’est évident. Ou bien vous voyez un cron serveur qui appelle une commande très générale, sans argument explicite.
Dans ces cas, je privilégie une approche d’enquête, pas une destruction. Si vous supprimez au hasard, vous pouvez casser un mécanisme légitime, et vous perdez des repères. Une désinfection WordPress devient alors plus compliquée, car vous ne savez plus si le problème initial est encore là, ou si vous l’avez remplacé par un nouveau bug.
Un bon compromis consiste à neutraliser l’exécution (temporairement), à analyser le code et l’intention, puis à agir. Sur un site critique, cette prudence évite les effets domino.
Autre piège : croire qu’une liste “de tâches” suffit. Les attaques qui se régénèrent ne se laissent pas capturer une seule fois. C’est pour cela que le contrôle après suppression est non négociable, surtout si l’attaque a une persistance solide.
Ce qu’il faut contrôler ensuite, pour être sûr d’avoir “fini”
Une fois les tâches planifiées traitées, je fais une dernière boucle de vérification orientée “preuves de persistance absente”. Je cherche des indices qui signent que rien ne rejoue.
D’abord, je vérifie l’absence de nouveaux événements suspects sur une période courte. Ensuite, je regarde les fichiers fréquemment modifiés et je m’assure que les dates de modification ne repartent pas dans le mauvais sens. Enfin, je surveille les requêtes d’accès sur les périodes où, auparavant, l’infection “se manifestait”.
Le but n’est pas de tout observer indéfiniment, mais de confirmer que la désinfection WordPress a réellement cassé le mécanisme d’exécution automatique. Une persistance se trahit rarement par une seule action, elle se trahit par une répétition qui n’arrive plus.
Conclusion implicite, mais utile : la désinfection commence quand l’exécution automatique s’arrête
Si vous ne deviez retenir qu’une idée, ce serait celle-ci : les tâches planifiées compromises sont souvent le fil qui relie la compromission à ses retours. Vous pouvez nettoyer des fichiers, supprimer des comptes, corriger des thèmes, si vous ne coupez pas la capacité à exécuter à nouveau, la “re-chute” est une question de temps.
La bonne démarche consiste à investiguer à deux niveaux, WordPress et serveur, à recouper les événements avec le code cible, puis à confirmer l’absence de régénération. Ce travail demande du soin, mais il économise des heures de “désinfection” qui ne fait que répéter le même scénario.
Si vous êtes en train d’assainir un site ou de préparer une reprise après incident, dites-moi votre contexte (hébergement mutualisé ou VPS, accès SSH ou non, présence de logs, plugins de sécurité utilisés). Je pourrai vous proposer une stratégie d’investigation plus ciblée, sans supposer d’environnement que vous n’avez pas.