Nettoyage virus WordPress : analyser l’URL patterns pour repérer le malware

Quand un site WordPress se met à rediriger vers une page bizarre, à charger du JavaScript au mauvais endroit, ou à générer des pages “propres” en apparence mais suspectes côté contenu, on se retrouve très vite avec une question pragmatique: par où le malware se signale, et comment le prouver sans se contenter d’impressions?

Dans les incidents que j’ai traités, l’analyse des URL patterns finit souvent par donner ce que d’autres indices tardent à fournir: des traces exploitables, répétitives, et suffisamment caractéristiques pour orienter le nettoyage virus WordPress, sans faire du travail à l’aveugle. L’idée n’est pas de “deviner” à partir d’un seul incident, mais de repérer des motifs, des récurrences, et des chemins d’exécution qui ne collent pas au fonctionnement normal du site.

Pourquoi les URL disent souvent la vérité

WordPress est une machine à routes. Même quand un attaquant a réussi à déposer un fichier ou à modifier une option, il lui faut presque toujours un moyen de déclencher quelque chose chez le visiteur ou chez le serveur: un endpoint ciblé, un script, une ressource cachée, une redirection, une requête vers admin-ajax.php, un comportement conditionnel sur un paramètre, ou une charge depuis wp-content.

Les URL sont donc la surface visible d’un mécanisme invisible. Elles ne prouvent pas toujours la nature exacte du malware à elles seules, mais elles permettent de répondre à des questions très concrètes:

1) Est-ce que c’est un trafic “humain” (pages recherchées, pages d’archives, navigation normale) ou un trafic automatisé (chemins aléatoires, paramètres répétitifs, probes)? 2) Est-ce que le site génère ou reçoit des requêtes vers des scripts atypiques? 3) Est-ce que certaines combinaisons de paramètres déclenchent systématiquement des réponses anormales?

Quand on nettoie un site, on fait souvent face à un piège classique: on supprime “ce qui ressemble” au malware, puis il revient parce que la vraie entrée n’a pas été fermée. Les patterns d’URL aident précisément à localiser l’entrée, pas seulement la sortie.

Distinguer le scan opportuniste de l’exploitation

Tous les sites WordPress reçoivent des requêtes de reconnaissance. Les robots tentent des endpoints connus, scannent des noms de fichiers, testent des chemins de PHP, parfois sans réussir à écrire quoi que ce soit. Une partie du trafic ressemble donc à “du malware” alors qu’il s’agit juste de bruit.

Le bon réflexe consiste à croiser l’URL pattern avec deux signaux: la nature de la réponse et la répétition. Par exemple, une requête vers /wp-content/uploads/shell.php qui renvoie 404 et ne génère aucune autre activité sur le serveur, ce n’est pas la même histoire qu’un 200 suivi d’un chargement de code, puis de l’appel d’un autre script.

Dans la pratique, sur un site compromis, je cherche un trio récurrent: des chemins atypiques, des paramètres codés, et une chaîne d’URL qui se répond. Le site n’exécute pas seulement une action isolée, il suit un enchaînement.

Patterns d’URL qui reviennent dans les compromissions WordPress

Les signatures varient selon le type de charge, mais certains motifs reviennent avec une régularité dérangeante. L’objectif ici n’est pas de “coller une étiquette” à chaque URL, mais de reconnaître des formes.

Paramètres suspects dans les requêtes

Quand je vois une URL avec des paramètres qui ressemblent à du contenu encodé ou à des commandes, je marque d’abord mentalement “c’est un déclencheur”. Les attaquants utilisent souvent ? avec des noms de paramètres trompeurs, et parfois une charge dans une valeur.

Exemples de comportements à surveiller:

    Paramètres qui ressemblent à du base64 ou à des blocs binaires encodés, parfois très longs pour une page normale. Paramètres dont le nom ne correspond à aucun plugin connu du site, ni à un formulaire classique. Paramètres “proxy” ou “redirect” qui pilotent la destination ou la récupération de contenu distant. Combinaisons qui appellent admin-ajax.php avec des action= improbables.

Sur un site e-commerce, j’ai vu une vague d’accès vers admin-ajax.php?action=... avec un action répétitif, puis des requêtes suivantes vers des URLs de récupération. Même si la réponse finale était affichée comme “banale”, les journaux montraient une séquence d’exécution qui ne correspondait à aucune fonctionnalité installée.

Chemins qui ne devraient pas être touchés

WordPress a des zones assez “prévisibles” côté exposition. Quand un site commence à recevoir des hits sur des chemins qui ne sont pas utilisés par votre thème ou vos plugins, surtout avec des patterns de paramètres identiques, ça mérite une enquête.

