Désinfection WordPress : identifier les appels à des domaines inconnus

Sur WordPress, la partie la plus délicate de la désinfection n’est pas toujours de “supprimer un fichier” ou de “relancer une sauvegarde propre”. La vraie difficulté, c’est de comprendre ce que le site a essayé de faire pendant l’infection, puis de prouver que l’on a aussi fermement coupé le mécanisme derrière le problème. Dans les cas récents que je vois revenir, le fil rouge ressemble souvent à ceci: des appels sortants vers des domaines inconnus, parfois très ponctuels, parfois en boucle, parfois déguisés dans du JavaScript, du PHP discret ou des requêtes dans des fichiers temporaires.

Quand on cible ces domaines, on gagne deux choses. D’abord, on identifie la logique d’attaque, donc on sait quoi bloquer. Ensuite, on obtient des indices concrets pour valider que la désinfection WordPress a été efficace, pas juste “cosmétique”.

Le premier indice: des connexions que WordPress ne “devrait” pas faire

WordPress, même bien configuré, fait des appels sortants dans des cas assez prévisibles. Par exemple: mises à jour automatiques, vérification de plugins, chargement d’avatars quand c’est autorisé, requêtes vers un fournisseur de services (captcha, analytics), ou appels vers une API que vous avez vous-même intégrée.

Un site compromis, lui, peut chercher à contacter des domaines qui n’ont rien à faire là. Les scénarios varient, mais la forme est souvent la même: le site tente d’atteindre une destination externe pour télécharger du code, envoyer des identifiants, récupérer des instructions, ou déclencher une charge utile côté client.

Le piège, c’est que ces appels peuvent ne pas être visibles dans les pages publiques. Ils peuvent démarrer sur certains événements (chargement d’une page précise, apparition d’un utilisateur dans un segment, horaire programmé), ou après une action (publication, ouverture du back-office, appel AJAX). Résultat: vous pouvez avoir l’impression que “rien ne se passe” tant que vous ne mettez pas le nez dans les requêtes réseau et les logs.

Distinguer une anomalie d’un simple bruit applicatif

Avant de déclarer “infection” sur la base d’un seul domaine inconnu, je recommande de vérifier le contexte. Plusieurs éléments peuvent produire des domaines “surprenants” sans que le site soit compromis.

Par exemple, certains plugins récupèrent des ressources distantes. Des thèmes “premium” ou des intégrations marketing appellent des CDN. Des solutions de performance injectent des scripts dont l’origine n’est pas toujours évidente. En plus, certaines configurations masquent les requêtes: proxy applicatif, WAF, scripts chargés dynamiquement.

Ce que vous cherchez n’est pas la présence d’un domaine isolé, c’est un pattern.

Un pattern qui met la puce à l’oreille ressemble souvent à ceci:

    le domaine apparaît uniquement après un changement (mises à jour, ajout de plugin, modification de thème, changement de DNS), l’appel est déclenché par un chemin ou un fichier suspect, la requête envoie des paramètres inattendus (tokens, identifiants encodés, UA custom), et surtout, le domaine est absent de votre liste habituelle d’intégrations.

Si vous avez accès aux logs HTTP côté serveur ou au niveau de votre hébergeur, vous pouvez recouper plus finement. Sinon, vous pouvez au moins observer ce que le navigateur récupère et dans quel ordre.

Où repérer ces appels: navigateur, logs PHP, logs proxy, traces DNS

Je commence presque toujours par une observation “côté client” et une observation “côté serveur”, parce que chacune raconte une partie du film.

Côté navigateur, l’objectif est de voir ce que la page charge réellement. Dans les outils de développement, vous pouvez ouvrir l’onglet réseau et filtrer. Quand un compromis vise des visiteurs, il expose souvent des scripts externes, des chargements d’images à visée de tracking, ou des requêtes AJAX vers un hôte qui ne ressemble pas à votre écosystème.

Côté serveur, vous cherchez plutôt les traces PHP, les erreurs de curl, les appels file getcontents, les requêtes HTTP faites par des fichiers qui ne devraient pas communiquer. Dans beaucoup d’incidents que j’ai traités, les domaines inconnus n’étaient pas “dans la page” au sens strict, ils étaient invoqués par un bout de PHP enterré dans un thème, un plugin, ou parfois dans un fichier qui n’a rien à voir avec la logique principale.

Si votre hébergeur expose des logs de type accès sortant ou logs applicatifs, c’est encore mieux. Sinon, il reste la piste DNS, surtout si vous voyez des résolutions répétées vers un même hôte inconnu.

