Supprimer un malware WordPress sans perdre le contenu
Comparer le cœur et les extensions aux zips officiels, retirer les ajouts, conserver uploads (médias) et base. Un scan qui « répare » 200 fichiers en un clic en casse souvent quinze — surtout un thème enfant.
Comparer cœur et extensions officielles, retirer les ajouts, conserver uploads et base. Un scan qui « répare » 200 fichiers en un clic en casse souvent 15.
Ce qu'on garde, ce qu'on remplace
On remplace ce qui a un original : `wp-admin`, `wp-includes`, les plugins du répertoire, le thème parent marketplace. On conserve ce qui est unique : `wp-content/uploads` (images), la base (pages, commandes), le thème enfant, le `wp-config.php` relue ligne à ligne — on ne le télécharge pas depuis un tutoriel au hasard.
Réinstaller « à neuf » et réimporter un XML perd les commandes Woo, les ACF, les formulaires. Comparer coûte moins cher que reconstruire.
Toujours après une copie hors serveur. Par où commencer.
Décidez avant d'ouvrir le FTP ce qui a un original (cœur, plugins du repo, thème parent) et ce qui est unique (uploads médias, base, enfant, wp-config relu). Les scanners « réparent » les deux de la même façon : c'est ainsi qu'un thème enfant perd trois ans de CSS et qu'un `cache.php` pirate survit dans un plugin. La copie hors serveur n'est pas négociable : sans elle, le clic repair n'a pas de filet. Par où commencer.
Le cœur : zip contre disque
Téléchargez le zip de votre version exacte (pas « la dernière » si vous n'êtes pas prêt à migrer PHP). Écrasez `wp-admin` et `wp-includes`. À la racine, remplacez les PHP du cœur (`wp-login.php`, `xmlrpc.php`, `wp-settings.php`…) mais pas `wp-config.php`, pas `.htaccess` sans le lire, pas `wp-content`.
Un `index.php` de racine doit faire quatre lignes et charger `wp-blog-header.php`. Dix kilooctets de plus : ouvrez-le.
Téléchargez le zip de votre version exacte, pas « la dernière » si vous n'êtes pas prêt à migrer PHP. Écrasez wp-admin et wp-includes. À la racine, remplacez les PHP du cœur, pas wp-config, pas .htaccess sans le lire, pas wp-content. Un index.php de racine doit faire quatre lignes ; dix Ko de plus : ouvrez-le.
Plugins : officiel, abandonné, inconnu
Pour chaque extension du répertoire : zip officiel de la même version, ou mise à jour après le clean si la faille est connue. Les fichiers en trop dans le dossier du plugin (un `cache.php` qui n'existe pas sur wp.org) : dehors.
Abandonnée (plus de 2 ans, plus de repo) : on ne « répare » pas, on remplace la fonction, on retire le dossier. Inconnue (nom aléatoire) : isolement, pas « réparer ».
File Manager, duplicator installer, old contact form add-on : portes. File Manager, CF7.
Thème parent, thème enfant
Parent : zip éditeur. Enfant : ne pas écraser. Lire `functions.php` et les fichiers datés le jour de l'incident. Un `eval` n'est pas votre CSS.
Nulled : on sort. Même si « ça faisait le job ». Une copie du payload est souvent déjà en mu-plugin. Thème nulled.
La base : options et posts, pas un dump aveugle
`wp_options` : `siteurl` / `home` (redirection admin), widgets, theme_mods, options Yoast, extraits `script` / `iframe`. Une passe SQL « delete %script% » casse le site. Cherchez des domaines étrangers, du `base64`, des `eval`.
`wp_posts` : contenus injectés, révisions. Les users extra. Woo : webhooks, clés REST. WooCommerce.
Ne restaurez pas un dump d'il y a six mois « pour être sûr » : vous perdez les commandes. Nettoyez le dump actuel.
wp_options : siteurl/home, widgets, theme_mods, Yoast, extraits script/iframe. Une passe delete %script% casse le site. wp_posts et révisions. Users extra. Woo : webhooks, clés REST. Ne restaurez pas un dump de six mois : vous perdez les commandes.
Uploads : médias oui, PHP non
Ne videz pas `uploads`. Vous perdez le site visuellement. Cherchez les PHP et doubles extensions, retirez-les, interdisez l'exécution. `.php.jpg` n'est pas une photo. PHP dans uploads.
Les `.html` de pharmacies dans un sous-dossier : 410 après retrait. Les `.htaccess` locaux qui forcent le PHP sur les images : retirez ces règles.
Le piège « tout réparer »
Wordfence / Imunify « repair » remplace par une signature. Sur un thème enfant ou un plugin sur mesure, c'est une perte de métier. Triez : cœur comparable, plugin comparable, fichier inconnu, faux positif. Wordfence 80 fichiers.
Un scan Sucuri distant vert après ça ne dit pas que le mu-plugin est parti. Sucuri ensuite.
Wordfence / Imunify repair remplace par une signature. Sur un enfant ou un plugin maison, c'est une perte de métier. Un Sucuri distant vert après ça ne dit pas que le mu-plugin est parti. Sucuri ensuite.
Refermer avant de republier
Mots de passe dans l'ordre, clés AUTH, plus de File Manager, PHP uploads interdit, extensions à jour ou retirées, PHP supporté. PHP obsolète.
Puis seulement les listes Google. Blacklist. Délégation : créer un espace.
Refermez avant de republier : mots de passe dans l'ordre, clés AUTH, plus de File Manager, PHP uploads interdit, extensions à jour ou retirées, PHP supporté. Puis seulement les listes Google. Blacklist. Délégation : créer un espace.
Permissions, cron, et ce qu'on ne restaure pas
Après le tri : fichiers 644, dossiers 755, wp-config 640 si l'hébergeur le permet. Le 777 « pour que ça marche » est une invitation. Cron WordPress et cron système : un `wget` vers un PHP retiré le recrée. Demandez la crontab du panel.
Updraft, Ai1WM, Duplicator : sortez les archives du webroot. La dernière sauvegarde contient souvent le backdoor. On remonte à un point propre, on compare, on ne restaure pas « la dernière » par réflexe. Duplicator.
Puis PHP supporté et WP à jour, dans cet ordre-là une fois le disque comparable. PHP obsolète. Créer un espace.