Désinfecter un site WordPress : ma méthode pas à pas

Je dévermine des sites WordPress depuis un petit moment et je sens que j’ai besoin de coucher par écrit la méthode, afin de l’avoir plus facilement à portée de main.

Si cela peut servir à quelqu’un, faites-vous plaisir.

Actions à faire en cas de piratage WordPress illustration

Symptômes d’un site WP infecté

Votre hébergement (OVH au hasard ?) vous a bloqué car votre domaine envoie des emails spams ? Vous avez un captcha hasardeux sur toutes les pages de votre site ? Une pop-up s’affiche demandant une rançon ou un clic frauduleux ? Un compte administrateur s’est invité sur votre site sans que vous sachiez de qui il s’agit ?

Autant de signes qui indiquent une compromission de votre site web, comprendre une intrusion inopinée d’une personne malveillante. Votre site peut alors servir de pierre angulaire pour des envois de mails non sollicités, des arnaques, du phishing… J’en passe et des meilleures.

Rassurez-vous, il n’est pas trop tard. Suivez cette méthode pas-à-pas ou, plus simple, confiez-moi la désinfection de votre site WordPress.

Audit initial

  • Faire un scan avec WPScan, NinjaScanner et Wordfence pour avoir une vue d’ensemble : version de WordPress, plugins, thèmes, utilisateurs exposés, mu-plugins, wp-cron public, readme.html accessible…
  • Trier le bruit (faux positifs) des vrais éléments malveillants.
  • Croiser avec les informations du back-office WordPress, notamment via Outils > Santé du site, afin d’avoir les versions exactes et les vulnérabilités connues.

Analyse des fichiers suspects

  • Cibler en priorité le dossier mu-plugins, premier endroit où les hackers injectent du code persistant car il est invisible dans la liste des plugins et se charge avant les extensions classiques et donc les extensions de sécurité. Cette analyse est forcément manuelle ou assistée, car il n’existe pas de référence en mu-plugins à l’inverse des extensions disponibles dans le repo WordPress.
  • Inspecter le contenu du dossier wp-content/plugins pour vérifier tout dossier inconnu ou avec un nom trompeur.
  • Télécharger les fichiers suspects en local et les analyser manuellement pour comprendre leur fonctionnement ((exfiltration, webshell, C2…) et évaluer l’étendue de la compromission : trojan, backdoor, spam d’emails…
  • Vérifier les fichiers index.php à la racine et dans les sous-dossiers.
  • Vérifier les plugins Premium qui ne peuvent pas être comparés à une référence.

Signes d’infection dans un fichier PHP

Quelques éléments sont récurrents dans du code malveillant :

  • Code eval()
  • Code base64_decode()
  • Code file_get_contents() vers une URL externe
  • Auto-dissimulation (obfuscation) dans la liste des plugins
  • Connexion automatique sans mot de passe (avec possiblement ajout d’un code bypassant le formulaire de connexion)
  • Injection de script dans le head
  • Obfuscation par encodage caractère par caractère via urldecode() et reconstruction de chaîne
  • Variables nommées avec des suites de O et 0 illisibles, signe quasi-certain d’obfuscation automatisée
  • Connexion à un serveur C2 externe pour recevoir des instructions ou du contenu à injecter

Analyse de la base de données

  • Vérifier la base de données pour des injections résiduelles. Les requêtes SQL sont à adapter si le préfixe de la base de données est différent.
SELECT ID, post_title FROM wp_posts 
WHERE post_content LIKE '%eval(%'
OR post_content LIKE '%base64_decode%'
OR post_content LIKE '%adspect%';

SELECT option_name FROM wp_options 
WHERE option_value LIKE '%eval(%'
OR option_value LIKE '%base64_decode%'
OR option_value LIKE '%blog-sitemap%';

SELECT * FROM wp_postmeta 
WHERE meta_value LIKE '%eval(%'
OR meta_value LIKE '%base64_decode%';

SELECT * FROM wp_usermeta 
WHERE meta_value LIKE '%eval(%';

SELECT * FROM wp_comments 
WHERE comment_content LIKE '%eval(%'
OR comment_content LIKE '%base64%';

SELECT ID, user_login, user_email, user_registered 
FROM wp_users 
WHERE ID IN (
    SELECT user_id FROM wp_usermeta 
    WHERE meta_key = 'wp_capabilities' 
    AND meta_value LIKE '%administrator%'
);

Note : la dernière requête permet de lister les administrateurs WordPress, au cas où un malware aurait manipulé l’affichage côté back-office via un hook.

Scan local du contenu du dossier wp-content

  • Télécharger le contenu du dossier wp-content/ en local puis exécuter ces commandes Terminal depuis le dossier wp-content pour rechercher des fichiers suspects :
# Fichiers PHP modifiés après une date de référence
touch -t 202512010000 /tmp/ref_date
find . -name "*.php" -newer /tmp/ref_date > ~/Desktop/scan_recent.log

# Recherches de code malveillant
grep -rl "eval(" . --include="*.php" > ~/Desktop/scan_eval.log
grep -rl "base64_decode" . --include="*.php" > ~/Desktop/scan_base64.log
grep -rl "file_get_contents(\"http" . --include="*.php" > ~/Desktop/scan_fgc.log
grep -rl "system(\|exec(\|passthru(\|shell_exec(" . --include="*.php" > ~/Desktop/scan_shell.log

# PHP dans uploads (il ne devrait y en avoir aucun)
find . -name "*.php"

# Index.php avec du contenu (les légitimes sont vides)
find . -name "index.php" -size +1k > ~/Desktop/scan_index.log

# Htaccess avec du contenu
find . -name ".htaccess" | xargs grep -l "." > ~/Desktop/scan_htaccess.log

Nettoyage post infection

  • Supprimer tous les fichiers malveillants identifiés.
  • Supprimer les thèmes inactifs inutilisés, augmentant même désactivés la surface d’attaque.
  • Supprimer les extensions inutilisées.
  • Mettre à jour tout ce qui est disponible.
  • Réinstaller le core WordPress proprement depuis un téléchargement sain, et le réinjecter dans le FTP hormis le dossier wp-content/ et le fichier wp-config.php.
  • Réinstaller chaque plugin depuis les sources officielles sans réutiliser les fichiers existants, en se servant au besoin de Sucuri.
  • Scanner à nouveau le site avec WPScan, NinjaScanner et Wordfence pour valider le nettoyage.

Sécurisation finale

  • Changer le mot de passe de la base de données et le préfixe avec Brozzme DB Prefix (voire changer de base de données) et mettre à jour le fichier wp-config.php.
  • Remplacer le SALT dans wp-config.php pour forcer la reconnexion de tous les utilisateurs.
  • Provoquer un reset des mots de passe de tous les comptes administrateurs et forcer le 2FA via Wordfence.
  • Sécuriser l’installation WordPress.

Conclusion

Un site WordPress n’est pas infaillible. Les causes d’intrusion sont multiples : extension vulnérable mise à jour trop tard, compte administrateur et mot de passe cassé par brute-force, accès non autorisé à la base de données….

L’important est de pouvoir se débrouiller pour retrouver son site web sans trop de bobos. Si vous avez besoin d’un coup de main pour désinfecter votre site WordPress, faites-moi signe.