Désinfection WordPress : audit des tables WP sensibles
Quand on parle de désinfection WordPress, on pense souvent au plugin malveillant, au thème compromis, ou à un fichier injecté dans le dossier racine. C’est normal, parce que ce sont les pièces les plus visibles. Mais, dans beaucoup d’incidents réels, le “cœur” de la compromission se loge aussi dans la base de données. Et plus précisément dans certaines tables WordPress, où l’on retrouve à la fois des traces d’injection et des mécanismes de persistance.
Mon point de vue vient de chantiers où le site semblait propre côté fichiers, mais où tout redevient sale quelques heures après un nettoyage. La cause, souvent, était dans le SQL, dans l’architecture habituelle de WordPress, ou dans des tables “autres que wp_” qui ont été ajoutées au fil du temps. D’où l’importance de faire un audit des tables WP sensibles avant de lancer la désinfection, ou pendant qu’on la mène.
Pourquoi la base de données devient un terrain de persistanceWordPress est un CMS orienté contenu, donc tout passe par des tables. Certaines gèrent le contenu (articles, pages, contenu des médias), d’autres gèrent les métadonnées, les https://gardewp.fr/ utilisateurs, les catégories, les options de configuration. Tant que la base reste cohérente, le site se comporte normalement.
Quand un attaquant prend la main, il cherche deux choses: exécuter du code sans laisser de fichiers évidents, et revenir au propre dès qu’on supprime la couche externe. Dans la pratique, ça se traduit par des injections dans les champs de contenu (par exemple du HTML ou du JavaScript), par l’ajout de comptes administrateurs cachés, et par des entrées “options” ou “transients” qui déclenchent des comportements au prochain appel de page.
Même quand il y a des fichiers webshell visibles, l’attaque se nourrit parfois de données base. C’est là que l’audit des tables sensibles devient indispensable, parce qu’il permet de comprendre ce qui déclenche quoi.
Les tables sensibles à surveiller en prioritéJe parle “sensibles” parce qu’il ne s’agit pas d’une liste universelle gravée dans le marbre. Selon votre historique, votre version WordPress, et les plugins installés, certaines tables sont plus exposées. En revanche, plusieurs familles reviennent régulièrement.
Tables de contenu et métadonnées wp_posts (articles, pages, révisions, pièces jointes) est souvent le premier endroit où l’on voit des contenus injectés. Le site peut sembler normal, mais certaines pages ou révisions contiennent un payload. Parfois, seule une meta clé déclenche un affichage. wp_postmeta héberge les métadonnées associées aux publications. C’est un point chaud pour les effets “fantômes”: un plugin ou une fonctionnalité est déclenchée par une meta spécifique, même si aucun fichier n’a l’air modifié. wp_comments peut aussi porter des charges malveillantes via contenu de commentaire, parfois avec des redirections ou du spam SEO. La désinfection passe alors par validation, nettoyage, et par une analyse des patterns.Ce qui trompe, c’est que l’injection peut ne pas être visible immédiatement. WordPress filtre certains champs, et le rendu dépend du template, du thème, et de la manière dont le contenu est “appelé”. Une petite injection dans un endroit précis peut suffire.
Tables d’utilisateurs et droits wp_users et wp_usermeta sont une autre zone critique. L’ajout d’un utilisateur admin ou de droits escaladés est une méthode de persistance très fréquente. Plus insidieuse encore: des rôles modifiés, des capacités supplémentaires dans user_meta, ou une modification d’identifiants. Les attaques passent parfois par une session ou un compte existant, puis elles stabilisent l’accès en ajustant user_meta et en créant des entrées de mise à jour, d’activation, ou de tokens.Sur des sites multi-auteurs, ou sur des installations où l’historique est dense, on peut avoir des comptes “légitimes” qui ressemblent à des anomalies. La clé est de recouper, pas de juger uniquement sur la présence d’une valeur.
Tables de configuration et d’exécution wp_options est souvent le coffre-fort des réglages qui pilotent des comportements. On y trouve des éléments du core et des plugins, des caches, des réglages, et parfois des fragments qui déclenchent du code. Ce n’est pas “le code” au sens PHP, mais des valeurs qui orientent la sortie HTML ou la logique applicative. wp_actionscheduler_actions et wp_actionscheduler_logs existent si vous utilisez certains systèmes de planification (souvent le cas avec des plugins de tâches). Ils peuvent contenir des hooks exécutés de manière répétée. Dans une désinfection WordPress sérieuse, on ne peut pas ignorer ce planificateur si le site “remet du sale” de lui-même.Attention, là encore: vider wp_options au hasard est une mauvaise idée. On gagne du temps sur le papier, on perd des heures ensuite.
Tables taxonomie et navigation wp_terms, wp_term_taxonomy, wp_term_relationships et parfois wp_termmeta (selon votre environnement et vos plugins) sont moins “code-exécutif”, mais ils sont utilisés dans des attaques SEO: création de taxonomies “bizarres” ou pages d’archives qui redirigent. Le site peut alors publier automatiquement des pages “propres” visuellement, mais orientées vers autre chose.Je les surveille surtout quand je vois des patterns d’URL ou des changements inexpliqués dans la structure du site.
Ce que vous cherchez réellement pendant l’auditUn audit SQL efficace n’est pas un “grand nettoyage”. C’est une lecture ciblée des signaux: valeurs anormales, incohérences, dates qui ne collent pas, contenus qui déclenchent une transformation à l’affichage.
Sur le terrain, je me fixe trois objectifs.
Premièrement, repérer ce qui sert à persister. Un payload réapparaissant après nettoyage indique une source dans la base, dans un planificateur, ou dans une automatisation plugin.
Deuxièmement, repérer les points d’exécution. Par exemple une option qui déclenche un hook, une meta clé consommée par le thème, ou une action programmée. La valeur brute n’est pas suffisante, il faut comprendre comment elle est utilisée.
Troisièmement, mesurer l’impact. Si seulement 2 pages sur 300 contiennent une injection, on ne traitera pas la base entière comme si tout était compromis.
Méthode pragmatique pour auditer sans casserUn risque fréquent lors d’une désinfection WordPress est de “toucher” trop tôt. On commence à modifier des tables avant d’avoir isolé le mécanisme. Résultat, on supprime quelque chose qui était utile au fonctionnement, et l’incident se transforme en autre incident.
La méthode que j’utilise, surtout sur des hébergements mutualisés ou avec accès limité au terminal, consiste à:
Préparer une copie de la base (au minimum un export logique, idéalement un backup complet). Identifier l’origine du comportement malveillant côté front (quelles pages, quels patterns d’URL, quels moments de réapparition). Faire un audit orienté “lignes suspectes”, plutôt que des suppressions massives.Si vous n’avez qu’un accès phpMyAdmin ou un client SQL basique, c’est encore plus important, parce que les requêtes doivent rester simples et explicables.
Une mini-checklist avant de lancer les requêtes Vérifier que vous disposez d’un export de la base avant toute modification Rechercher les comptes utilisateurs récents ou créés sans équipe interne Contrôler les wp_posts récents, surtout les statuts et types (révisions incluses) Inspecter wp_options pour les clés d’origines plugins inconnues ou récentes Chercher des entrées planifiées si votre site utilise un scheduler via pluginsCette liste ne remplace pas une stratégie, mais elle évite la séquence “on nettoie, puis on comprend”.
Cas concrets d’anomalies dans les tables WordPressLes attaques ne se ressemblent pas, mais elles se comportent souvent de façon répétitive. Voici quelques cas typiques, avec la logique derrière le symptôme.
1) Des contenus injectés dans wp_posts et wp_postmetaVous voyez des pages qui affichent du texte illisible, ou des redirections via JavaScript. En audit, on découvre que certaines entrées dans wp_posts ont un champ post_content contenant des scripts ou des balises inhabituelles. Parfois, le contenu est “propre” dans post_content, mais un fragment apparaît dans une meta.
Dans wp_postmeta, le couple clé-valeur est le point de décision. Une meta clé peut être “utilisée” par un thème ou un plugin (par exemple via affichage de bloc, shortcode custom, ou logique conditionnelle). Dans ce cas, supprimer le contenu visible ne suffit pas, car la meta réinjecte le comportement.
Ce que je fais dans ce scénario, c’est comparer les entrées suspectes avec des entrées proches: même type, même auteur, même période. On cherche la rupture, pas juste une valeur isolée.
2) Un compte admin ajouté, ou des rôles gonflés via wp_usermetaQuand le site est “désinfecté” mais repasse en compromis, je regarde toujours la couche accès. wp_users peut montrer un utilisateur fraîchement créé avec un email qui ressemble à du spam, ou un nom d’utilisateur étrange.
Mais le plus piégeux, ce sont les modifications dans wp_usermeta. Un utilisateur existe depuis longtemps, mais ses capacités ont été ajoutées. Un attaquant peut alors se connecter, déclencher un mécanisme de réécriture des données, puis disparaître.
Dans ce cas, l’audit consiste à:
établir une chronologie de création des utilisateurs vérifier les rôles effectifs, pas seulement les champs “affichables” repérer les entrées meta “récentes” ou incompatibles avec le comportement normal 3) wp_options qui déclenche du contenu au prochain chargementOn voit parfois une URL qui renvoie un contenu différent selon l’heure, ou un changement qui apparaît après un cron. Là, l’option devient un suspect. C’est particulièrement vrai si les options “transient” ou “cache-like” contiennent des chaînes qui ne devraient pas être stockées ainsi.
Le piège, c’est de confondre normal et anormal. Beaucoup de plugins stockent des structures en option, parfois sérialisées. On ne peut pas conclure en voyant du texte. L’audit doit être “contextuel”: quelle clé, quelle date, quelle taille, et comment cela se traduit dans l’affichage.
4) Des tâches planifiées, avec Action Scheduler ou équivalentsSur WordPress, les cron internes et certains plugins planifient des actions. Une désinfection WordPress doit donc englober ce planificateur. Si un attaquant a ajouté une tâche qui poste du contenu, modifie une option, ou réécrit des pages, vous pouvez nettoyer les fichiers et la base, et voir l’infection revenir au prochain cycle.
Dans l’audit, je recherche les tâches créées récemment, associées à un hook non standard, et je vérifie aussi les logs s’ils sont accessibles. Le but n’est pas seulement de supprimer, c’est de comprendre si la désinfection doit aussi supprimer le plugin ou seulement les entrées malveillantes.
Comment interpréter ce que vous trouvez (sans tomber dans l’auto-piège)Quand vous voyez une valeur suspecte, il est tentant de la supprimer immédiatement. Sur une base WordPress, ce réflexe peut casser des fonctionnalités. WordPress utilise parfois des structures sérialisées dans wp_options ou des métadonnées qui peuvent être nécessaires au plugin.
L’approche la plus sûre, que j’adopte quand le site est en production et que le temps compte, c’est:
tester sur un environnement de restauration si c’est possible sinon, procéder par “élimination” avec prudence, en gardant des traces de ce qui change garder les requêtes reproductibles pour pouvoir revenir en arrièreUne désinfection WordPress propre repose autant sur la méthode que sur le nettoyage. Une suppression aveugle peut faire disparaître le symptôme, mais pas la cause. Et parfois elle aggrave le problème en cassant la mécanique du site, ce qui rend l’incident suivant plus difficile à diagnostiquer.
Requêtes d’audit utiles, avec un esprit de retenueJe ne vais pas vous donner une recette unique de requêtes (elle doit s’adapter à vos préfixes de tables, à votre version et à vos plugins), mais je peux décrire les catégories de requêtes qui donnent des résultats.
Vous cherchez généralement:
des enregistrements “récents” par rapport à la date du premier incident des chaînes contenant des marqueurs courants de payload (balises script, patterns de redirection, encodages bizarres) des entrées dont la taille est anormalement grande par rapport aux voisins des incohérences entre auteurs, dates, et contenus typiques du siteSur WordPress, les révisions peuvent tromper l’œil. Un article “propre” peut avoir une révision “sale”. Selon le thème et les mécanismes de sauvegarde, l’affichage peut remonter une révision. Donc l’audit doit aussi inclure les entrées de type révision, au moins quand le site a commencé à afficher du contenu de façon inattendue.
Les pièges courants pendant la désinfection via la baseIl y a des erreurs qui reviennent sur quasiment tous les audits, même quand l’équipe est compétente.
1) Copier des suppressions “sur internet” sans contexteUne requête du type “supprimer tout ce qui contient ” peut avoir des effets secondaires. Un site peut contenir du code JavaScript légitime dans un contenu. La différence se fait dans l’origine, dans l’emplacement, et dans le fait que ce code apparaît après l’incident.
2) Ignorer les plugins de planification ou les tables ajoutées
Beaucoup de sites ne se limitent pas aux tables wp_... standard. Un plugin crée ses propres tables, parfois préfixées avec wp_, parfois pas. Si l’attaque passe par un plugin compromis, les entrées de persistance ne seront pas forcément dans wp_posts ou wp_options.
3) Traiter la base sans traiter l’accès
Si le vecteur d’intrusion initial n’est pas corrigé, l’audit devient un travail répétitif. Une désinfection WordPress “par la base” sans sécuriser l’espace d’accès (mots de passe, rôles, durcissement, limitations d’accès, mise à jour des composants) finit par échouer. La base peut être propre ce matin, sale demain.
Exemple de diagnostic en conditions réellesJe repense à un site vitrine où l’équipe signalait des redirections vers des pages externes. Les fichiers semblaient cohérents, le thème n’avait pas bougé sur la fenêtre visible. Le scan de fichiers donnait peu de résultats.
L’audit de base a révélé plusieurs entrées wp_posts de type page, créées à un intervalle de temps précis, avec un post_content qui contenait des fragments HTML dont l’apparence était presque “banale”. Le gros du problème n’était pas le contenu visible, c’était la manière dont le thème intégrait certains champs via une logique conditionnelle.
En parallèle, un compte admin avait été ajouté, puis supprimé à une heure différente. Le compte lui-même avait disparu, mais l’effet persistait parce qu’une option et des métadonnées avaient déjà été enregistrées. Une fois ces entrées retirées et le mécanisme d’escalade corrigé, le site est resté stable.

