WordPress compromis : analyser les requêtes répétées et nettoyer

Quand un WordPress devient “bizarre”, la première réaction consiste souvent à installer un nouveau plugin de sécurité, relancer un scan et prier. Sur le terrain, ce réflexe fait parfois gagner du temps… mais il ne règle pas la cause. Le signe le plus parlant d’un compromis, ce n’est pas toujours un fichier louche visible en FTP. C’est très souvent un motif, répété encore et encore, dans les journaux serveur, ou une rafale de requêtes identiques qui reviennent comme une horloge.

Je parle ici des requêtes répétées qui se déclenchent sur des URLs précises, des scripts qui tournent à la même fréquence, ou des appels qui “testent” le site. Analyser ce bruit, puis nettoyer de manière structurée, change tout. On passe d’une chasse au symptôme à une reprise de contrôle.

Les requêtes répétées, ce qu’elles révèlent vraiment

Sur un site WordPress, les acteurs malveillants n’agissent pas toujours en continu. Beaucoup fonctionnent par cycles, pour éviter d’attirer l’attention et pour optimiser leur taux de succès. Une requête répétée peut être :

    un balayage de chemins connus (uploads, backups, wp-includes, fichiers PHP dans des répertoires anormaux), une tentative d’exploitation d’une vulnérabilité sur un endpoint standard (par exemple l’accès à xmlrpc.php), un essai d’obtention de jetons via des pages de connexion, un appel à un script implanté pour piloter le site à distance.

Quand ces requêtes reviennent, l’information est double. D’abord, elles indiquent le vecteur probable (le “chemin” visé). Ensuite, elles donnent un tempo (toutes les 30 secondes, toutes les minutes, à heures fixes). Ce tempo sert ensuite pour confirmer qu’on a bien stoppé la chaîne, ou au contraire que quelque chose continue à tourner.

J’ai vu des cas où la suppression d’un fichier webshell en FTP semblait faire disparaître les erreurs… puis les logs continuaient à montrer exactement les mêmes URLs, à la même fréquence. La conclusion était simple : le fichier supprimé n’était pas le cœur du problème, c’était un composant périphérique. Le vrai contrôle résidait ailleurs, souvent dans un cron compromis, une tâche planifiée, ou un plugin modifié.

Où regarder les logs (et ce que vous cherchez)

Avant de toucher au site, je commence par collecter trois sources. Si vous n’avez accès qu’à une seule, prenez les accès HTTP, mais idéalement vous aurez un mix.

    Journaux d’accès web (Apache access.log, Nginx access.log ou logs de virtual host). Journaux d’erreurs (Apache error.log, Nginx error.log). Ils contiennent parfois des erreurs PHP, des permissions refusées, ou des indications de “include” ratés. Journaux WordPress côté application (si vous activez un logging raisonnable). Sans alourdir le site, juste pour repérer les actions internes déclenchées.

Ensuite, je cherche des répétitions. Pas seulement “beaucoup de requêtes”, mais des requêtes identiques ou quasi identiques, avec le même chemin, le même User-Agent ou des paramètres récurrents. Un motif fréquent, c’est une série de tentatives sur wp-login.php, wp-admin/admin-ajax.php, xmlrpc.php, ou sur des scripts ajoutés dans wp-content/ (thèmes et plugins), parfois avec des noms banals.

Un détail utile : regardez aussi le statut HTTP. Un 404 répété sur un même chemin peut indiquer un balayage. Un 200 répété sur une URL anormale peut indiquer un contrôle fonctionnel. Un 301 ou 302 répété peut simplement correspondre à une redirection de campagne, mais c’est souvent un indice de chaîne.

Cas fréquents de requêtes répétées sur WordPress

Les patterns varient selon les campagnes, mais il y a des familles récurrentes. L’objectif n’est pas de “deviner”, c’est de classer rapidement pour réduire le champ de recherche.

