Sécurité WordPress : comment détecter un plugin compromis

Un site WordPress finit rarement “infecté” d’un coup comme dans les films. Le plus souvent, il y a une lente dégradation, des symptômes discrets, puis un incident. Et parmi les points d’entrée les plus fréquents, il y a le plugin. Un plugin compromis peut agir comme un cheval de Troie, rester silencieux, ouvrir une porte, ou redéployer du code malveillant dans un endroit inattendu.

J’ai déjà vu des cas où tout semblait propre côté serveur, où les logs n’avaient rien de spectaculaire, et où l’origine était pourtant un module apparemment banal: un constructeur de formulaires, un plugin de SEO “gratuit” ou un outil d’import. Les fichiers étaient modifiés à peine, quelques lignes ajoutées, puis une chaîne de requêtes préparées pour récupérer du code plus tard. https://gardewp.fr/securite-wordpress/ Le piège, ce n’est pas seulement de détecter. C’est de détecter assez tôt, avec des preuves suffisantes pour décider quoi supprimer et quoi restaurer.

L’objectif de cet article est simple: vous donner une méthode réaliste pour repérer un plugin compromis, confirmer vos soupçons sans partir dans tous les sens, puis renforcer la sécurité WordPress autour de ce risque.

Pourquoi un plugin compromis est difficile à repérer

Un plugin légitime fait souvent des choses “normales”: charger des bibliothèques, interagir avec la base de données, ajouter des hooks, appeler des API. Le code malveillant se glisse là-dedans en profitant du fait que WordPress est extensible. Il peut, par exemple:

    injecter un script côté front, pour rediriger ou voler des cookies, modifier des options WordPress (comme l’URL d’un script, un réglage d’administration, des paramètres de cron), ajouter des utilisateurs, ou préparer un mécanisme d’exécution déclenché seulement sous certaines conditions (une plage d’horaires, une IP précise, un navigateur spécifique).

Le résultat est souvent frustrant: vous voyez un comportement étrange, mais vous ne pouvez pas dire immédiatement “c’est ce plugin”. Il faut passer du ressenti à l’observation, puis à la comparaison.

Les premiers signaux qui doivent mettre la puce à l’oreille

Avant de plonger dans les fichiers, je commence toujours par cartographier les symptômes. Ils ne prouveront pas à eux seuls qu’un plugin est compromis, mais ils indiquent où chercher.

Un plugin compromis peut se manifester par des signaux côté site et côté administration. Par exemple:

    le site renvoie des redirections inattendues (parfois seulement sur certaines pages), du contenu “parasite” apparaît dans le HTML sans logique éditoriale, des scripts externes inconnus se chargent dans la page, surtout via le header ou le footer, des mails d’administration partent alors que vous n’avez rien fait, la charge CPU ou le temps de génération de page augmentent sans changement notable côté thème, des nouvelles tâches planifiées apparaissent, ou l’ordonnancement WordPress (WP-Cron) se déclenche de manière anormale, l’administration devient instable: pages lentes, erreurs PHP bizarres, ou comptes qui se multiplient.

J’accorde une attention particulière à tout ce qui touche à la persistance. Un script qui “se voit” dans le front peut n’être qu’un symptôme. Le vrai mécanisme peut être caché dans un fichier PHP du plugin, ou dans une option stockée en base, ou encore dans un fichier ajouté dans wp-content.

La méthode qui marche le mieux: vérifier la différence, pas seulement la présence

Dans mes interventions, le déclencheur le plus utile est la comparaison. Si vous avez un site en production et que vous n’avez pas d’historique, vous devez créer un “référentiel” rapide: versions connues, fichiers attendus, signatures de contenu, et traces d’exécution.

L’idée n’est pas de “scanner au hasard”. C’est de répondre à trois questions:

Qu’est-ce qui a changé récemment ? Quels fichiers sont modifiés, où, et par qui (dans la mesure des journaux disponibles) ? Quel code est réellement exécuté au chargement de WordPress, pendant l’affichage, ou au moment d’une action (formulaire, cron, connexion) ?

WordPress a une architecture qui permet de repérer des anomalies par localisation. Le cœur est rarement la cible principale. En revanche, wp-content/plugins, wp-content/uploads, et parfois wp-content/themes sont souvent impliqués. Même si vous suspectez un plugin, vérifiez aussi si le plugin a déposé des artefacts dans uploads.

Étape 1: isoler le problème et réduire le bruit

Avant d’ouvrir 300 fichiers, je cherche à limiter les variations. Si le site est en production et que vous pouvez vous permettre une action de frein, je bascule sur une approche d’isolation:

    passer temporairement à un environnement de staging si vous en avez un, ou activer une maintenance, ou couper l’exécution front temporairement via règles au niveau serveur, pour garder les logs et l’accès admin.

Le but est de conserver des preuves pendant que vous explorez. Un site compromis peut se “reconfigurer” à chaque visite, surtout si le code malveillant interroge un serveur externe ou régénère du contenu.

À ce stade, surveillez aussi les logs applicatifs et serveur. Les journaux d’erreurs PHP, les accès web, et les logs du moteur (Nginx ou Apache) donnent souvent une piste sur les fichiers déclenchés.

image

Étape 2: repérer les fichiers modifiés récemment dans wp-content

C’est souvent là que tout se joue. Les plugins compromis laissent des traces de modification de fichiers PHP, d’ajout de scripts, ou de création de fichiers au nom “banal”. Les dates ne suffisent pas à elles seules, car un déploiement légitime peut toucher les mêmes zones. Mais la combinaison date + contenu + emplacement est très parlante.

Je procède généralement comme suit, sans prétendre à une “science exacte”:

    repérer les fichiers récemment modifiés dans wp-content/plugins, repérer les fichiers récemment ajoutés dans wp-content/plugins et wp-content/uploads, regarder si un plugin a des fichiers en dehors de son dossier, ou des inclusions vers des chemins inhabituels, relever la liste des plugins et leurs versions, puis vérifier que vous ne voyez pas une différence de version ou d’archive non prévue.

Dans un cas réel que j’ai traité, un plugin SEO avait un fichier PHP ajouté avec un nom plausible. L’ajout ne représentait que quelques dizaines de lignes. Le reste du plugin était identique. Le code ne “faisait rien” au chargement standard, mais se branchait sur un hook spécifique, puis tirait du contenu depuis une URL codée en dur.

Étape 3: lire le PHP de la zone “dangereuse” avec un regard critique

Quand un plugin est compromis, le code malveillant se repère souvent à des motifs récurrents. Je ne parle pas d’une liste universelle, car les adversaires s’adaptent. Mais il y a des signatures de comportement.

Voici les endroits que je regarde en priorité dans un plugin suspect:

    la présence de eval, base64_decode, gzinflate, str_rot13, ou des constructions qui transforment du code, l’usage de file_get_contents, curl (direct ou via wrappers), fopen vers des URLs externes, surtout si c’est conditionnel, l’accès à des chemins du serveur via ABSPATH, __DIR__, ou des concaténations bizarres, des “inclusions” vers des fichiers présents dans wp-content mais pas dans le plugin lui-même, des hooks WordPress inattendus: exécution sur init, wp_loaded, admin_init, ou des actions reliées à l’affichage, des opérations de base de données qui touchent des tables sans raison fonctionnelle évidente.

Ce qui m’aide, ce sont les détails: le plugin récupère t-il une charge utile et l’exécute seulement si une condition est vraie ? Le plugin “cachait” il son comportement dans une condition dépendant d’un identifiant d’utilisateur, d’un cookie, ou d’une IP ?