Les chemins typiques des tentatives et parfois des injections incluent, selon les campagnes:

    Accès répétés à wp-admin/admin-ajax.php en dehors des usages attendus. Tentatives sur des fichiers dans wp-includes ou wp-content qui ne devraient jamais être listés ou exécutés. Requêtes vers des endpoints avec des extensions inhabituelles ou des segments de chemin qui ressemblent à des noms de fichiers PHP déguisés. URL construites pour déclencher une redirection, par exemple en injectant une URL dans un paramètre.

Le détail important, c’est la fréquence et la corrélation. Une requête isolée vers un chemin ne suffit pas. Une vague cohérente, avec des patterns identiques et une hausse des erreurs serveur, oui.

Redirections et “sorties” étrangères

Un malware WordPress a souvent besoin de livrer quelque chose: un landing page, un téléchargement, une tentative d’hameçonnage, ou un chargement de ressources externes.

Ce qui m’intéresse, ce sont les redirections: quand une URL de votre domaine redirige vers un domaine externe, ce n’est pas forcément interdit, mais c’est rarement normal. Si la redirection survient de façon systématique à partir d’une même sous-URL, vous avez probablement un point de contrôle compromis.

Dans un cas, une redirection se déclenchait sur une page d’archive très précise, uniquement quand un paramètre de type “tri” était présent. L’URL pattern était peu spectaculaire à première vue, mais elle revenait avec des variations contrôlées. Le nettoyage a réussi quand nous avons identifié ce qui pilotait la redirection et corrigé le mécanisme d’entrée.

Ce que vous devez regarder dans les logs (et ce que vous pouvez ignorer)

Les URL patterns ne valent que si vous les reliez aux bons champs. Sur un serveur WordPress, les journaux les plus utiles combinent:

    l’horodatage précis, la méthode HTTP (GET, POST), l’URL complète avec query string, le code de statut renvoyé, le temps de réponse ou la taille (parfois), l’IP source, et parfois le User-Agent, et si possible, les logs applicatifs (par exemple PHP-FPM ou erreurs PHP).

Ce que j’évite, c’est de “sur-interpréter” le User-Agent. Beaucoup de bots imitent des navigateurs, et certains logs sont déjà normalisés par le proxy ou un CDN. Si vous avez accès à la vitesse de réponse, elle aide énormément. Un endpoint qui met plusieurs secondes à répondre à chaque hit patterné est souvent un endpoint qui exécute du code.

Par contre, vous pouvez ignorer une partie du trafic très bruyant si vous constatez que vos endpoints sensibles ne sont jamais atteints. Le tri doit être guidé par la cible, pas par le bruit.

Un mini cadre pour repérer rapidement la logique de l’attaque

Avant de vous plonger dans la chasse au fichier, je conseille de cartographier le motif d’attaque. L’objectif est de passer de “c’est bizarre” à “voilà le déclencheur et voilà la chaîne”.

Voici une approche que j’utilise souvent, avec une exécution pas trop lourde:

    Ouvrir les journaux sur une fenêtre qui couvre l’incident (par exemple une heure autour du pic). Filtrer sur les URLs qui contiennent admin-ajax.php, wp-content, wp-admin, ou des paramètres très longs. Repérer les requêtes qui reviennent avec les mêmes paramètres en boucle. Corréler ces URL avec les codes de statut (200, 301, 302, 500) et avec les erreurs PHP. Vérifier si une même séquence d’URL apparaît côté client et côté serveur (par exemple redirection puis ressource).

L’intérêt de ce cadre, c’est de garder l’enquête orientée vers la compromission, pas vers les suppositions.

Tableau mental: quels patterns sont “signal” et lesquels sont “bruit”

Je ne vais pas vous imposer un modèle unique, mais j’utilise un classement simple, basé sur l’observation:

    Signal fort: patterns répétitifs, paramètres codés, chaîne d’URL qui enchaîne vers une ressource ciblée, codes de statut incohérents avec le contenu attendu, erreurs applicatives corrélées. Bruit: tentatives isolées, erreurs 404 partout, patterns trop “génériques”, aucune corrélation dans le temps.

Le point délicat, c’est quand le malware utilise une stratégie furtive. Parfois, la charge utile n’est déclenchée que pour certains User-Agent, certaines régions, ou certains cookies. Dans ces cas, les URL patterns peuvent sembler “rares”. Vous devez alors vous baser sur la cohérence: même si l’occurrence est faible, la structure de l’URL et sa logique comptent.

