WordPress infecté : repérer les obfuscations et variables masquées
Quand on découvre qu’un WordPress est compromis, la première réaction est souvent de vouloir “nettoyer” vite. On désinstalle un thème, on change un mot de passe, on relance une sauvegarde. Et parfois, ça marche. D’autres fois, le site revient à l’identique le lendemain, ou pire, il continue d’émettre des requêtes silencieuses pendant que tout le monde croit l’incident terminé.
Ce qui piège le plus, ce sont rarement les malwares visibles. Ce sont les obfuscations, les bouts de code déguisés en apparence anodine, et les variables masquées qui rendent l’origine du problème difficile à cerner. Dans les cas sérieux, l’infection ne se contente pas de “casser” le site. Elle prépare une suite, elle attend un trigger, ou elle appelle un second étage de payload.
Ce texte n’est pas un manuel parfait pour tout le monde, mais une méthode de terrain pour repérer ce qui compte: où regarder, comment reconnaître les signaux d’obfuscation, et comment comprendre les variables masquées avant de relancer une production fragile.
Le scénario classique, et pourquoi il dure
Un site WordPress infecté ne “s’infecte” pas toujours avec une seule action. Le plus souvent, il y a une compromission initiale, puis une persistance, puis un déploiement progressif.
Sur le terrain, on voit fréquemment cette progression: une modification discrète dans un fichier PHP qui n’a l’air de rien, puis des appels réseau qui ne ressemblent pas à du trafic normal, puis une modification côté base de données (options, utilisateurs, contenu injecté). Si l’obfuscation est bien faite, l’injection ne s’exécute que sous certaines conditions: un certain user agent, une plage d’IP, une URL précise, ou simplement le moment où le cache expire.
Ce comportement explique pourquoi les actions “rapides” peuvent échouer. Si vous supprimez le fichier malveillant mais que la persistance est ailleurs, il réapparaît. Si vous remplacez un thème ou un plugin, mais que l’infection est dans un fichier hors de votre radar, le problème revient. Et si vous ne comprenez pas les variables masquées, vous supprimez le symptôme au lieu de la mécanique.
Ce que signifie “obfuscation” dans un WordPress compromis
Dans ce contexte, l’obfuscation n’est pas un simple encodage pour gagner de la place. C’est une façon de rendre le code moins lisible pour vous, tout en restant exécutable pour la machine.
Concrètement, l’obfuscation peut ressembler à:
des chaînes construites à partir de morceaux (concatenation) plutôt que stockées en clair; des fonctions qui transforment, base64, rot, xor, gzinflate, strrev, ou des versions “sur mesure”; des variables nommées de manière peu parlante, parfois construites elles aussi; des conditions qui empêchent l’exécution lors d’un simple test en local.
Le signe le plus fréquent, c’est la présence d’un “code de déchiffrement” ou d’une routine de reconstruction. Souvent, il ne fait pas grand-chose à la lecture, puis soudain, il exécute quelque chose. Le point d’attention devient alors la ligne qui mélange une chaîne et un appel à une fonction d’exécution.
Dans WordPress, ces éléments se nichent très souvent dans des fichiers qui ne devraient pas contenir de logique complexe, par exemple:
des fichiers “utilitaires” dont le rôle réel est minime; des fichiers “autoload” ou des includes de thèmes; des fichiers dans des dossiers qui ne sont pas typiquement manipulés par votre équipe; des fragments PHP ajoutés au hasard en bas de fichier. Les emplacements où l’on trouve le plus souvent des obfuscations
Il n’y a pas une liste universelle, mais j’ai tendance à suivre une logique: commencer par ce qui a le plus de chances d’être exécuté, ensuite remonter vers la persistance.
Sur un WordPress, les points d’exécution fréquents sont liés à la structure PHP: chargement de thèmes, plugins, includes, hook système, et code dans les fichiers globaux.
Les obfuscations que j’ai vues sur le terrain surgissent souvent dans:
les fichiers placés dans le thème actif, surtout functions.php et des includes ajoutés au hasard; des plugins installés récemment ou jamais utilisés; des fichiers PHP dans uploads si quelqu’un a réussi à forcer l’exécution côté serveur (et parfois sans que l’URL soit évidente); des fichiers racine ou quasi racine qui ne correspondent pas aux fichiers WordPress standards; des scripts minifiés ou “habillés” qui servent à reconstruire un code plus tôt.
Le détail important: même si vous remplacez le thème ou le plugin, vérifiez aussi les fichiers qui sont inclus par le CMS. Un fichier malveillant peut être “invisible” parce qu’il n’est pas appelé directement, mais parce qu’un include le charge.
Reconnaître les variables masquées: le vrai piège
Les variables masquées sont souvent ce qui rend l’attaque difficile à analyser. Le code obfusqué peut reconstruire des paramètres à partir de fragments, puis les passer dans un appel.
Il faut distinguer deux niveaux.
1) Variables masquées côté PHP (noms, valeurs, reconstruction)
Vous verrez parfois des variables avec des noms bizarres, ou des valeurs non évidentes:
des variables qui ne contiennent pas la chaîne en clair; des variables construites par substr, pack, unpack, chr, ord; des variables qui servent à composer une URL ou une commande.
L’important n’est pas le nom. C’est la manière dont les valeurs sont obtenues et où elles sont utilisées.
2) Variables masquées via la logique (conditions, triggers, timing)
Même avec du code lisible, l’exécution peut être conditionnée:
comparaison d’une valeur GET ou POST; activation selon un cookie; vérification du referer ou du user agent; exécution uniquement si une fonction réseau renvoie une certaine forme de réponse.
Cette couche explique pourquoi les tests peuvent passer. Vous ouvrez une page, rien ne se passe. Puis un crawler différent arrive, https://gardewp.fr/ https://gardewp.fr/ ou le cache expire, et le code s’exécute.
Dans beaucoup d’infections, les variables masquées jouent ce rôle: elles stockent une “configuration” qui décide quand et comment agir.
Signaux concrets à observer dans le code
À défaut de pouvoir lire chaque ligne d’un obfusqué, vous pouvez repérer des motifs de comportement. Voici des signaux utiles, sans supposer une signature unique.
Quand j’analyse un WordPress suspect, je cherche surtout:
des appels à des fonctions d’exécution (ou équivalents) qui ne devraient pas être là dans un contexte “thème” ou “plugin”; des routines de transformation de chaînes répétées, surtout si elles alimentent ensuite une exécution; la construction d’URL ou de chemins à partir de fragments; des variables de type “configuration” qui semblent être lues dans un flux obfusqué; des eval, assert, gzinflate, base64_decode ou des enchaînements inhabituels.
Le point délicat: WordPress lui-même peut contenir des mécanismes internes qui utilisent parfois des fonctions de transformation, mais un plugin ou un thème légitime les utilisera de manière cohérente et surtout, dans un contexte clair.
L’obfuscation malveillante, elle, se caractérise souvent par une absence d’intention fonctionnelle. On sent un code qui n’appartient pas à la logique métier. Il sert à reconstruire puis exécuter.
Une première lecture efficace, sans se faire piéger
Face à un fichier obfusqué, j’ai appris à éviter le piège “je lis tout le fichier ligne par ligne”. Dans beaucoup d’incidents, c’est du temps perdu, parce que la logique principale tient dans quelques fragments.
Voici une méthode pragmatique:
d’abord, repérez la fin d’exécution: là où l’output est envoyé, où une fonction réseau est appelée, ou où un traitement exécute. ensuite, remontez vers la construction des paramètres utilisés juste avant l’exécution. enfin, cherchez les sources des variables: où elles sont initialisées, comment elles sont modifiées, si elles viennent de $_GET, $_POST, de $_COOKIE, ou de la base de données via des options.
Cette logique vous aide à retrouver la “chaîne d’intention” même si le texte est illisible. Une infection bien faite masque les valeurs, mais elle ne peut pas effacer la structure globale: elle doit finir par agir quelque part.
Où regarder dans le WordPress lui-même: fichiers et base de données
On parle souvent des fichiers, mais la persistance passe aussi par la base. Une obfuscation peut être stockée côté PHP dans des fichiers, ou déclenchée via une option ou un champ modifié.
Je garde deux rails en parallèle:
le rail fichiers: thèmes, plugins, includes, et dossiers “annexes” susceptibles d’être inclus; le rail base: options, utilisateurs, et contenus (notamment si le site injecte des scripts dans des pages).
Si votre incident a été provoqué par une compromission via un plugin vulnérable, il est fréquent que l’attaquant ait aussi laissé des traces “propres” dans la base pour piloter le déploiement. Parfois, l’obfuscation n’est pas dans le fichier, elle est dans une valeur, puis reconstruite au moment du rendu.
Ce décalage est critique. Si vous ne regardez que les fichiers, vous pouvez avoir l’impression que vous avez tout supprimé, puis le site réinjecte le code à chaque génération de page.
Mettre l’analyse au service d’une réponse, pas d’un diagnostic théorique
Une erreur fréquente, c’est de vouloir “prouver” l’infection avant de prendre des mesures. En incident, la priorité est de réduire le risque et de conserver l’environnement d’analyse.
Avant de toucher à tout, j’essaie de documenter ce que je vois:
quels endpoints ont changé en dernier, quelles pages injectent quelque chose, à quel moment (tout de suite, après un certain temps, seulement sur une partie des visiteurs), si le code exécute une requête externe.
Ensuite seulement, je me concentre sur les obfuscations et les variables masquées pour comprendre le mécanisme.
Si vous êtes dans un environnement de production, la prudence consiste à ne pas “casser” votre seule copie de preuve. Déplacez, isolez, sauvegardez, puis jouez l’analyse. Un nettoyage trop agressif peut détruire la chaîne utile.
Indicateurs d’exécution externe et de mécanismes de déploiement
Les obfuscations ont rarement un objectif qui reste purement local. L’attaquant doit récupérer des instructions, déposer des charges utiles, exfiltrer, ou au minimum vérifier le succès.
Dans le code, cherchez donc les indices de communication. Cela peut être:
des constructions d’URL à partir de fragments, des appels réseau dissimulés dans une fonction interne, des paramètres qui ressemblent à des identifiants de campagne (guid, tokens, sous-domaines).
En pratique, si votre serveur a des logs réseau ou si vous pouvez comparer le comportement avant et après, vous verrez parfois des requêtes inhabituelles. Le code obfusqué vous dira vers où, mais les logs vous diront quand et à quelle fréquence.
Le “quand” est essentiel. Si le déclenchement dépend d’un cookie ou d’un paramètre, vous aurez du mal à reproduire le comportement en test manuel. Les logs, eux, ne sont pas trompés par votre navigateur.
Checklist terrain pour repérer une obfuscation réellement suspecte
Voici les cinq signaux qui, dans mon expérience, méritent une attention immédiate. Ce n’est pas une preuve à eux seuls, mais ce sont des déclencheurs d’analyse approfondie.
Un fichier hors logique métier contient des routines de transformation de chaînes, puis une exécution ou une inclusion dynamique. Des chaînes et des URLs sont construites via des morceaux, sans valeur en clair cohérente. Le code utilise des variables issues directement de $_GET, $_POST ou $_COOKIE pour décider de la logique d’exécution. Il y a un comportement conditionnel qui semble dépendre de l’agent navigateur ou du contexte de requête. Le site fait des appels externes depuis un endroit inattendu (thème, options, fichier “simple” qui ne devrait pas toucher au réseau).
Dès que deux ou trois de ces points sont réunis, je considère qu’on est face à une obfuscation active, pas juste à du code chargé ou minifié par hasard.
Variables masquées dans les hooks WordPress: le cas le plus fréquent
Une autre zone qui crée de la confusion, ce sont https://gardewp.fr/nettoyage-malware-wordpress/ https://gardewp.fr/nettoyage-malware-wordpress/ les hooks. WordPress est un système d’événements, donc un code malveillant peut se greffer sans être “appelé” directement.
Les variables masquées peuvent alors servir à garder le hook “silencieux” au début, puis à activer un comportement à un moment précis, par exemple lors d’un filtre sur le rendu, ou lors d’un événement d’admin.
Quand vous analysez, gardez à l’esprit que le fichier infecté peut sembler inoffensif si vous le lisez seul. Il devient dangereux quand il est branché à un hook spécifique. Dans ces cas, la bonne approche consiste à:
repérer l’enregistrement du hook, suivre la fonction callback, et vérifier la construction des paramètres à l’intérieur.
Beaucoup d’obfuscations sont “courtes” parce que la logique principale est reconstruite et exécutée ailleurs. Le hook est le point de raccord. Si vous le repérez, vous remontez ensuite vers la source.
Pourquoi remplacer des fichiers ne suffit pas toujours
Remplacer un thème ou un plugin est souvent le premier geste. Il reste indispensable, mais ce n’est pas une stratégie complète quand il y a des variables masquées.
Raisons fréquentes:
l’attaque a modifié un fichier qui ne fait pas partie du thème ou du plugin remplacé, la persistance est dans la base de données, l’injection se fait à la volée au rendu, donc le “même” fichier redevient malveillant après régénération, l’attaquant a compromis un fichier “d’include” ou un mécanisme de chargement.
Je me souviens d’un cas où le propriétaire avait remplacé le plugin supposé vulnérable. Le site semblait propre pendant une heure. Puis un crawler a déclenché l’injection, et des liens frauduleux sont apparus. En remontant, on a trouvé une option base de données contenant un fragment obfusqué qui reconstruisait l’injection au moment du rendu.
Le plugin avait été innocenté par remplacement, mais le pilotage venait de la base.
Deux techniques pour démêler une obfuscation sans casser tout
Il existe plusieurs méthodes. Je reste volontairement prudent, parce qu’exécuter un code malveillant “pour voir ce qu’il fait” peut aggraver la situation ou exfiltrer des données.
Deux approches utiles:
1) La désobfuscation “sans exécution”
Quand le code utilise des encodages standard comme base64_decode, il est parfois possible de reconstituer des chaînes sans lancer de fonctions dangereuses. Vous observez alors ce que l’attaquant construit, vous cherchez où cela mène.
Le but n’est pas d’exécuter, c’est de comprendre la trajectoire. Si vous voyez une URL reconstruite et qu’elle pointe vers un domaine malveillant, vous avez déjà un angle d’éradication.
2) L’analyse orientée flux
Vous identifiez les points d’entrée (hook, include, condition de trigger), puis vous suivez comment les variables masquées prennent forme jusqu’au moment où elles servent à une action. La lecture devient moins “poétique” et plus “mécanique”.
Dans les infections, l’attaque ressemble souvent à un automate: des pièces reconstruites, puis une action finale. En suivant ce flux, vous découvrez rapidement où se trouve l’ordonnateur, même si le code est laid.
Le point de vue “défense” : empêcher le retour
Une fois que vous avez identifié les obfuscations et les variables masquées, il faut empêcher la récidive. Le nettoyage seul n’est pas une fin, c’est une étape.
Sur WordPress, la récidive vient souvent de trois sources:
une vulnérabilité non corrigée dans un plugin ou un thème, des identifiants ou une session compromis, des droits trop larges sur des fichiers, ou des configurations qui permettent l’exécution là où elle ne devrait pas exister.
Le plus dur est de corriger durablement sans pénaliser l’exploitation légitime du site. Par exemple, durcir le serveur pour empêcher l’exécution dans uploads peut être vital, mais il faut vérifier si votre stack s’appuie sur du traitement de médias qui utilise ces chemins.
Dans un incident, j’aime bien procéder par “réduction de surface” avant “durcissement”. D’abord isoler et supprimer les points infectés, ensuite appliquer les protections compatibles avec votre architecture.
Un mini scénario d’enquête (typique) pour relier tout ensemble
Imaginons un site qui affiche soudainement des scripts injectés dans le HTML, sans que le thème actif ait changé. Vous regardez les fichiers récents, vous voyez un ajout minime dans un fichier PHP du thème. Le code est court, mais il appelle une fonction de décodage et reconstruit une chaîne. Cette chaîne ressemble à une URL, mais elle n’est pas en clair.
En lisant le code, vous repérez une variable masquée qui dépend d’une condition if. Cette condition vérifie un paramètre GET, ou un cookie. Vous constatez alors que le comportement se déclenche uniquement sur certaines pages ou pour certaines requêtes.
Vous remontez ensuite vers la logique d’initialisation et vous trouvez que la variable est complétée par une valeur stockée dans la base, via une option WordPress. Là, l’attaque devient cohérente: le fichier déclenche, mais la configuration vit en base.
Le nettoyage doit alors faire deux choses: supprimer la partie obfusquée dans le fichier, et aussi nettoyer l’option base de données et toute persistance associée. Si vous ne faites que l’une des deux, le mécanisme redémarre. Si vous ne corrigez pas la vulnérabilité de départ, un nouvel acteur injectera à nouveau la même mécanique.
C’est ce fil conducteur, fichiers plus variables masquées dans les options ou hooks, qui permet d’éviter le “faux propre”.
Quand vous ne pouvez pas être sûr à 100 pour cent
Il y a des cas où l’obfuscation est suffisamment ambiguë pour hésiter: du code qui pourrait être un fragment de performance, une fonctionnalité de caching, ou une bidouille historique. La règle que je garde, c’est de privilégier le risque.
Si le comportement réseau est suspect, si l’injection est confirmée, et si le code “ne colle pas” à la fonction du module, vous avez assez pour agir. Vous pouvez ensuite tenter une analyse plus fine, mais en attendant, vous isolez.
L’autre règle: ne pas casser la production inutilement. Le bon compromis est souvent une procédure d’isolement, restauration depuis une sauvegarde propre si vous en avez, et remontée progressive des différences. Quand on compare un état “avant” et “après”, les obfuscations deviennent moins mystérieuses.
Ce qu’il faut faire pour avancer vite, sans se perdre
Si vous devez prioriser, je vous conseille de garder une progression en trois temps:
repérer les emplacements où le code est exécuté (fichiers et hooks), comprendre la reconstruction des variables masquées jusqu’à l’action finale (URL, inclusion, exécution), éliminer la persistance dans les fichiers et dans la base, puis corriger la cause probable.
C’est plus laborieux que de “nettoyer et espérer”, mais c’est la différence entre une infection vraiment éradiquée et un site qui rechute.
Dernier point: tester proprement après correction
Une fois le nettoyage effectué, il ne faut pas seulement vérifier visuellement. Si l’attaque s’exécute selon un trigger rare, vous devez simuler différents contextes: naviguer sur les pages sensibles, tester côté compte connecté, vérifier l’espace admin, et observer les logs pendant quelques heures.
Le bon réflexe est de surveiller les signaux qui révèlent une activité résiduelle. Même sans voir de “défiguration” de page, des requêtes externes inattendues peuvent indiquer qu’il reste une variable masquée ou une persistance cachée.
Quand un site WordPress infecté revient à une stabilité satisfaisante pendant une période significative, avec des logs propres et un code cohérent, vous pouvez alors considérer que l’incident est derrière vous. Et si vous avez un doute, vous faites l’erreur inverse, vous ne “laissez pas ça en l’état”. Vous revenez à la source, parce que l’obfuscation n’est pas un détail, c’est un indice de méthode.
Si vous me décrivez votre situation, même de façon partielle, je peux vous aider à orienter l’analyse: quelles pages injectent, quels fichiers ont changé, et quel type d’obfuscation vous observez (par exemple base64_decode, substr, chaînes fragmentées, hooks).