Désinfection WordPress : supprimer les fichiers .php inconnus

Quand on administre un site WordPress, on finit par mémoriser quelques réflexes. Mettre à jour les thèmes et les plugins, surveiller les sauvegardes, garder un œil sur les commentaires et les erreurs 404. Et puis, un jour, on tombe sur un détail qui ne colle pas: des fichiers .php présents à des endroits inattendus, avec des noms bizarres, parfois sans taille cohérente, parfois créés le lendemain d’une mise à jour ou d’une tentative de connexion. C’est souvent le début d’une désinfection WordPress, et plus précisément, la suppression de fichiers .php inconnus.

Ce type d’incident a un profil assez récurrent: le site est compromis, puis l’attaquant dépose un webshell ou une charge utile, parfois déguisée en fichier “normal”. Ensuite, selon la méthode utilisée, le script peut voler des identifiants, injecter du code dans le front, rediriger vers de faux téléchargements, ou même servir de relais pour d’autres machines. Supprimer un fichier .php inconnu aide, mais ce n’est pas toujours suffisant si la compromission a laissé d’autres traces ailleurs.

Je vais donc traiter le sujet comme je le vois sur le terrain: comment identifier ces fichiers, comment vérifier qu’ils sont réellement “inconnus”, comment supprimer sans casser le site, et comment s’assurer qu’il n’y a pas une porte d’entrée qui réapparaît.

Pourquoi ces fichiers .php posent problème

Dans une installation WordPress saine, vous savez à peu près à quoi ressemble l’empreinte “normale” des fichiers. Le noyau contient wp-admin, wp-includes et des fichiers à la racine comme index.php. Les thèmes vivent dans wp-content/themes/, les extensions dans wp-content/plugins/. Les médias dans wp-content/uploads/. Les seuls .php “réellement attendus” à la racine sont ceux fournis par WordPress et ceux ajoutés par vous pour un usage précis (par exemple un script maison ou un plugin mu-plugin).

Quand un fichier .php apparaît au mauvais endroit, avec un nom ambigu, et surtout s’il n’a aucune raison d’être là, il faut partir du principe qu’il a été déposé pendant l’intrusion. Les webshells utilisent souvent des noms courts, parfois aléatoires, ou une extension qui ressemble à un utilitaire. Ils peuvent aussi être camouflés comme un composant utilisé par un thème ou un plugin, jusqu’à ce que vous regardiez le contenu.

L’autre aspect qui rend ces cas délicats, c’est la “fausse familiarité”. J’ai déjà vu un site où un fichier venait d’un thème importé, et avait un nom qui ressemblait étrangement à ceux d’un webshell. Le contenu était minimal, mais inoffensif. À l’inverse, j’ai déjà vu des fichiers minuscules, parfois quelques lignes, qui avaient l’impact maximal. Le nom ne suffit donc pas, et c’est là que l’approche méthodique compte.

La première étape: localiser les .php réellement inconnus

Avant de supprimer quoi que ce soit, vous gagnez du temps en bornant le périmètre. La question n’est pas “y a-t-il des .php”, la question est “lesquels n’auraient pas dû être là, et quand sont-ils apparus”.

Sur un chantier récent, j’ai travaillé sur un site dont les fichiers modifiés dataient majoritairement de la même journée. Les administrateurs n’avaient rien changé. En consultant l’historique côté serveur (ou les métadonnées via FTP/SFTP), on voyait une vague de nouveaux fichiers .php dans plusieurs dossiers, dont wp-content/uploads/ et un dossier de thème qui n’avait pourtant pas été touché. Le schéma était très typé.

Selon votre accès, les méthodes pratiques sont:

    Accès FTP/SFTP ou gestionnaire de fichiers de votre hébergeur Outil de gestion des fichiers de votre panel (souvent basique, mais utile) Accès shell si vous êtes à l’aise, ce qui permet un inventaire plus fiable Plugins de sécurité, parfois utiles pour détecter, mais pas toujours fiables à 100 pour cent pour la classification