L’important est de relier chaque domaine à un déclencheur. Sans cela, vous risquez de bloquer un domaine qui n’est qu’un effet secondaire, pas la cause.

image

Comment l’attaque se présente souvent dans WordPress

Les campagnes exploitent WordPress parce que l’écosystème est vivant. Pourtant, le cœur des mécanismes reste assez constant: persistance, déclenchement, exfiltration ou charge utile.

Une observation pratique: les appels à des domaines inconnus s’insèrent fréquemment dans des endroits qui peuvent passer pour “légitimes” en surface.

Par exemple:

    des fichiers modifiés dans un thème, parfois au niveau de templates rarement consultés, des plugins modifiés, mais seulement sur certains hooks, des fichiers d’apparence anodine, avec une petite fonction qui fait un curl ou charge un script depuis l’extérieur.

L’infection peut aussi utiliser un système d’obfuscation. Des chaînes encodées, des fragments concaténés, un base64 qui n’explique rien tant qu’on ne décode pas. Dans ce cas, l’outil le plus utile n’est pas uniquement l’antivirus, c’est votre capacité à lire et comprendre ce qui est exécuté, au moment où l’appel externe se produit.

La méthode pragmatique pour identifier les domaines vraiment responsables

Pour éviter la chasse aux fantômes, je travaille avec une logique simple: “Qu’est-ce qui appelle dehors, quand, et pourquoi”. Le but est d’identifier les domaines inconnus liés à l’infection, puis de les invalider à la source.

image

Voici ma démarche, en restant réaliste sur ce que vous pouvez faire selon votre niveau d’accès:

1) Repérez le moment où le comportement commence. Quand les pages commencent à charger un script externe, quand les erreurs apparaissent, quand le trafic change. Si vous avez des dates, prenez-les. Les timestamps sont souvent plus utiles que des hypothèses.

2) Isoliez les requêtes sortantes. Depuis le navigateur, voyez les scripts, requêtes fetch, XHR et images. Depuis le serveur, cherchez les appels HTTP sortants ou l’exécution de fonctions de lecture de contenu.

3) Reliez chaque domaine à un fichier ou un chemin d’exécution. Quand vous trouvez un domaine inconnu dans un script chargé par la page, revenez au point de départ. Quel fichier génère ce script? Quel hook l’injecte? Dans quel template? Si c’est côté PHP, quel fichier appelle la ressource?

4) Confirmez l’existence du “circuit” complet. Un compromis sérieux ne se limite pas à charger une ressource. Il y a souvent une seconde étape, par exemple un téléchargement ou un traitement qui déclenche une suite d’actions. Cherchez l’enchaînement, pas seulement la première requête.

5) Documentez ce que vous observez. Un incident de désinfection WordPress se résout mieux quand vous avez une trace claire: domaine, URL exacte, fréquence, déclencheur, fichier responsable, et impact perçu (redirection, injection, erreur, consommation CPU).

Pour garder ça concret, je vous mets un mini cadre d’observation. C’est court volontairement, car le vrai travail se fait dans le recoupement:

    domaines qui n’apparaissent pas dans vos intégrations habituelles et qui déclenchent des charges utiles (scripts, endpoints d’API, redirections), présence répétée dans les outils réseau, en particulier sur des pages précises, exécution liée à un fichier modifié, souvent avec du code obfusqué ou des fonctions d’appel HTTP, requêtes qui incluent des paramètres anormaux (identifiants, variables encodées, formats difficiles à justifier), changement de comportement après un événement (déploiement, ajout de plugin, mise à jour).

Bloquer sans casser: les risques d’une “liste noire” trop agressive

Une fois que vous avez identifié des domaines inconnus, l’instinct est de les bloquer à tout prix. C’est souvent nécessaire. Mais il y a un piège classique: vous pouvez bloquer un domaine qui n’est pas la source du problème, mais un service légitime utilisé par un plugin.

La bonne question n’est pas seulement “ce domaine est-il inconnu?”, c’est “ce domaine est-il appelé par un composant suspect?”. Si vous bloquez sans comprendre, vous risquez:

    de casser des fonctionnalités que l’utilisateur utilise, de rendre l’investigation plus difficile (car certaines traces disparaissent), ou de laisser un morceau de l’attaque intact ailleurs.

Dans la pratique, je préfère une approche progressive: d’abord isoler le composant responsable, ensuite appliquer un blocage ciblé et vérifier que le comportement disparaît. Si vous ne pouvez pas isoler à 100 pour cent, vous pouvez au moins bloquer temporairement avec une fenêtre de test, puis valider que le site fonctionne.

