Désinfection WordPress : analyse du code injecté dans le thème

Quand on parle de désinfection WordPress, on imagine souvent le scénario le plus visible: un site qui “défigure”, une redirection automatique, ou des pages qui apparaissent là où rien n’a été prévu. Dans la vraie vie, la première trace utile est plus souvent discrète. Le trafic augmente, la charge CPU monte, quelques URL suspectes sont générées, et surtout le thème contient des fichiers modifiés avec des bouts de code qui n’ont aucune raison d’être là.

J’ai déjà ouvert des thèmes qui semblaient fonctionnels côté interface, tout en portant une charge malveillante très ciblée. Le point commun, c’est que l’injection passe presque toujours par des endroits où WordPress exécute du PHP à la volée. Le thème est un candidat fréquent, parce qu’il est chargé tôt, et parce que de nombreux sites utilisent les hooks du thème sans trop inspecter le contenu des fichiers. Résultat: la désinfection ne se résume pas à “supprimer un fichier”, elle consiste à comprendre ce que fait exactement le code injecté, pour éviter la récidive.

Le piège du “fichier modifié” qui ne dit pas tout

La première réaction est souvent de comparer le thème installé à une version saine. C’est une bonne approche, mais elle révèle un faux sentiment de sécurité. L’injection peut ne pas se limiter à un fichier, et le code malveillant peut s’appuyer sur une logique qui ne s’exécute que dans certaines conditions.

Par exemple, j’ai vu des injections dont l’exécution dépendait de paramètres de requête, d’un intervalle de temps, ou d’un UA (user agent) particulier. Le site semblait propre lors d’une inspection “à froid” puis devenait suspect une minute après, uniquement pour des visiteurs venant de sources spécifiques. À l’inverse, certains malwares s’exécutent systématiquement mais ne laissent de traces qu’en cas de privilèges élevés, ce qui masque le comportement pendant le debug.

C’est pour cela que l’analyse doit viser deux choses en parallèle:

    identifier le point d’exécution (où est le code, comment WordPress l’appelle) comprendre la chaîne de transformation (comment le code malveillant reconstruit ou choisit sa charge utile)

Le thème est souvent l’entrée, mais la charge peut être découpée en morceaux.

Où le code injecté se cache le plus souvent dans un thème

Dans un dossier de thème, tout n’est pas exécuté par WordPress. Certains fichiers ne servent qu’à des templates, d’autres à des assets, d’autres à des options. Pourtant, la plupart des injections exploitent des zones “branchées”:

    des fichiers chargés systématiquement comme functions.php des fichiers inclus depuis des templates (par exemple une logique ajoutée dans un template PHP) des fichiers exécutés via hooks (actions, filtres) liés au cycle de rendu

Le plus fréquent est l’ajout de code dans functions.php ou dans un fichier PHP déjà chargé. L’injection peut ressembler à une série de conditions, à une fonction anonyme, ou à un morceau de code concis qui fait tout le travail. Souvent, on ne voit pas une “redirection” en clair, on voit plutôt une préparation, puis une exécution différée.

Un signal courant: le code injécté se place en dessous de commentaires standards, ou juste avant une fonction existante, comme s’il avait été “inséré” sans changer le reste. Parfois, la modification est aussi subtile qu’une ligne ajoutée au milieu d’un add_action().

Le “pattern” le plus parlant: déchiffrement et exécution de charge

Beaucoup de malwares pour WordPress utilisent un mécanisme classique: stocker une charge utile compressée, encodée, ou fragmentée, puis la reconstruire au moment de l’exécution. Dans un thème, cela donne souvent quelque chose comme:

    des chaînes longues base64 des appels à gzinflate, gzuncompress, str_rot13, ou des variantes du eval(...), parfois indirect via une fonction wrapper des conversions par strrev, substr, str_replace ou boucles qui reconstituent des morceaux

Je dis “souvent”, pas “toujours”, parce qu’il existe des injections plus propres en apparence: elles installent d’abord une porte d’entrée qui attend une condition. Mais la logique de reconstruction est suffisamment fréquente pour qu’on l’attende dans les premiers examens.

Reconnaître la logique sans exécuter