Tentatives sur la connexion et les endpoints d’administration

Quand vous voyez une pluie de requêtes vers /wp-login.php avec différents paramètres, ou des posts répétés, il faut distinguer deux choses. D’une part, le brute force. D’autre part, la phase de validation de session ou de récupération d’informations.

Si vous avez aussi des tentatives sur /wp-admin/ et des erreurs associées, c’est souvent l’avant-scène d’une compromission par identifiants ou par injection. La réalité, c’est que beaucoup de compromissions viennent d’un compte compromis. Le site n’est pas forcément “hacké” au sens technique dès le départ. Il est d’abord “utilisé”, puis modifié.

xmlrpc.php et les impacts en cascade

xmlrpc.php a une histoire bien connue. Même avec des mesures de base, il reste une cible. Quand vous voyez des requêtes répétées sur cet endpoint, vous devez le traiter comme un signal fort. Parfois c’est une tentative de pingback, parfois un test d’exploit, parfois un morceau de chaîne utilisé pour pousser des contenus.

Sur un WordPress, l’appel à xmlrpc.php peut aussi déclencher des vérifications ou des effets de sécurité. Donc, quand vous nettoyez, il faut comprendre si ce trafic a déclenché autre chose (créations d’utilisateurs, modifications de contenus, ajout de tâches planifiées).

Requêtes vers des fichiers PHP dans des emplacements inhabituels

Là, c’est plus “mécanique”. Les webshells et autres chargeurs s’installent souvent dans des zones discrètes : uploads, répertoires de thèmes ou de plugins, parfois des chemins créés au hasard.

Quand les logs montrent des accès à une URL du type /wp-content/uploads///.php (ou un chemin similaire), c’est rarement une “mauvaise configuration”. C’est presque toujours une piste à investiguer.

Le piège classique consiste à supprimer le fichier sans regarder comment il a été déposé. Si le vecteur initial (vulnérabilité, plugin vulnérable, identifiant compromis, chaîne via un autre fichier) reste en place, le site se réinfecte. Nettoyer site WordPress infecté ne se résume donc pas à “effacer ce qu’on voit”.

Effets indirects : spam, redirections, contenus publiés

Parfois, les requêtes répétées ne visent pas directement des fichiers de contrôle. Elles alimentent une chaîne. Un bot appelle un script, ce script met en place des redirections, injecte du contenu, ou modifie des pages. Dans ce cas, les logs peuvent montrer une URL de déclenchement, mais l’impact se lit ailleurs, sur la page elle-même ou dans la base.

Je me souviens d’un site où les requêtes répétées étaient relativement peu nombreuses, mais les contenus du front changeaient “avec une régularité” qui correspondait au rythme du bot. Le nettoyage n’a pas été simple, parce que le front était “réécrit” par intermittence, et les fichiers déposés étaient discrets. L’analyse des journaux a permis d’identifier l’heure de la réécriture, puis de bloquer la cause.

Construire une hypothèse avant de nettoyer

Avant de supprimer quoi que ce soit, je note trois éléments simples, parce qu’ils orientent la suite.

Quelles URLs sont les plus répétées ? Quels statuts HTTP reviennent le plus souvent ? Y a-t-il un pic à un moment précis (heure, minute) ou un rythme stable ?

Ces réponses servent à formuler une hypothèse. Exemple : “Trafic vers xmlrpc.php toutes les 5 minutes, puis création d’articles et modification d’options dans la même fenêtre”. On comprend alors que le nettoyage doit inclure la base (options, utilisateurs, cron, meta tables), pas seulement les fichiers.

L’hypothèse permet aussi de décider ce que vous bloquez immédiatement. Sur certains incidents, bloquer temporairement une URL ciblée (au niveau serveur) stoppe le flux pendant que vous analysez. Ça évite que le compromis continue à se renforcer pendant vos manipulations.

Préparation indispensable : sauvegarde et contrôle d’accès