Quand le domaine inconnu n’est pas appelé directement par la page

Un détail qui surprend beaucoup de gens lors d’une désinfection WordPress: le domaine inconnu n’est parfois pas visible dans le HTML ou dans les scripts chargés. Il peut être appelé côté serveur, pendant le rendu, ou au moment d’une tâche.

Exemple concret de pattern que j’ai déjà rencontré: une page paraît normale, mais dans les logs serveur, on voit des appels sortants qui échouent, puis qui réussissent, et qui renvoient de petits payloads. Le code n’est pas chargé au front, il sert à autre chose, par exemple à mettre à jour un paramètre, créer un fichier cache, ou préparer une redirection conditionnelle.

Autre variante: l’appel se produit uniquement pour des requêtes avec un motif particulier (un user agent donné, un pays, ou une fréquence). Dans ce cas, en testant “vite fait” depuis votre navigateur habituel, vous ne verrez rien.

C’est pour cela que les journaux, même partiels, sont précieux. Ils montrent un rythme, une direction, et un volume. Une requête unique peut être un plugin rare. Des dizaines d’appels dans une fenêtre courte, vers un hôte inconnu, deviennent beaucoup plus suspectes.

Construire une preuve: du domaine au code

Une fois le domaine identifié, le travail devient plus “chirurgical”. Vous cherchez la trace dans les fichiers PHP ou les scripts.

Concrètement, vous pouvez chercher des occurrences du domaine inconnu dans le code source, mais attention, à cause de l’obfuscation, le domaine peut être reconstruit dynamiquement. On GardeWP contrôle malware ne retrouve pas toujours la chaîne littérale.

Dans ces cas, je m’appuie sur une méthode plus fiable:

    identifier la fonction responsable de l’appel sortant (curl, file getcontents, wp remoteget, wp remotepost), tracer l’endroit où cette fonction est invoquée, remonter le hook ou le chemin d’exécution.

Une fois que vous avez le fichier incriminé, vous comparez à une version propre. Sans exagérer: une simple différence de quelques lignes suffit parfois à prouver la compromission. Et si vous avez un dépôt Git ou des captures d’origines, la comparaison devient très rapide.

Une autre preuve utile est l’alignement de timestamp. Si un fichier a été modifié juste au moment où les appels à des domaines inconnus ont commencé, votre suspicion devient beaucoup plus solide.

Restaurer une base saine: ce qui marche, ce qui ne marche pas

Beaucoup de désinfections échouent parce que l’on restaure des parties sans reconstruire le mécanisme. Vous pouvez supprimer un fichier malicieux visible, et l’attaque continue via une autre persistance.

Sur WordPress, les persistance fréquentes incluent:

    fichiers injectés dans le thème ou un plugin, code mal placé dans des fichiers d’apparence “technique”, modifications de base de données (options, tables liées à des plugins), utilisateurs ou rôles créés discrètement.

Les appels à des domaines inconnus sont souvent l’indicateur le plus stable, mais pas le seul. Une vraie résolution consiste à faire correspondre l’observation (les appels) et la correction (la suppression de la cause).

Dans l’atelier, je traite généralement l’incident en trois couches: nettoyage applicatif, validation du code, puis verrouillage des vecteurs d’entrée.

Vous pouvez, par exemple, réinstaller le cœur WordPress depuis une source officielle, revalider vos thèmes et plugins (et pas seulement “mettre à jour”), puis contrôler la base de données si vous avez vu des modifications d’options suspectes.

Deux décisions à prendre vite: investigation active ou “freeze” total

Quand un site est compromis, il y a un choix de tempo.

Si vous estimez que la charge utile continue à s’exécuter, une désinfection trop lente peut aggraver l’impact, surtout si des visiteurs sont touchés ou si des données sont exfiltrées. Dans ce cas, on gagne à “geler” temporairement le site (mode maintenance, limitation d’accès, blocage sortant), pour couper la boucle.

Si, au contraire, vous avez un site peu exposé et que les appels semblent limités, vous pouvez garder le site en ligne le temps de collecter suffisamment d’indices pour identifier précisément le domaine et le fichier responsable.

Dans les deux cas, l’objectif est identique: mieux comprendre ce qui déclenche l’appel, puis supprimer la cause.

Checklist d’action rapide pour couper l’appel aux domaines inconnus