L’erreur la plus coûteuse, c’est de “tester” le code malveillant. Même si le site a l’air en lecture seule, l’injection peut déclencher une sortie réseau ou une modification de fichiers pendant un appel. Dans une désinfection WordPress sérieuse, on évite d’exécuter quoi que ce soit côté serveur tant qu’on n’a pas isolé l’environnement d’analyse.

Concrètement, on procède par lecture statique. On repère:

    une fonction qui prépare une chaîne un point d’exécution (hook, inclusion de fichier, condition) la présence de fonctions d’exécution dynamique (eval, assert, appel de fonction depuis une variable)

Quand il y a un eval, je traite le fichier comme compromis, même si la charge n’est pas visible en clair. Il suffit parfois d’une condition simple pour éviter que la charge soit déchiffrée dans un test “manuel”.

Comprendre le déclenchement: pourquoi le malware n’apparaît pas toujours

Une question revient souvent après incident: “Pourquoi on ne voyait rien dans l’URL, et pourtant des visiteurs étaient redirigés?”

La réponse tient au déclenchement. Les injections dans les thèmes peuvent s’activer selon plusieurs signaux. Sans inventer de scénario précis, voici les catégories qu’on observe réellement:

    activation sur une variable serveur (par exemple certaines valeurs issues de l’environnement) activation sur l’utilisateur ou le type de requête (site admin, front, type de page) activation sur des plages de temps activation sur une partie de l’URL, ou sur la présence d’un paramètre de requête activation sur des conditions “anti-robots” (même si les noms sont variables)

L’analyse consiste à chercher dans le code malveillant les conditions d’entrée. Parfois c’est un if un peu sale, parfois une logique plus structurée. Ce qui compte, c’est de comprendre si le code dépend de paramètres qu’on ne reproduira pas facilement en local.

Exemple de lecture utile (sans exécuter)

Quand on voit une forme du type add_action('wp_head', function()...), on sait que le code s’exécute lors de la construction de la page HTML. Si à l’intérieur il y a une logique d’injection de script ou un test d’URL, on peut comprendre la direction sans la lancer.

image

Inversement, si le code modifie une variable globale, ou s’il redéfinit une fonction, l’impact peut se voir seulement sur certaines pages. J’ai déjà vu des injections qui modifiaient des paramètres de rendu pour des templates spécifiques, ce qui rendait la détection plus lente, parce que le site “globalement” semblait intact.

Les indices “humains” dans le code injecté

Les malwares ne sont pas écrits pour être beaux. Dans un thème, même quand le code est compressé ou encodé, il existe des signatures de fabrication.

Je prête attention à:

image

    des noms de fonctions ou variables incohérents, mélangés à des identifiants inutiles des commentaires tronqués ou des blocs de code ajoutés au mauvais endroit des espaces bizarres, ou des “collages” entre morceaux des structures qui ne suivent pas le style du thème d’origine

Ce ne sont pas des preuves formelles, mais ce sont de bons repères. Ils guident l’endroit où concentrer l’analyse. Plus on économise du temps, plus on diminue le risque d’erreur dans la désinfection.

Analyse structurée du contenu compromis

Pour analyser efficacement un thème infecté, j’utilise une démarche qui tient en quelques étapes. L’idée est de ne pas se focaliser sur un seul fichier, mais sur la chaîne d’exécution.

Voici une manière pragmatique de procéder, sans listes interminables.

Localiser le point d’exécution: trouver le chargement du fichier (hook, inclusion, functions.php, template). Identifier la charge utile: chercher si le code reconstruit une chaîne encodée, ou s’il envoie une requête. Déterminer le déclencheur: lire les conditions, vérifier si elles dépendent de variables de requête. Évaluer la persistance: repérer si une fonction modifie des fichiers, des options, des variables de configuration. Isoler avant suppression: sauvegarder le thème, désactiver temporairement pour couper l’exécution, puis nettoyer.

Cette approche limite une erreur fréquente: supprimer “le plus visible” sans comprendre que d’autres fichiers du thème, ou des inclusions, portent la suite.

Comment distinguer une injection “simple” d’une compromission plus profonde

Un code injecté dans un thème peut être une charge autonome. Dans ce cas, la désinfection du thème suffit à arrêter le comportement. Mais on voit aussi des cas où le thème sert de relais vers une compromission plus large.