Comment analyser l’URL pattern concrètement, sans se noyer

L’analyse efficace, c’est souvent moins d’outils et plus de discipline. Vous cherchez des motifs reproductibles. Un bon exemple: repérer toutes les URL qui contiennent un paramètre de redirection et regarder si le même paramètre est utilisé dans plusieurs requêtes successives.

Si vous travaillez depuis des logs bruts, vous pouvez:

    extraire uniquement l’URL et les query string, regrouper par “forme” (par exemple remplacer la valeur d’un paramètre variable par un placeholder), compter les occurrences pour chaque forme, et observer les codes de statut dominants.

Je me méfie des analyses “100% regex” quand je n’ai pas une vue de ce que le site fait réellement. Une URL pattern “étrange” peut être légitime si votre site utilise un Ressources utiles moteur de recherche interne, un système de filtres, ou un plugin de redirection marketing. Le tri doit donc intégrer la réalité du site.

Cas typiques: ce que j’ai vu sur le terrain

1) Une attaque par admin-ajax.php qui ne ressemble pas à du WordPress

Sur un site vitrine, les requêtes anormales touchaient surtout admin-ajax.php. Les URLs ressemblaient à des appels dynamiques, avec un paramètre action qui n’existait dans aucun plugin ou thème. Ensuite, des requêtes “en aval” apparaissaient vers une ressource qui renvoyait un script ou une charge.

image

image

Le point clé a été de regarder la séquence, pas seulement l’URL initiale. Tant que nous ne regardions qu’un endpoint à la fois, nous faisions des erreurs d’interprétation. Quand nous avons tracé la chaîne d’URL entre les requêtes, l’objectif a été clair: un endpoint déclencheur, une récupération de contenu, puis une exécution côté client.

2) Des redirections sur une URL qui n’a pas “l’air” infectée

Un autre incident concernait une redirection vers un domaine externe. À l’écran, la page semblait “gérer un redirect normal” car elle répondait avec un code 301 ou 302. Mais l’URL source était une page qui ne redirigeait normalement jamais.

image

Le pattern se distinguait dans les query string, un paramètre précis, présent seulement dans les requêtes des attaquants. Sur le plan de l’analyse d’URL, c’était frustrant, car si on ne filtrait pas bien, on confondait avec du trafic marketing. Une fois le filtre ajusté, les occurrences se sont révélées presque parfaitement stables.

3) Du contenu injecté, mais déclenché par des requêtes “banales”

Le malware ne touchait pas toujours des endpoints exotiques. Parfois, il s’accrochait à des pages courantes, comme une page d’article, une archive, ou une pagination. L’URL “banale” devenait un déclencheur quand certaines variables étaient présentes.

Ici, l’URL pattern gagnant n’était pas “un chemin” mais un ensemble de paramètres. C’est pour cela que le nettoyage virus WordPress qui se limite à supprimer des fichiers typiques peut échouer: l’infection est dans la logique d’affichage ou dans un comportement conditionnel.

Du pattern à l’action: fermer les bons points d’entrée pendant le nettoyage

L’analyse d’URL sert à guider le nettoyage. Mais elle ne remplace pas la validation. L’erreur classique est de supprimer un fichier au hasard, puis de constater que la charge reste active, parce que le vrai point d’entrée n’a pas été stoppé.

Une fois que vous avez identifié une URL déclencheuse ou une forme de requête, vous devez ensuite vérifier:

    Est-ce que l’exécution passe par un plugin, un thème, ou un script ajouté? Est-ce qu’un endpoint renvoie une réponse modifiée, par exemple un JavaScript inattendu? Est-ce qu’il y a des inclusions PHP anormales, des appels base64_decode, des eval, des gzinflate, ou des fonctions de lecture distante? Est-ce que des fichiers ont été ajoutés ou modifiés récemment dans wp-content ou wp-includes? Est-ce que le site effectue des connexions sortantes quand il ne devrait pas?

Même si votre article porte sur l’analyse des URL patterns, le lien avec le nettoyage est essentiel. Sans ce pont, vous risquez de faire du tri dans les logs sans fermer l’accès du malware.

Deux checklists utiles, sans lourdeur

Pour ne pas transformer l’analyse en chasse au trésor, je garde deux checklists courtes.

Signaux rapides à noter dans les journaux (quand vous suspectez un malware)

    URLs répétitives sur une courte fenêtre, avec des paramètres stables Accès fréquents à admin-ajax.php ou à des chemins de wp-content non attendus Redirections vers des domaines externes, surtout avec un paramètre source identique Erreurs PHP (généralement 500) corrélées aux mêmes requêtes User-Agent varié, mais pattern d’URL inchangé (souvent le plus révélateur)