Quand vous êtes en situation de réponse à incident, je conseille une approche courte, orientée preuves. Voici une liste de cinq actions maximum, et je l’utilise comme garde-fou quand la pression monte:

    Dresser la liste des domaines inconnus observés, avec au moins une URL complète et un horodatage (ou une fréquence). Identifier le déclencheur (page, action admin, chemin, condition) et associer le domaine à une exécution côté serveur ou navigateur. Désactiver temporairement les plugins et thèmes récemment modifiés, ou basculer sur un thème par défaut, pour isoler l’injecteur. Mettre en place un blocage temporaire sortant ciblé (au niveau serveur ou pare-feu applicatif) sur les domaines incriminés, le temps de valider la correction. Après correction, recontrôler les logs et les requêtes réseau pour confirmer la disparition du pattern.

Si vous respectez cette logique, vous réduisez les chances de faire un “nettoyage partiel” qui ne supprime pas le mécanisme d’appel.

image

Cas particuliers: domaines inconnus qui apparaissent après correction

Parfois, après avoir nettoyé un fichier et réinstallé des composants, vous voyez encore quelques appels vers des domaines “bizarres”. Ce n’est pas toujours signe que l’infection persiste.

Les causes fréquentes que j’ai vues:

    un cache ou un plugin de performance conserve des scripts injectés jusqu’à purge complète, des utilisateurs ont encore des sessions ou des bundles dans un contexte spécifique (moins fréquent, mais possible), des appels étaient déclenchés uniquement par une tâche planifiée, et la tâche n’a pas été supprimée, ou le domaine inconnu est un “effet secondaire” d’un service légitime appelé via un redirect.

Le bon réflexe ici est de comparer le pattern. Si la fréquence chute drastiquement et que le déclencheur suspect disparaît, vous êtes probablement sur la bonne voie. Si les appels persistent exactement avec la même signature et la même cadence, vous devez continuer l’investigation jusqu’au fichier ou à la règle d’exécution.

Pourquoi l’identification des domaines change le résultat final

La désinfection WordPress devient beaucoup plus robuste quand on traite l’appel sortant comme un symptôme “verrouillable”. Un domaine inconnu est plus qu’un détail, c’est une empreinte.

Elle vous permet:

    de vérifier que la charge utile a cessé, de retrouver un chemin d’exécution, et de juger l’efficacité d’un nettoyage sans dépendre uniquement de ce que vous “voyez” dans une page.

Et surtout, vous évitez la fausse satisfaction. Une page peut avoir l’air propre alors que le serveur continue de contacter un domaine malicieux en arrière-plan. Quand vous partez de l’observation réseau, vous réduisez fortement cette zone aveugle.

Durcir après nettoyage: empêcher le retour

Une fois l’incident coupé, la question suivante revient toujours: comment éviter que ça se reproduise exactement de la même manière. Les appels à des domaines inconnus disparaissent, mais le vecteur d’entrée peut rester.

Sans entrer dans des procédures “magiques”, je recommande une logique de fond:

    vérifier les rôles et utilisateurs, supprimer ceux que vous ne reconnaissez pas, révoquer les sessions et les tokens si votre hébergeur le permet, revoir les identifiants, surtout si un accès a été utilisé avant l’incident, limiter l’installation de plugins et thèmes, ou au minimum exiger un suivi, et surveiller régulièrement les modifications de fichiers.

Si vous gérez plusieurs sites, vous apprenez aussi où les injections commencent. Sur beaucoup d’installations, ce sont les plugins “secondaires” ou rarement mis à jour qui offrent le plus de surface d’attaque.

Un dernier réflexe utile: penser comme l’attaquant, sans l’adorer

Identifier des appels à des domaines inconnus, c’est aussi comprendre le tempo. Une attaque qui contacte un domaine toutes les X minutes a probablement une intention de synchronisation. Une attaque qui n’appelle jamais pendant votre test, mais bien quand un autre profil visite une page particulière, vise le contournement de la détection.

Ce qui m’aide, c’est d’observer non seulement “ce qui est chargé”, mais “dans quelles conditions”.

En pratique, quand vous reliez le domaine au déclencheur, vous obtenez souvent un levier immédiat. Vous coupez le bon hook, vous corrigez le bon fichier, vous restaurez le bon comportement. La désinfection WordPress cesse d’être une série de gestes isolés, et devient une résolution structurée.

Si vous voulez, décrivez-moi le contexte de votre cas (hébergeur, visibilité des logs, ce que vous voyez dans le navigateur, présence d’un plugin récemment ajouté, et si les appels sortants sont côté serveur ou côté client). Je pourrai vous proposer une grille de diagnostic plus précise pour identifier le domaine incriminé et remonter au code responsable.