Le point à retenir est simple: la base a parfois une mémoire de l’attaque, même quand la porte d’entrée ne l’est plus.
Quoi vérifier après l’audit, pour valider la désinfectionUne fois les tables sensibles examinées et les entrées suspectes traitées, il faut confirmer. Le “propre” doit se mesurer, pas se supposer.
Je valide généralement avec:
- Une navigation réelle sur les pages affectées, y compris en navigation privée
- Une vérification de la présence de comptes à privilèges inattendus
- Un contrôle que les actions planifiées suspectes ne tournent plus
- Une observation du comportement sur plusieurs cycles (pages chargées, réapparition éventuelle après quelques heures)
Sur un site qui redevient compromis vite, la validation à froid ne suffit pas. Il faut une fenêtre d’observation. Sans inventer de délais, l’objectif est de couvrir le rythme de l’attaque, souvent lié aux cron, aux caches, ou à un bot.
Sécuriser pour que l’audit serve vraimentL’audit des tables sensibles est une étape de désinfection WordPress, pas une fin. Si vous ne traitez pas ce qui a permis l’injection, la base redeviendra le théâtre de la persistance.
Concrètement, je m’assure que les contrôles suivants sont en place côté accès, mises à jour et durcissement. Les détails varient selon votre stack, mais l’idée reste la même: empêcher la réintroduction.
- Mettre à jour WordPress, le thème, et les plugins, y compris ceux dont on ne sait pas vraiment “à quoi ils servent” aujourd’hui
- Révoquer les comptes non nécessaires, surtout ceux qui ont des accès trop larges
- Vérifier les logs de connexion et l’historique d’administration quand c’est disponible
- Contrôler les mécanismes de cron et les plugins de planification
- Revoir les pratiques d’authentification, notamment si des identifiants ont été exposés
Cette partie ne concerne pas seulement la base. Elle concerne le système complet, parce que la base reflète l’attaque, mais elle ne la crée pas.
Conclusion implicite: l’audit, c’est l’anti-surpriseQuand on fait une désinfection WordPress, on gagne énormément de sérénité en traitant la base avec la même attention que les fichiers. Les tables sensibles, wp_posts, wp_postmeta, wp_users, wp_usermeta, wp_options, et parfois les tables liées à la planification ou aux plugins, sont souvent là où la persistance se cache.
L’intérêt n’est pas de “tout nettoyer”, l’intérêt est d’identifier le mécanisme, puis de le couper proprement. Une base saine, ce n’est pas seulement l’absence de malice, c’est la cohérence entre ce que le site affiche et ce que ses données disent réellement.
Si vous commencez par l’audit, vous évitez de courir après des symptômes. Vous agissez sur la cause, et vous réduisez le risque de réapparition, ce qui, sur un site WordPress, vaut largement le temps d’analyse supplémentaire.