Le point clé est de repérer les fichiers .php dont vous ne connaissez pas l’origine. “Inconnu” ne veut pas dire “je ne me souviens pas”. “Inconnu” veut dire: pas listé dans votre documentation, pas fourni par WordPress, pas présent dans vos thèmes et plugins déclarés, pas attendu par votre historique de déploiement.

Les emplacements les plus suspects

Sans en faire une règle absolue, certains emplacements méritent une attention immédiate.

La racine du site est souvent ciblée, car un script peut être exécuté facilement. wp-content/uploads/ est aussi un terrain fréquent, car beaucoup d’installations stockent des fichiers, et l’utilisateur fait confiance à ce dossier. Les thèmes et plugins sont logiques, mais un fichier .php qui apparaît “en plus” ou qui n’est pas un fichier standard du thème/du plugin en question devient un drapeau rouge. Et parfois, on voit des .php dans des sous-dossiers inattendus, par exemple wp-content/themes//assets/ alors que ce dossier n’est pas censé contenir du PHP.

Reconnaître un fichier “suspect” sans se tromper

Supprimer un fichier “inconnu” peut suffire, mais j’ai appris à ne pas me baser uniquement sur l’emplacement. Un fichier peut être “inconnu” et pourtant légitime, surtout sur des sites qui ont une histoire longue (multisites, migrations, thèmes enfants, bouts de code ajoutés au fil des ans).

La bonne stratégie consiste à combiner trois signaux:

Le contexte: où il se trouve, ce qui l’entoure, si ce dossier a une raison d’héberger du PHP. Le moment: date de création ou de modification comparée à votre calendrier réel. Le contenu: la logique du script, sa taille, ses fonctions, et ses éléments typiques de webshell.

Un webshell, même “simple”, a souvent une signature. Par exemple, des fonctions qui lisent des paramètres HTTP, qui écrivent sur le disque, qui exécutent du code, ou qui chargent dynamiquement d’autres fichiers. Je ne vais pas vous donner de recettes d’attaque, mais côté défense, le réflexe consiste à ouvrir le fichier et regarder si le comportement est cohérent avec un usage “normal” de WordPress.

Sur un cas, le fichier en question faisait moins de 2 Ko. À l’intérieur, on voyait des structures conditionnelles liées à des clés de requête, et une logique de base qui servait à exécuter. Sans même comprendre parfaitement chaque ligne, on sentait l’objectif. À côté, des fichiers “légitimes” ont plutôt des structures de configuration, des classes orientées WordPress, ou des hooks clairs.

Cas particulier: les thèmes enfants, mu-plugins et code maison

Un site peut avoir des fichiers PHP “maison” qui changent selon les besoins. Si vous avez un thème enfant, vous pouvez retrouver des fichiers supplémentaires, et parfois des feuilles PHP qui aident à personnaliser des templates.

Si vous avez des mu-plugins (dans wp-content/mu-plugins/), ils sont parfois oubliés par l’équipe, surtout quand il y a eu un turnover. Là, “inconnu” est souvent un problème de documentation, pas une intrusion.

Le bon jugement consiste à vérifier ce qui est censé exister. Si votre site n’a jamais eu de plugin mu ou de thème enfant, un fichier dans ce style doit être suspect. S’il existe depuis longtemps et correspond à un composant que vous maintenez, il peut être conservé, même s’il surprend au premier coup d’œil.

Avant de supprimer: sauvegarde et réduction du risque

La désinfection WordPress devient rapidement dangereuse quand on mélange deux actions: supprimer des fichiers et restaurer une base de données. Ce n’est pas “interdit”, mais il faut maîtriser l’ordre, et surtout garder une sortie de secours.

Mon approche préférée est simple: sauvegarder d’abord, puis travailler de manière réversible. Sur un site en production, j’ai déjà vu des suppressions trop agressives provoquer une page blanche. La cause était rarement un “core PHP” modifié, plus souvent un fichier “inconnu” qui était en réalité une dépendance d’un plugin, ou une redirection gérée par un script custom.