Quelques signaux qui orientent vers une compromission plus profonde:

    plusieurs fichiers du thème modifiés dans des chemins différents présence de code identique ou proche dans d’autres répertoires (plugins, uploads, mu-plugins) création de hooks ou filtres non cohérents avec le thème répétition d’un même mécanisme d’encodage dans plusieurs endroits usage de variables globales et de fonctions qui semblent servir de “dispatcher” entre plusieurs charges

Le point essentiel: le thème infecté peut être un symptôme, pas la cause racine. Si le site a été compromis via un identifiant administrateur, le thème peut être seulement l’étape la plus visible. D’où l’importance, en désinfection WordPress, de vérifier au-delà du dossier du thème.

Risques et arbitrages pendant la désinfection

Nettoyer un thème a un coût opérationnel. On veut couper l’exécution, puis restaurer une version saine, mais il y a des contraintes réelles:

    le site doit rester accessible autant que possible on doit éviter une rupture de fonctionnalités légitimes on doit préserver les personnalisations (child theme, traductions, réglages)

J’ai déjà vu des équipes supprimer tout un dossier, puis constater qu’elles avaient effacé des modifications légitimes, comme une surcharge de https://gardewp.fr/nettoyage-malware-wordpress/ templates ou une configuration de shortcodes. La bonne pratique consiste à restaurer le thème via une source de référence fiable (dépôt du vendeur, contrôle de version, archive connue) et à comparer ensuite ce qui doit être réappliqué.

Sur le plan sécurité, je recommande de couper l’exécution rapidement. Une mesure efficace consiste à désactiver le thème incriminé (ou basculer temporairement vers un thème de secours). Cela stoppe la boucle, mais attention au “moment” où WordPress charge la page: certaines charges peuvent aussi se déclencher sur des pages de style d’interface ou dans le back-office. D’où l’intérêt de faire les changements en dehors des heures de pointe, si possible, et avec une procédure de retour.

Où chercher dans les fichiers: micro-détection utile