Je reste prudent: un plugin légitime peut utiliser des fonctions similaires pour compresser des données, gérer des imports, ou exécuter des templates. La différence, c’est l’intention, la structure, et le contexte. Un plugin d’import peut faire de l’import. Un plugin d’anti-spam ne devrait pas soudainement contacter un serveur externe pour injecter du HTML.

Étape 4: cherchez les points de persistance en base et via les options

Beaucoup de compromissions ne reposent pas uniquement sur des fichiers modifiés. Un attaquant peut ajouter une option WordPress contenant du code ou une URL, puis déclencher l’exécution via un hook. Parfois, un plugin compromis ne fait qu’initialiser une configuration en base.

Dans WordPress, les “options” et les métadonnées sont des zones à surveiller. Je prête attention à:

    les options contenant des chaînes inhabituelles, les actions planifiées (WP-Cron) qui exécutent des hooks inattendus, les modifications de rôles et de capacités, la création d’utilisateurs récents, l’apparition de nouveaux termes ou pages, sans cohérence avec votre activité éditoriale.

Si vous avez un accès à l’exécution SQL via un outil d’administration, vous pouvez vérifier certaines incohérences. Mais attention, sur un site en production, ne lancez pas des requêtes agressives. L’idée est de repérer des traces, pas de provoquer une surcharge.

Étape 5: comparer avec la version “saine” du plugin

Si vous avez une sauvegarde de l’état précédent, c’est le moyen le plus robuste. Si vous n’en avez pas, vous pouvez reconstruire une référence saine en réinstallant le plugin à partir d’une source officielle.

Le principe: installer proprement, comparer le dossier, puis regarder ce qui a été ajouté ou modifié. La comparaison permet souvent de trancher même quand les dates ne sont pas claires.

Ce travail demande du temps, mais il évite un piège fréquent: supprimer “au feeling” un plugin innocent. Un plugin peut paraître bizarre parce qu’il est trop verbeux ou parce qu’il utilise des librairies tierces. En revanche, la différence de code par rapport à la version attendue, elle, est difficile à contester.

Comment confirmer qu’un plugin est réellement à l’origine

On peut suspecter un plugin, mais confirmation ne veut pas dire “on supprime et on voit”. En production, je préfère une approche qui prouve, par observation, que le comportement disparaît quand le plugin ne s’exécute plus.

Le test le plus simple est la désactivation. Mais WordPress peut charger le plugin différemment selon le contexte, et un plugin compromis peut déclencher des actions seulement dans certaines pages. Il faut donc tester avec un périmètre cohérent:

    tester les pages qui montrent le symptôme, tester l’accès admin si c’est là que le problème se déclenche, tester des actions connues, comme l’envoi d’un formulaire ou une page en cache.

Si, après désactivation, vous voyez clairement que les redirections ou injections disparaissent, alors vous avez un fort signal. Ensuite, revenez au code pour comprendre la cause, car supprimer le plugin ne restaure pas forcément les dégâts déjà laissés en base.

Checklist rapide pour détecter un plugin compromis

Voici la méthode de terrain que j’utilise le plus souvent, pour passer de “suspicion” à “constat”.

    Repérer les fichiers modifiés ou ajoutés récemment dans wp-content/plugins et wp-content/uploads Vérifier si le plugin appelle des URLs externes, surtout via des fonctions de lecture ou des requêtes conditionnelles Inspecter les hooks déclenchés sur admin init, init, wploaded, save_post, ou sur l’affichage du contenu Comparer le dossier du plugin à une version fraîche installée depuis une source officielle Vérifier la base: utilisateurs récents, options modifiées, et cron planifié lié à des hooks inattendus

Cette checklist est volontairement “courte”. En pratique, elle déclenche des pistes concrètes, puis on approfondit sur le code et les traces.

Les cas fréquents de plugins compromis (et ce qu’on observe)

Certains schémas reviennent sans être identiques.

1) Le plugin a l’air normal, mais ajoute un fichier dans uploads