Si vous pouvez, faites une sauvegarde complète du dossier WordPress (ou au minimum un snapshot du répertoire) et une sauvegarde de la base de données. Si vous n’avez pas de plan, au moins créez une copie du dossier avant toute suppression, même si c’est “lourdit”, cela évite de partir dans le noir.

Ensuite, isolez votre action. Quand vous supprimez un fichier, vous voulez pouvoir expliquer pourquoi, et vous voulez pouvoir revenir en arrière si nécessaire. Si vous travaillez à plusieurs, notez les fichiers supprimés avec leur chemin, leur taille, et leur date observée. Une trace de travail en texte suffit, pas besoin d’un outil compliqué.

Supprimer les .php inconnus: la méthode qui évite la casse

La suppression, dans l’absolu, est mécanique. En pratique, c’est un jugement basé sur les preuves.

Pour chaque fichier suspect, je procède généralement comme ceci:

    Je vérifie son emplacement, et s’il est cohérent avec la structure attendue. Je compare sa date de création ou de modification avec les événements récents (mise à jour plugin, accès admin, changement d’hébergement). J’ouvre le fichier et je regarde la logique globale, sans chercher à exécuter le moindre code. Si le fichier est manifestement malveillant ou manifestement hors de son cadre, je le retire. Si le fichier est “ambivalent”, je le mets de côté (par exemple je le déplace dans un dossier temporaire) plutôt que de le supprimer définitivement, le temps de vérifier la page concernée.

Le fait de “déplacer plutôt que supprimer” a un avantage psychologique et technique. Vous réduisez le risque de casser une fonctionnalité. Et si vous réalisez que c’était légitime, vous pouvez le remettre.

Faut-il supprimer aussi le contenu associé en base?

Souvent oui, mais pas au même niveau que les fichiers. Les intrusions laissent des traces dans la base de données, par exemple:

    options modifiées qui modifient des comportements comptes administrateurs ajoutés fichiers injectés via certains mécanismes moins évidents entrées de tables liées à des plugins compromise

Cependant, la suppression des fichiers .php peut déjà arrêter l’exécution. Le script n’est plus là. Ensuite, vous pouvez calmer l’intrusion et investiguer la base. Je recommande cette progression parce qu’elle vous donne une observation concrète: si le site redevient propre après suppression, vous savez que vous avez cassé la chaîne. Si le problème persiste, vous cherchez plus loin.

Vérifier que la compromission ne s’est pas “propagée” autrement

Une désinfection WordPress sérieuse ressemble plus à un examen de scène qu’à une simple suppression. Les attaquants cherchent souvent la persistance. Un fichier supprimé, et ils peuvent avoir laissé:

    un autre fichier à un autre endroit une tâche planifiée (selon l’hébergement) des comptes utilisateurs créés discrètement un accès via des clés API ou des tokens stockés une porte dérobée dans un plugin ou un thème

Vous pouvez éviter beaucoup d’efforts en faisant une vérification ciblée, puis en élargissant si nécessaire.

Signaux typiques qui justifient d’aller plus loin

Sans faire une liste exhaustive, voilà ce qui revient souvent lors de ces incidents:

    redirections vers des domaines externes téléchargement déclenché depuis le front sans interaction claire pages qui changent de contenu de manière intermittente multiplication de fichiers .php récemment ajoutés, surtout dans des dossiers “souvent ignorés” accès admin impossibles, ou connexions qui réussissent malgré vos changements de mots de passe

Si vous observez un de ces motifs, n’hésitez pas à passer en mode “récupération contrôlée”.

Deux contrôles qui font gagner un temps énorme

Sur beaucoup de chantiers, deux contrôles donnent un signal fiable rapidement.

Le premier consiste à comparer vos fichiers avec une version attendue. Cela peut être basé sur un export de votre déploiement précédent, ou simplement sur la connaissance des composants installés. Si un plugin que vous n’utilisez pas contient des fichiers modifiés récemment, c’est une piste. Si un thème que vous avez remplacé récemment possède encore des résidus, c’est aussi une piste. Et si vous voyez des .php dans uploads alors que vous n’ajoutez jamais de code dans ce dossier, il y a presque toujours un problème.