Ensuite, comment orienter le nettoyage virus WordPress à partir de vos patterns

    Identifier l’URL déclencheur exacte, puis regarder les requêtes “juste avant” et “juste après” Chercher l’empreinte côté serveur: fichiers modifiés récemment, fonctions dangereuses, inclusions douteuses Valider si un plugin ou un thème corrèle avec l’endpoint observé (même indirectement) Contrôler les redirections, filtres, hooks et AJAX endpoints qui pourraient déclencher la charge Mettre en place un bloc temporaire (au niveau webserver ou WAF) pendant l’investigation, si possible

Ces étapes ne garantissent pas la découverte immédiate, mais elles évitent les faux pas où l’on nettoie “l’effet” plutôt que la “cause”.

Edge cases: quand les patterns trompent

Il existe des situations qui rendent l’analyse moins directe, et où la prudence compte.

Trafic légitime qui imite des motifs

Si votre site utilise un plugin de recherche interne, des filtres d’articles, une bibliothèque de catalogues, ou un système de traduction, il peut générer des query string longues et répétées. Sans corrélation avec les codes de statut, les redirections et les erreurs serveur, vous pourriez conclure à tort.

La parade consiste à comparer le pattern suspect avec vos URLs “normales” produites par votre site. Une pratique utile: enregistrer quelques navigation réelles (depuis votre navigateur ou via un outil interne) et comparer les formes de requêtes.

Malware “conditionnel” basé sur la requête

Certains scripts ne se déclenchent que si un paramètre est présent, si un cookie existe, ou si le chemin correspond exactement à une structure. Résultat: vous ne verrez pas de volume énorme dans les logs. Vous verrez plutôt des requêtes qui ont une structure précise, sans bruit autour.

Dans ce cas, votre meilleure amie, ce sont les formes d’URL, même à faible fréquence. L’analyse par “forme” et par similarité devient plus importante que le volume.

Compromission côté serveur, pas côté application

Parfois, les URL patterns semblent pointer vers WordPress, mais la cause est plus bas niveau: réécritures dans .htaccess, règles de proxy, ou scripts au niveau du serveur. Dans ce contexte, les patterns peuvent être des artefacts, et pas la cause.

C’est pour cela que j’aime toujours regarder les changements récents sur le serveur, pas uniquement dans WordPress. Si vous constatez une logique de redirection au niveau webserver, l’attaque peut ne pas être “dans les pages” mais dans le routage.

Ce que j’inclurais après le nettoyage, pour éviter la récidive

Une fois que le site est nettoyé, l’URL pattern devrait diminuer. Mais pour être crédible sur la durée, il faut garder une discipline de surveillance.

Je vérifie généralement que:

    les endpoints déclencheurs observés ne reviennent plus, ou reviennent uniquement au niveau de reconnaissance bloquée, les redirections suspectes disparaissent, les erreurs PHP associées aux patterns cessent, et les plugins/thèmes ajoutés ou modifiés sont bien identifiés.

Je recommande aussi de revoir les permissions et l’hygiène de déploiement, parce que beaucoup de compromissions viennent d’une faiblesse d’accès (identifiants, plugins non maintenus, mauvaise gestion des clés).

L’objectif n’est pas seulement de nettoyer un épisode, c’est d’empêcher la prochaine histoire d’écrire la même page.

Choisir le bon niveau d’action, sans casser le site

Une question revient souvent: “est-ce que je bloque tout ce qui ressemble au pattern?” La réponse dépend de l’impact potentiel. Bloquer trop agressivement peut couper des fonctions légitimes, par exemple un plugin de cache ou une API interne qui utilise admin-ajax.php.

La stratégie que je privilégie consiste à commencer par une observation précise, puis à bloquer en ciblant la forme la plus fiable de l’URL déclencheur. Ensuite seulement, on ajuste. C’est plus lent au début, mais ça évite les pannes après nettoyage.

Si vous devez retenir une idée

Quand vous faites un nettoyage virus WordPress, les fichiers et les hooks comptent. Mais l’analyse des URL patterns donne souvent la boussole: elle indique quels chemins sont utilisés pour déclencher la charge, et elle permet de relier des symptômes dispersés à une logique cohérente.

Si vous prenez le temps de regarder les requêtes complètes, avec leur séquence et leurs codes de statut, vous passez d’une réaction émotionnelle à une démarche technique. Et c’est exactement ce qui réduit les chances de récidive.