J’ai rencontré des cas où le plugin ne contenait presque aucune ligne suspecte, mais déposait un fichier dans wp-content/uploads. Le fichier, souvent un PHP masqué dans un nom “document”, servait ensuite de loader. Dans cette configuration, un scan superficiel du dossier plugins ne suffit pas.

Ce type de persistance se détecte en regardant les fichiers récemment créés dans uploads et en inspectant comment ils sont inclus. Parfois, c’est via un chemin calculé.

2) Le plugin injecte du JavaScript depuis le backoffice

Un autre scénario est l’injection dans le front via l’admin. L’attaquant vise la rentabilité: voler des sessions ou rediriger vers des domaines. On observe alors des scripts externes inconnus dans le HTML rendu, parfois seulement pour certains utilisateurs.

La vérification consiste à remonter depuis le HTML jusqu’à la source: quel hook ajoute le script ? Quel fichier PHP l’exécute ? Quel plugin contient la logique ?

3) Le plugin déclenche une charge utile seulement pour certaines conditions

Un comportement “flottant” est un gros indice. Par exemple, tout marche quand on teste, puis ça casse pour un autre type de visite. La condition peut être une version de navigateur, une plage d’horaires, ou une IP.

Dans ce cas, les logs de requêtes et les journaux de requêtes PHP sont précieux. Si vous pouvez, capturez plusieurs visites, avec des profils différents, et comparez ce qui change.

Renforcer sécurité WordPress après détection: ne pas se contenter de nettoyer

Une fois le plugin compromis identifié, l’étape suivante est souvent bâclée. Les fichiers peuvent être remis à l’état sain, mais l’attaque a peut-être déjà laissé des traces en base, des comptes, ou une reconfiguration.

Renforcer sécurité WordPress revient à faire trois choses, avec un minimum de méthode:

Restaurer l’état “attendu” (plugins, thèmes, fichiers spécifiques), éliminer les persistance en base (options, cron, utilisateurs), Durcir l’environnement pour empêcher la prochaine compromission.

Dans la vraie vie, vous n’aurez jamais une garantie absolue. Mais vous pouvez réduire drastiquement la surface d’attaque.

Plan d’assainissement réaliste (sans magie)

Voici une approche d’assainissement que j’ai vu fonctionner, à condition de la faire sérieusement et dans le bon ordre.

1) Remettre le plugin à une version saine, ou le remplacer, puis vérifier que le site retrouve un comportement normal.

2) Traquer les artefacts laissés. Si des fichiers ont été déposés dans uploads, ils doivent être supprimés, et le mécanisme d’inclusion doit être neutralisé. Supprimer uniquement le dossier du plugin ne suffit pas si le loader reste ailleurs.

3) Contrôler les comptes et rôles. Si l’attaquant a créé un utilisateur, supprimez-le, mais vérifiez aussi la cohérence des rôles et des capacités. Parfois, un compte légitime a juste été reconfiguré.

4) Contrôler les options et le cron. Les hooks programmés peuvent redémarrer la charge utile même après remplacement de fichier.

5) Réinitialiser les secrets. Si vous suspectez une prise de contrôle, changez les mots de passe des comptes, idéalement aussi pour les rôles admin, éditeur, et tout ce qui a accès aux réglages. Selon votre cas, changez aussi les clés d’authentification WordPress.

Cette séquence évite un piège: “on supprime le plugin, mais le comportement revient”. Souvent, c’est parce que la base a conservé une persistance.

Durcir l’environnement pour éviter la récidive

La prévention n’est pas qu’une question d’outil, c’est aussi une question de discipline opérationnelle.

En général, je recommande de réduire l’exécution de code non contrôlé et d’améliorer la visibilité:

    maintenir WordPress, thèmes et plugins à jour, supprimer les plugins inutilisés, limiter les droits, éviter que des comptes non nécessaires aient accès à l’upload ou à l’installation, surveiller les modifications de fichiers (au moins ceux qui sont critiques), activer une journalisation exploitable (logs serveur et logs applicatifs), forcer des connexions robustes côté administration.