Le second contrôle consiste à inspecter les utilisateurs WordPress. Le but est simple: supprimer la persistance. Changez les mots de passe, et cherchez les comptes qui ont des rôles élevés. Dans beaucoup de compromissions, l’attaquant ne se contente pas d’un webshell. Il veut garder la main, soit par un compte administrateur créé, soit par l’ajout de rôles à un compte existant.

Je vous laisse gérer ces actions selon votre politique interne, mais mon conseil pratique est d’abord de sécuriser l’accès (mots de passe, sessions si votre stack le permet), puis de nettoyer.

image

Plan d’action concret, sans panique

Voici une approche ordonnée, que j’ai https://gardewp.fr/nettoyage-malware-wordpress/ utilisée sur des incidents où l’équipe était sous pression.

1) Coupez la propagation si nécessaire

Si le site redirige ou affiche du contenu malveillant, vérifiez si vous pouvez le mettre en maintenance pendant que vous travaillez. Ça réduit la charge, ça évite que des visiteurs exposés déclenchent des actions imprévues, et ça vous laisse le temps d’analyser tranquillement.

2) Sauvegardez avant de toucher aux fichiers

Copie complète du répertoire WordPress et sauvegarde de base de données. Même si vous pensez “c’est bon”, faites-le. En incident, les “pensées” coutent plus cher que la sauvegarde.

3) Identifiez les .php inconnus par chemin et date

Faites un inventaire rapide, au moins pour ceux qui ont une date de création récente ou qui sont dans des emplacements atypiques. Mettez-les de côté, puis examinez le contenu.

4) Supprimez ou déplacez les fichiers clairement malveillants

Si vous avez un doute sur un fichier, déplacez-le plutôt que de supprimer définitivement, le temps de tester. Si vous êtes sûr qu’il est malveillant, supprimez-le, et documentez son chemin.

5) Vérifiez et nettoyez les persistance côté WordPress

Contrôlez les utilisateurs, les paramètres de plugins, et tout ce qui a pu être modifié. Ensuite seulement, regardez si vous avez aussi besoin de restaurer des fichiers de core ou de plugins.

Ce plan est volontairement “humain”. Il vise à éviter un piège fréquent: passer trop vite à la restauration complète alors que la compromission est peut-être localisée.

Ce que j’ai déjà vu comme pièges (et comment les éviter)

Les désinfections échouent rarement parce qu’on “n’a pas supprimé le bon fichier”. Elles échouent souvent à cause d’un détail de méthode.

Le premier piège: supprimer des fichiers sans comprendre s’ils font partie d’un mécanisme attendu. Un dossier de thème enfant peut contenir des fichiers PHP “d’assistance” qui ne sont pas présents dans le thème parent. Si vous supprimez au hasard, vous cirez une partie du front.

Le second piège: ignorer que WordPress peut recréer des fichiers ou réinstaller des dépendances. Certains plugins, lors de l’activation ou de la mise à jour, créent des assets, ou même des fichiers de cache. Si vous observez de nouveaux .php après suppression, c’est un signal de persistance ou de re déploiement.

Le troisième piège: croire que seule la racine est concernée. Les attaquants adorent uploads, les sous-dossiers de thèmes, et les zones où vous regardez moins souvent. La “bonne” liste de fichiers suspects dépend du comportement de votre site. Un site avec un pipeline CI/CD peut créer des fichiers de manière fréquente, alors qu’un site artisanal peut n’en créer quasiment jamais. Le calendrier aide énormément.

Enfin, il y a le piège émotionnel: vouloir tout régler “d’un coup”. Souvent, un premier cycle de suppression des .php inconnus met fin à l’exécution. Puis vient l’étape d’approfondissement. Ce découpage réduit les erreurs.

image

Sécurité après nettoyage: empêcher le retour

Une désinfection WordPress qui réussit en surface mais qui échoue sur la répétition, c’est le classique “on a supprimé, mais on n’a pas réparé la cause”.