Quand on ouvre le fichier compromis, on peut chercher des marqueurs textuels. Sans transformer cela en “recette” universelle, il y a des éléments qui reviennent:

    eval(, assert(, ou d’autres exécutions dynamiques base64_decode(, gzinflate(, gzdecode( des boucles de reconstruction, par exemple des opérations répétées sur une chaîne des appels à des fonctions réseau (requêtes HTTP, sockets), parfois indirectes des manipulations de fichiers (création, écriture) si la persistance existe

L’idée n’est pas de “tout supprimer” automatiquement. Parfois il y a des références à ces fonctions dans un autre contexte, par exemple un thème qui compresse quelque chose de façon légitime, mais c’est rare dans la pratique.

Le bon réflexe: si on trouve une combinaison incohérente, ou un enchaînement typique “décodage puis exécution”, je traite la totalité du bloc comme hostile et j’étudie sa trajectoire.

Départager le thème source du thème ciblé: child themes et inclusions

Un point qui surprend souvent: les thèmes “parent” et “child” peuvent être mêlés. L’injection peut être dans le parent, mais l’appel peut venir du child, ou inversement.

Dans un child theme, il existe souvent un functions.php réduit qui inclut le parent, puis ajoute quelques hooks. Si le parent est intact mais que le child contient l’injection, la désinfection doit viser le child sans casser les ajustements légitimes. À l’inverse, si l’injection est dans le parent, même la désactivation du child ne suffit pas.

C’est pour cela que l’analyse doit inclure la logique d’inclusion: quelles fonctions sont chargées, et comment. Une seule inclusion malveillante peut faire exécuter tout le reste.

Contrôles complémentaires au-delà du thème

Même si l’objectif du diagnostic est “analyse du code injecté dans le thème”, une désinfection WordPress propre exige des vérifications transversales. Sinon, on risque de nettoyer une façade et de laisser la porte ouverte.

Dans la pratique, j’inspecte notamment:

    les plugins installés et leurs dates de modification les fichiers sensibles dans l’arborescence WordPress (en tenant compte des pratiques de chaque site) les utilisateurs et rôles, surtout si une création récente d’un compte suspect est apparue les traces côté serveur (logs d’accès, logs PHP) pour voir si l’exécution correspond à une requête

Je garde ces contrôles en tête même si, au départ, seul le thème semble en cause. Le code injecté est un indice, pas une preuve de la source.

Comment documenter l’analyse pour éviter les rechutes

Une désinfection bien faite se voit au-delà du “ça marche de nouveau”. Ce qui évite la rechute, c’est la capacité à répéter le diagnostic rapidement si un nouveau fichier apparaît.

Je recommande de conserver:

    une copie datée des fichiers compromis (avant nettoyage) les lignes exactes où l’exécution démarre (sans forcément conserver toute la charge si elle est trop dangereuse) un résumé du déclencheur (conditions, hooks) la liste des emplacements modifiés

C’est particulièrement utile si vous travaillez en équipe, ou si vous externalisez. Sans documentation, on perd du temps à reconstruire le raisonnement, et on risque de refaire les mêmes erreurs de jugement.

Quand le code injecté ressemble à du “style” et pourquoi ça trompe

Il existe un cas frustrant: le code injecté imite une esthétique “propre”. Parfois il semble s’intégrer au thème: variables bien nommées, structure proche du style original, parfois même des fonctions qui semblent utiles.

Le trompe-l’œil est souvent un bloc encodé ou une charge utile déplacée dans une autre fonction. Le code visible peut paraître raisonnable, mais la branche qui exécute la charge peut être cachée derrière une condition rarement satisfaite.

image

C’est là que l’analyse doit être loyale envers le déclencheur. Si vous ne savez pas quand ça s’exécute, vous ne pouvez pas conclure que c’est inoffensif. En désinfection WordPress, j’ai appris à ne pas “se calmer” trop vite juste parce que la partie lisible ne contient pas de redirection explicite.

Nettoyage: ce que je fais, et ce que je refuse de faire

Une fois l’analyse terminée, la logique de nettoyage est souvent simple sur le papier, mais délicate dans les détails.

Je privilégie:

    restauration à partir d’une base saine suppression stricte des blocs identifiés comme injectés vérification que le thème retrouve son comportement attendu recontrôle des emplacements connus pour empêcher la récidive

Je refuse en général:

    de laisser en place des fonctions suspectes “juste au cas où” de garder des blocs encodés “sans comprendre” de tenter de désactiver uniquement le déclencheur sans vérifier la persistance (si la charge a déjà été structurée pour d’autres chemins)

La désinfection WordPress devient efficace quand vous coupez la chaîne, pas uniquement le symptôme.

Signes d’alerte post-désinfection: vérifier sans sur-réagir

Après nettoyage, il y a deux pièges. Le premier est de supposer que tout est réglé parce que le site charge. Le second est d’être trop agressif et de casser des intégrations légitimes.

Les signes à surveiller dépendent de votre contexte, mais en pratique je regarde si:

    les pages montrent des anomalies, comme des scripts injectés dans le HTML la vitesse de rendu reste stable les redirections suspectes cessent les logs cessent d’exhiber des erreurs liées aux fichiers nettoyés

Si le trafic suspect continue malgré la désactivation du thème, c’est un indice que l’injection n’était pas uniquement dans le thème. Là, l’analyse doit remonter ou élargir son périmètre.

Une dernière recommandation: traiter l’incident comme un chantier, pas comme une correction

J’ai vu des désinfections “réussies” qui ont échoué deux semaines plus tard, parce que la même faiblesse d’accès n’avait pas été corrigée. Le code injecté dans le thème est souvent la conséquence d’un point d’entrée. Si vous ne colmatez pas cet accès, le thème redeviendra un support.

Sur les environnements professionnels, on combine généralement:

    rotation des identifiants et vérification des comptes durcissement de la sécurité WordPress (selon votre politique) surveillance (fichiers modifiés, comportements réseau) procédure de restauration testée

L’analyse du code injecté dans le thème, c’est la partie technique la plus spectaculaire. Mais c’est aussi celle qui demande le plus de rigueur, parce qu’elle touche à un équilibre: comprendre sans exécuter, nettoyer sans casser, restaurer sans réintroduire une porte d’entrée.

Si vous avez déjà un extrait du code ou le fichier concerné (en masquant les éléments sensibles), je peux vous aider à le lire ligne par ligne et à déterminer le déclencheur, la forme de la charge utile, et la manière la plus sûre de le neutraliser.