Sur certains sites, j’ai aussi vu la différence venir de réglages d’hébergement: désactiver des fonctions PHP dangereuses si c’est possible, restreindre les accès, et contrôler les permissions de fichiers. Ce sont des ajustements qui demandent une coordination avec l’hôte, mais ils réduisent fortement la marge d’un script malveillant.

Pièges et limites: ce qui peut tromper même un bon diagnostic

Il y a des cas où un plugin “bizarre” n’est pas compromis, et des cas où un plugin compromis ne se voit pas facilement.

Un plugin peut sembler suspect sans l’être

Un plugin de sauvegarde, un plugin d’import, ou un outil de performance peut contenir du code qui ressemble à une obfuscation. Certains utilisent des transformations de chaînes pour gérer des payloads d’options, des compressions, ou des templates. La clé est la cohérence fonctionnelle et la comparaison à une version saine.

L’injection peut venir d’un endroit hors plugin

Le thème, un fichier de mu-plugin, un fichier dans wp-content mu-plugins, ou un artefact dans uploads peuvent porter la charge utile. Dans une enquête, j’inspecte donc l’ensemble des “zones de persistance” possibles, même si le premier soupçon tombe sur un plugin.

Un faux positif est possible

Si vous supprimez un plugin à tort, vous risquez de casser des fonctionnalités et de perdre du temps. C’est pour cela que je privilégie une approche par comparaison et par test contrôlé. Le but n’est pas de “gagner” une chasse au monstre, c’est de rétablir un site propre.

Comment organiser votre routine de détection (sans en faire trop)

Pour un site WordPress qui évolue, je conseille une routine légère mais régulière. Pas besoin d’une usine à gaz, mais vous devez garder la capacité de détecter “ce qui change”.

Une bonne routine inclut:

    des sauvegardes régulières, pour restaurer rapidement, un inventaire des plugins et thèmes, avec versions, une relecture ponctuelle des événements: ajouts, mises à jour, erreurs inhabituelles, une inspection périodique des fichiers récents dans wp-content.

Si vous avez déjà vécu une compromission, vous savez que la meilleure prévention, c’est de ne pas perdre les moyens de comparaison. Même une simple sauvegarde “avant mise à jour” vous sauve un week-end entier quand un doute surgit.

Quand faire appel à un professionnel (ou au moins demander un deuxième avis)

Vous pouvez faire une partie du travail vous-même, surtout si vous avez une bonne maîtrise du serveur et si vous pouvez maintenir une copie pour analyse. En revanche, il vaut mieux demander de l’aide si:

    vous voyez des redirections et vous suspectez un vol de sessions, vous trouvez des artefacts multiples dans plusieurs dossiers, votre base montre des modifications importantes sans comprendre la logique, le site est instable et les logs sont difficiles à lire, vous n’avez pas de sauvegardes exploitables.

Dans ces cas, l’important est de sécuriser rapidement, puis d’analyser avec méthode. Une action trop rapide peut masquer la cause.

Dernier point: la discipline après l’incident

Après une compromission, on a tendance à vouloir repartir vite. C’est compréhensible, mais c’est aussi le moment où des angles morts se créent: un plugin réinstallé sans vérifier sa provenance, un compte rétabli sans contrôle des accès, une option oubliée.

Prenez le temps de valider ce qui a réellement été modifié. Cette validation, même partielle, vous aide à renforcer sécurité WordPress, pas juste à “nettoyer une fois”.

Si vous n’avez qu’un seul réflexe à garder, c’est celui-ci: quand vous suspectez un plugin compromis, ne cherchez pas uniquement “un fichier suspect”. Cherchez des différences, des comportements et des points de persistance. C’est là que le diagnostic devient solide, et que le nettoyage tient dans le temps.