Avant nettoyage, faites une sauvegarde que vous pouvez restaurer. Pas “un export rapide”, pas “j’ai copié le thème”. Je veux dire une sauvegarde exploitable, incluant les fichiers et la base de données, idéalement avec une option de restauration testée.

Ensuite, pendant l’intervention, je change la logique d’accès. Si vous restez sur le même compte admin, si votre mot de passe est suspect, vous risquez d’avoir un compte qui continue à être ciblé. Même si le site est compromis, les attaquants ciblent souvent les accès pour garder la main.

Sur WordPress, c’est aussi l’occasion de revoir deux points : l’authentification et la surface https://gardewp.fr/ des plugins. Je ne vous demande pas d’être agressif. Juste d’être discipliné. Le nettoyage sans verrouillage de l’accès, c’est une porte restée ouverte.

Un plan concret pour analyser et nettoyer (sans casser)

Voici comment je procède quand je dois répondre à un cas “WordPress compromis” avec un symptôme central : requêtes répétées.

Collecte rapide des traces

Je relève une fenêtre temporelle d’observation, souvent 30 à 120 minutes autour du moment où le trafic est actif. Je repère les chemins les plus appelés, et je note les User-Agent dominants si disponibles. Si les logs sont énormes, je filtre sur les chemins suspects.

image

Blocage temporaire de la cause probable

Si un endpoint est visé de façon répétée et clairement anormale pour votre site, je bloque temporairement l’accès au niveau serveur. Le but n’est pas de “résoudre”, c’est de stabiliser. Par exemple, bloquer xmlrpc.php est fréquent quand il n’est pas nécessaire.

Inspection fichiers et permissions

Je compare l’état attendu. Les fichiers de wp-content/plugins et wp-content/themes doivent correspondre à ce que l’installation a déployé. Je cherche les timestamps récents, les tailles inhabituelles, et les fichiers PHP ajoutés dans des emplacements non usuels.

Inspection de la base de données

image

Je vérifie les tables liées aux utilisateurs, aux options, et à la planification. Les compromissions laissent des traces via wp_users, la table des rôles, les options, et parfois wp_cron. Si le nom des tables n’est pas wp_, je m’adapte. L’idée n’est pas la table exacte, c’est le contenu et la cohérence.

Restauration “propre” si nécessaire

Quand plusieurs éléments semblent douteux (fichiers modifiés + base incohérente), je préfère restaurer depuis une sauvegarde saine, puis re-déployer uniquement ce qui est nécessaire. Ce n’est pas toujours “le plus rapide”, mais c’est souvent le plus sûr. Nettoyer site WordPress infecté avec un mélange de suppressions partielles peut laisser un reste fonctionnel.

Ce n’est pas une formule magique. Mais cette séquence évite le piège classique : agir au hasard, puis découvrir que la “boucle” du compromis n’a jamais été rompue.

Signaux concrets qui pointent vers un compromis actif

Les requêtes répétées peuvent venir de robots non malveillants, par exemple des scanners automatisés génériques. Donc je croise toujours avec des signaux internes. Voici ceux qui m’ont le plus souvent servi sur le terrain.

    Création d’utilisateurs inattendus, surtout avec des rôles élevés, ou modifications d’e-mails et de noms d’affichage. Présence de fichiers PHP ajoutés récemment dans uploads ou dans des sous-dossiers qui n’auraient jamais dû contenir du code. Changements d’options applicatives, comme des modifications de paramètres de redirection, de scripts, ou des valeurs stockant une charge utile. Trafic répété sur des URLs qui ne correspondent pas à la logique de votre site (par exemple des scripts jamais utilisés). Changements de contenus sans action éditoriale, ou réponses qui redirigent vers des domaines externes.

Quand vous avez plusieurs signaux ensemble, l’urgence augmente. Quand vous n’avez qu’un seul signal (par exemple beaucoup de 404 sur un chemin non ciblé), vous pouvez être plus prudent et éviter de casser l’environnement.