La cause, c’est parfois un mot de passe faible, une exposition d’endpoint, une faille plugin, ou un compromis de comptes via d’autres vecteurs. Je ne vais pas faire de promesse générale, mais il y a des mesures très concrètes qui réduisent drastiquement la probabilité d’une récidive:

    installer les mises à jour WordPress et corriger les plugins à risque fermer les comptes inutilisés et forcer une rotation de mots de passe revoir les accès serveur, limiter les droits, supprimer les comptes FTP inutiles activer une sécurité applicative qui bloque les tentatives évidentes et limite la force brute

Et surtout, surveiller. Après un nettoyage, je garde toujours une période d’observation où je check l’état des fichiers, les logs de l’hébergement, et l’aspect front du site sur plusieurs pages. Les attaques qui persistent le font souvent dans les jours qui suivent.

Mini check avant de remettre le site pleinement en ligne

    Le site s’affiche correctement sur le front et l’espace d’administration Les .php inconnus ont été retirés, ou au moins isolés sans impact fonctionnel Les comptes utilisateurs et les rôles ont été revus Les plugins et thèmes ont été vérifiés, en particulier ceux dont la date de modification est incohérente La surveillance de base est activée le temps de confirmer l’absence de nouvelles modifications

Cette étape est courte, mais elle évite de “relancer” un site qui n’est pas encore stabilisé.

Comment documenter ce que vous avez trouvé (même si personne ne vous le demande)

La documentation n’est pas une formalité. En incident, elle aide à deux choses: retrouver votre raisonnement et accélérer une nouvelle vérification si vous devez reprendre à zéro plus tard.

Je conseille de garder une note par session. Au minimum, notez:

    la liste des fichiers supprimés avec leurs chemins la date de création ou modification observée pourquoi ils étaient considérés comme inconnus le résultat après suppression (front ok, erreur 500, redirection stoppée, etc.) les actions côté WordPress (comptes, plugins, paramètres modifiés)

Une fois, j’ai repris trois semaines plus tard un site sur lequel une précédente intervention avait “supprimé des fichiers”. La seule trace était une capture d’écran floue. Ça a rallongé l’analyse, parce qu’on ne savait pas quels chemins avaient été touchés, et donc ce qui avait pu être oublié. Une note simple aurait évité une demi journée.

Et si vous n’arrivez pas à être sûr à 100 pour cent?

Parfois, le fichier est “suspect”, mais le contenu n’est pas immédiatement lisible, ou bien il y a trop de modifications autour. Dans ces cas, la décision la plus saine consiste à mettre le fichier en quarantaine (le déplacer hors de l’arborescence chargée), tester, puis décider.

Si le site fonctionne sans ce fichier, et qu’il s’agit d’un chemin atypique, vous avez une forte base pour supprimer définitivement. Si le site casse, vous remettez le fichier ou vous investiguez sa fonction. La qualité d’un incident vient du fait qu’on préfère tester plutôt que deviner.

Et si vous n’arrivez pas à stabiliser, une restauration partielle ou totale peut être la seule solution fiable. Mais même là, il faut éviter de restaurer “l’état compromis”. La restauration doit s’appuyer sur une source saine et une période de confiance.

Ce que signifie “suppression” dans une désinfection réelle

Quand on dit “supprimer les fichiers .php inconnus”, on pense souvent que c’est une action binaire. En réalité, c’est un ensemble d’actions:

    isoler les fichiers suspects supprimer ceux qui sont malveillants et confirmés restaurer ceux qui ont été modifiés de façon indésirable vérifier les points de persistance côté WordPress

La suppression est le geste visible. La désinfection, c’est le système complet.

Si vous faites une seule chose, faites en sorte de ne pas casser la compréhension. Retirez proprement, documentez, et vérifiez le comportement. Les attaques WordPress laissent des motifs. Quand vous prenez ces motifs au sérieux, vous retrouvez un site stable, et vous réduisez la probabilité d’un retour.

Si vous voulez, décrivez-moi les emplacements exacts des .php inconnus que vous voyez (chemins complets, noms, tailles approximatives, et date de modification). Je peux vous aider à trier ce qui doit partir en premier, et ce qui mérite une quarantaine avant suppression.