Le nettoyage : quels éléments traiter, et pourquoi

Plugins et thèmes : “désinstaller” ne suffit pas toujours

Beaucoup d’incidents démarrent via un plugin vulnérable ou mal configuré. Même si vous désinstallez, il peut rester des traces dans la base, des options ou des tâches.

Je conseille donc de traiter les plugins et thèmes avec méthode. Si un plugin a été modifié hors cycle normal (fichiers timestamp récents, différence de taille, code injecté), je ne discute pas longtemps, je le remplace par une version connue et intacte depuis la source légitime.

Attention aux dépendances : certains sites “maison” ont des thèmes et plugins custom. Remplacer à l’aveugle peut casser. La bonne pratique consiste à récupérer les éléments sains depuis une sauvegarde, ou depuis un dépôt fiable.

Fichiers “persistants” : cron et chargeurs cachés

Le compromis qui revient est souvent une boucle. La boucle peut passer par wp-cron, par des tâches serveur, ou par un script qui agit quand une requête arrive. C’est pour cela que l’analyse du rythme compte.

Si les logs montrent une action à minutes fixes, je regarde la planification. Sur WordPress, les déclenchements dépendent souvent du trafic. Donc si vous réduisez temporairement le trafic et que le comportement disparaît, ce n’est pas forcément une victoire, c’est parfois juste un décalage du déclenchement. Le vrai test, c’est de voir si les requêtes répétées continuent une fois les points de contrôle supprimés et remplacés.

Base de données : options, utilisateurs, contenus

La base contient la mémoire du compromis. Les attaquants modifient souvent des options, insèrent du code dans des champs exploités par le thème, ajoutent des scripts dans des zones qui s’affichent dans le front, ou créent des comptes.

Le piège est l’illusion du “fichier propre”. Un webshell supprimé laisse parfois encore l’injection dans une option ou un champ. Le site peut continuer à produire des redirections ou du contenu indésirable, même si la charge utile visible n’est plus là.

Pour nettoyer proprement, je fais une validation croisée : après modification, je vérifie le comportement. Si les redirections et injections cessent, je confirme que le trafic répété se calme. Si le trafic continue, je reviens aux fichiers et aux déclencheurs.

Bloquer sans casser : niveau serveur et compromis

Une mesure efficace consiste à réduire le trafic vers des endpoints agressés. Mais il faut le faire avec mesure. Sur un WordPress, bloquer xmlrpc.php est souvent acceptable si vous n’utilisez pas de fonctions de publication via XML-RPC. Par contre, certains workflows peuvent en dépendre.

C’est le type de décision qui se prend au cas par cas. J’ai déjà bloqué xmlrpc.php et ensuite appris qu’un outil de synchronisation l’utilisait. La correction a demandé un déblocage, puis un filtrage plus fin.

Donc, au lieu de tout fermer, je préfère quand c’est possible : filtrer, limiter le taux, et cibler les chemins les plus répétitifs et clairement anormaux pour votre site.

Après nettoyage : vérifier que le rythme a vraiment disparu

Le dernier point est souvent négligé. Vous pouvez “nettoyer” et croire que c’est fini, alors que la boucle n’a pas été brisée. Pour vérifier, je réutilise la même méthode que pour l’analyse initiale.

Je reconsulte les logs sur une fenêtre comparable. Si les requêtes répétées disparaissent ou chutent drastiquement, c’est bon signe. Si les requêtes restent au même volume, il faut accepter une réalité : soit le trafic est externe et indépendant, soit un composant persiste.

Dans beaucoup de cas, la différence se voit vite. Quand le compromis était déclenché par un endpoint précis, bloquer et supprimer les fichiers associés fait s’éteindre le motif. Si le motif persiste malgré la suppression et le remplacement des éléments suspects, on élargit l’enquête.

Les pièges qui prolongent l’infection

Il y a quelques erreurs récurrentes. Elles ne sont pas dramatiques quand on les comprend à l’avance, mais elles font perdre des heures.

    Remplacer un plugin compromis sans revalider les utilisateurs et options, donc la base continue à porter des paramètres malveillants. Supprimer un fichier visible alors que le vrai déclencheur est dans une tâche planifiée ou un champ de configuration. Réinstaller un plugin ou thème depuis une copie déjà contaminée (si la sauvegarde était elle-même compromise). Changer les mots de passe sans vérifier la compromission du compte, ou en gardant des comptes “anciens” difficiles à distinguer de ceux qui ont été utilisés. Installer une “solution de nettoyage” sans vérifier les logs, ce qui fait passer à côté de la boucle de requêtes.

Quand je vois un site qui a été “nettoyé” deux fois sans effet durable, je me demande presque toujours ce qui a été confirmé dans les logs. Une intervention réussie laisse une trace : le motif s’éteint, et le comportement du front se stabilise.

Prévenir la récidive, sans transformer votre site en bunker

Prévenir, c’est choisir une série de mesures cohérentes, pas empiler des couches au hasard.

Le point central, c’est la réduction de surface et la discipline de mise à jour. Sur WordPress, les compromis passent très souvent par des composants laissés en retard. Ensuite, il y a la sécurité d’accès : mots de passe, suppression des comptes inutiles, limitation des tentatives de connexion, et surveillance.

Sur les requêtes répétées, une approche simple existe : garder un regard régulier sur les motifs, pas seulement sur le volume global. Un volume global élevé peut venir d’un pic marketing. Un motif identique sur des chemins non liés à votre navigation, lui, mérite une réponse.

image

Et si vous devez mettre une règle de blocage, testez. Bloquer un endpoint agressé peut calmer le site immédiatement, mais la règle doit correspondre à votre usage réel.

Quand il faut aller plus loin (et comment décider)

Il y a des cas où le nettoyage “manuel” devient une perte de temps. Si vous avez plusieurs fichiers modifiés à des endroits variés, si la base contient des incohérences multiples, ou si vous n’avez pas de sauvegarde saine proche, la restauration depuis un point fiable devient souvent la voie la plus rationnelle.

Décision pratique : si vous passez plus de temps à chercher “où est la dernière porte” qu’à rétablir une version connue du site, vous êtes probablement en train de lutter contre une boucle complexe. Dans ces situations, une restauration, puis une mise à niveau propre, est souvent plus rapide au final, même si elle demande un effort de re-déploiement.

Et si vous n’êtes pas sûr de l’état de vos sauvegardes, ne partez pas du principe qu’elles étaient saines. C’est précisément à ce moment-là que certains “nettoyages” échouent, parce qu’on remplace du code par du code déjà contaminé.

Un mot sur la recherche du “pourquoi”

Analyser les requêtes répétées répond à la question “comment ça se manifeste”. Mais pour éviter de revivre la scène, il faut comprendre la porte d’entrée. Souvent, c’est un plugin ou thème non mis à jour, parfois un identifiant compromis, plus rarement une configuration serveur fragile. Le “nettoyer site WordPress infecté,” c’est une étape. Le “ne plus revenir” demande d’identifier la cause.

Sur le terrain, je constate que les sites les plus résilients sont ceux qui tiennent un minimum de traçabilité : versions installées, dates de modification, procédures de déploiement, et historique des changements. Quand ces éléments existent, l’analyse des logs devient une enquête rapide, pas un roman policier.

Si vous êtes en pleine intervention, commencez petit : relevez le motif, bloquez temporairement ce qui est visiblement ciblé, puis nettoyez en suivant la logique fichiers et base, pas uniquement fichiers. Les requêtes répétées ne sont pas un ennemi en soi. Ce sont souvent la voix de l’infection, et elle vous dit exactement où chercher.