Contexte : analyse passive du site d'une PME du bassin transfrontalier Lille / Mouscron / Estaimpuis, secteur sensible (services de sécurité). Site WordPress + Elementor sur hébergement mutualisé. Approche : pentest passif, aucun bruteforce, aucune tentative d'intrusion, uniquement des outils qui listent ce qui est déjà accessible publiquement (dirsearch, WPScan en mode passif, analyse manuelle). 5 findings remontés : R1 fichiers et endpoints DB exposés (Critique), R2 interface phpMyAdmin accessible sans authentification (Critique), R3 divulgation via l'API REST WordPress /wp-json/wp/v2/users/ avec hash MD5 des emails admin (Élevée), R4 archive web.zip à la racine avec code source + dump SQL + identifiants (Critique), R5 plugins WordPress obsolètes dont Elementor, Yoast SEO (Élevée). Impact démontré : compromission complète du site, reconstitution de l'environnement, base clients lisible, pivot vers messagerie et ERP crédible. Remédiation : responsible disclosure au dirigeant, suppression du web.zip, coupure de phpMyAdmin publique, restriction de l'API REST, mise à jour des plugins, blocage global des extensions de sauvegarde au niveau serveur, revue de la politique de backup.
Le contexte
Une PME du bassin transfrontalier Lille / Mouscron / Estaimpuis, activité orientée services de sécurité privée. Le site sert de vitrine commerciale et de point d'entrée pour les demandes de devis. Stack technique : WordPress avec Elementor et Elementor Pro, plusieurs plugins additionnels dont Yoast SEO et Essential Addons for Elementor Lite. Hébergement mutualisé standard. Pas d'équipe IT interne, maintenance déléguée à un prestataire externe.
La démarche est encore plus légère qu'un pentest classique : c'est une analyse passive dans une logique de sensibilisation, sans mandat de test actif. Aucun compte fourni, aucune tentative d'intrusion, aucun bruteforce. On regarde uniquement ce qui est déjà exposé publiquement à un attaquant qui passe par là, avec des outils qui ne font que lister ce que le serveur accepte de renvoyer. C'est le niveau zéro de l'effort côté attaquant : tout ce qui remonte de cette analyse est déjà exploitable par n'importe qui armé d'un navigateur et de dix minutes de temps.
Analyse passive : les outils utilisés
Le premier réflexe sur ce type de mission est banal mais rentable : cartographier la surface exposée. Sous-domaines, endpoints, technologies utilisées, headers de sécurité, cookies, formulaires. WPScan en mode passif remonte immédiatement le fingerprint WordPress, la version du core, les plugins visibles (Elementor 3.28.0, Elementor Pro 3.13.2, Yoast SEO 24.6, Essential Addons for Elementor Lite) et les utilisateurs exposés via l'API REST.
En parallèle, dirsearch lance un scan de content discovery sur une wordlist orientée fichiers sensibles : web.zip, site.zip, backup.zip, www.zip, prod.zip, dev.zip, old.zip, admin.zip, save.zip, mais aussi les variantes .tar.gz, .sql, .bak, .7z, les patterns typiques de dev (.git/config, .env, .htaccess.bak) et les chemins d'administration classiques (/phpmyadmin, /pma, /adminer, /wp-admin). C'est un test qui coûte 5 minutes de setup et rapporte régulièrement des trouvailles majeures. Aucune tentative de login, aucun bruteforce : uniquement des requêtes HTTP GET qui listent ce que le serveur accepte de renvoyer.
Découverte 1 : phpMyAdmin exposé sans authentification
Le scan dirsearch remonte d'abord un chemin qui n'aurait jamais dû être public :
/phpmyadmin/ [Status: 200, Size: 24118]
Un accès direct à l'interface phpMyAdmin, servie sans authentification préalable au niveau serveur. CWE-306 (Missing Authentication for Critical Function). L'interface est publique, indexable, et n'importe quel attaquant peut aller y tenter les credentials par défaut, un bruteforce lent, ou attendre qu'une CVE phpMyAdmin sorte pour exploiter directement. On ne teste pas de login (pentest passif, cadré) mais la présence de l'interface est en soi le finding : cette porte n'aurait jamais dû être accessible depuis Internet.
Découverte 2 : divulgation via l'API REST WordPress
WPScan et un simple curl sur /wp-json/wp/v2/users/ remontent la liste des utilisateurs du site, avec pour chacun :
$ curl -s https://target.tld/wp-json/wp/v2/users/ | jq
[
{
"id": 1,
"name": "admin_pme",
"url": "",
"description": "",
"link": "https://target.tld/author/admin_pme/",
"slug": "admin_pme",
"avatar_urls": {
"24": "https://secure.gravatar.com/avatar/<md5_email>?s=24",
"48": "https://secure.gravatar.com/avatar/<md5_email>?s=48"
}
}
]
CWE-200 (Information Exposure), OWASP A01:2021. L'URL de l'avatar Gravatar contient le hash MD5 de l'email de l'administrateur. MD5 étant cassé depuis 20 ans, un attaquant récupère ce hash, le passe à hashcat sur un dictionnaire d'emails plausibles pour le domaine (info@, contact@, direction@, prenom.nom@), et sort l'email admin en clair. Prêt pour du phishing ciblé, du password reset abuse, ou du bruteforce d'auth.
Découverte 3 : le fichier web.zip à la racine
Quelques secondes plus tard, dirsearch remonte la ligne qui fait toujours plaisir :
/web.zip [Status: 200, Size: 34521804]
Un fichier zip de plusieurs dizaines de mégaoctets, code HTTP 200, servi directement sans authentification. Téléchargement en 20 secondes. CWE-552 (Files or Directories Accessible to External Parties), OWASP A05:2021.
$ file web.zip
web.zip: Zip archive data, at least v2.0 to extract
$ unzip -l web.zip | head
Archive: web.zip
Length Date Time Name
--------- ---------- ----- ----
4278 2025-06-14 14:22 www/wp-config.php
8102 2025-06-14 14:22 www/wp-content/plugins/
12844 2025-06-14 14:22 www/wp-content/themes/
16220 2025-06-14 14:22 www/backups/db_prod.sql
...
C'est le backup complet du répertoire web WordPress. Pas une partie, pas un ancien fichier oublié : le site actuel, tel qu'il tourne en production, empaqueté et laissé à la racine du serveur.
Le fichier a très probablement été créé par le prestataire lors d'une intervention de maintenance. Un développeur qui voulait faire une sauvegarde avant modif, qui a lancé un zip -r web.zip www/ depuis le répertoire parent, et qui a oublié de le supprimer une fois la modif validée. Le nom web.zip est tellement banal qu'il ne saute pas aux yeux dans une revue rapide du répertoire. Mais il saute aux yeux du premier scan qui tourne dessus.
Ce qu'il y avait dans le zip
L'archive contenait le tree WordPress complet. Le premier fichier qu'on ouvre, systématiquement, c'est wp-config.php. Ici, la valeur exemple :
<?php
// ** MySQL settings ** //
define( 'DB_NAME', 'prod_pme' );
define( 'DB_USER', 'admin_pme' );
define( 'DB_PASSWORD', 'P@ssw0rd-2024!' );
define( 'DB_HOST', 'localhost' );
// ** Authentication Unique Keys and Salts. ** //
define( 'AUTH_KEY', 'redacted...' );
define( 'SECURE_AUTH_KEY', 'redacted...' );
define( 'LOGGED_IN_KEY', 'redacted...' );
define( 'NONCE_KEY', 'redacted...' );
Quelques lignes qui donnent tout : accès direct à la base MySQL en local sur le serveur, et pour peu que la base soit accessible depuis l'extérieur (fréquent en mutualisé), accès direct sans passer par le site. Les clés d'authentification et salts WordPress fuités permettent en plus de forger des cookies de session valides pour n'importe quel compte connu, sans avoir besoin du mot de passe.
Dans le sous-répertoire backups/ de l'archive traîne un dump SQL complet de la base db_prod.sql. À l'intérieur, la table wp_users avec les identifiants de tous les comptes, y compris les administrateurs. Les mots de passe sont hashés avec phpass, cassable au dictionnaire sur GPU, avec un rendement acceptable si les mots de passe ne sont pas robustes. Le dump contient aussi l'ensemble des données clients : leads, formulaires de contact remplis depuis des mois, emails, numéros de téléphone, historique des devis demandés.
wp_users présent dans le zip : chaque ligne contient un identifiant, un email et un hash phpass legacy WordPress cassable au dictionnaire sur GPU consumer.La réutilisation des mots de passe est le multiplicateur d'impact ici. Un mot de passe admin cassé sur le WordPress ouvre la porte à la messagerie professionnelle, à l'ERP, aux comptes d'hébergement, à tout ce qui partage le même mot de passe chez l'utilisateur concerné. C'est le scénario classique de propagation post-compromission.
Découverte 4 : plugins WordPress obsolètes
WPScan en mode passif dressait la liste des plugins et de leurs versions. Rien à faire côté attaquant à ce stade : la donnée est publique via les commentaires HTML ou les fichiers readme.txt non nettoyés. CWE-937 (Using Components with Known Vulnerabilities), OWASP A06:2021.
- Elementor v3.28.0 : dernière version 3.28.3 à date d'audit. CVE potentielles connues.
- Elementor Pro v3.13.2 : version identifiée comme ancienne, gap important.
- Yoast SEO v24.6 : dernière version 24.8.1.
- Essential Addons for Elementor Lite : version non déterminée, historique connu de failles.
La combinaison "code source du site en clair (via web.zip) + plugin obsolète avec CVE publique" est particulièrement dangereuse : l'attaquant a la structure exacte de la stack, il sait quels endpoints tester, et il n'a plus qu'à chaîner la CVE publique avec les credentials du fichier de config.
Responsible disclosure au dirigeant
Sur ce type de finding, la démarche relève du responsible disclosure classique. La cible n'était pas cliente, l'analyse était menée dans une logique de sensibilisation externe (le fait de vérifier ce qui est publiquement exposé sur un site n'est ni intrusif ni illégal). Une fois le web.zip identifié, contact direct avec le dirigeant dans les deux heures pour expliquer, en clair et sans jargon inutile : un fichier de sauvegarde du site est publiquement accessible, il contient le code source complet, la base et les mots de passe, il faut agir maintenant. Confirmation par mail avec URL exacte, taille, extrait masqué du contenu, et actions immédiates recommandées.
Le rapport complet (référence R_AC_ v1.0, format standard HackHeart) est remis dans les jours qui suivent avec la liste des 5 findings, leurs CWE et catégories OWASP, la description technique, l'analyse de risque (technique, réputationnel, financier, légal), et les recommandations de remédiation par ordre de priorité. La remédiation démarre le jour même.
La remédiation recommandée
Suppression du fichier web.zip dans l'heure qui suit l'alerte. Ce n'est que le premier pas, et le moins important : si un attaquant l'a déjà récupéré, la donnée est dehors. Le vrai travail commence après.
Recommandations formulées, par ordre de criticité :
- Suppression immédiate du web.zip et scan complet des variantes classiques (
site.zip, backup.zip, www.zip, prod.zip, old.zip, wp-content.zip) pour vérifier qu'aucun autre backup n'est exposé. - Rotation complète des credentials exposés dans le zip : mot de passe MySQL, clés WordPress (
AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY), rotation forcée des mots de passe de tous les comptes utilisateurs (invalidation des sessions actives en changeant les salts). - Coupure de l'exposition publique de phpMyAdmin : soit désinstallation, soit restriction par IP au niveau serveur, soit ajout d'une authentification HTTP Basic devant l'interface. Aucun outil d'administration DB ne doit être directement accessible depuis Internet.
- Restriction de l'API REST WordPress aux seuls utilisateurs authentifiés, ou désactivation des endpoints inutiles (au minimum
/wp-json/wp/v2/users/). Un plugin de type Disable REST API ou une règle dansfunctions.phpsuffit. - Mise à jour de l'ensemble des plugins WordPress vers leur dernière version stable : Elementor, Elementor Pro, Yoast SEO, Essential Addons for Elementor Lite. Mise en place d'un cycle de mises à jour mensuel documenté.
- Blocage global des extensions de sauvegarde au niveau serveur, avec une règle qui coupe la classe entière du problème :
Peu importe qu'un dev laisse traîner un fichier de sauvegarde à l'avenir : le serveur ne le servira jamais.# Nginx location ~* \.(zip|tar|gz|7z|bak|old|sql|swp|save|orig)$ { return 404; access_log off; } # Apache (.htaccess) <FilesMatch "\.(zip|tar|gz|7z|bak|old|sql|swp|save|orig)$"> Require all denied </FilesMatch> - Politique de sauvegarde revue : plus aucun backup ne doit se retrouver dans un répertoire servi par le serveur web. Les sauvegardes sont poussées vers un espace de stockage privé (S3 avec bucket policy, NAS local, cloud dédié).
Le rapport souligne également que ces mesures immédiates ne constituent pas à elles seules une stratégie de sécurité complète : elles corrigent les points critiques visibles mais laissent intactes les vulnérabilités logiques métier, la configuration serveur profonde, les erreurs de code custom. Un pentest complet (actif, avec cadrage formel) reste recommandé pour couvrir la surface non visible en analyse passive.
L'analyse de risque
Le rapport livré au dirigeant catégorise l'exposition sur trois axes :
Risques techniques. Compromission complète du site via l'exposition combinée du web.zip (code source et credentials) et de phpMyAdmin (accès direct à la base). Escalade d'accès crédible vers la messagerie et l'ERP si les mots de passe admin sont réutilisés (cas fréquent). Exploitation facilitée des plugins WordPress obsolètes via CVE publiques. Pivot possible vers l'infrastructure interne si le serveur web n'est pas isolé.
Risques réputationnels et publics. Pour une entreprise dont l'activité repose sur la fourniture de services de sécurité, la découverte publique d'une compromission touche directement la crédibilité commerciale. Les partenaires B2B et clients institutionnels sont sensibles à ce signal : un prestataire qui laisse un web.zip à sa racine pose une question évidente sur sa capacité à sécuriser d'autres environnements. Une médiatisation, même modérée, amplifie l'impact bien au-delà du coût technique de l'incident.
Risques financiers et légaux. Exposition de données personnelles côté clients belges (majorité) et français (minorité transfrontalière) : violation RGPD et directive NIS2 transposée en Belgique par la loi du 26 avril 2024. Amendes potentielles jusqu'à 4 % du chiffre d'affaires annuel. Notification obligatoire à l'APD (Autorité de Protection des Données belge) sous 72 heures en cas de fuite avérée. Coûts opérationnels de réponse à incident, restauration, audit post-incident. Responsabilité contractuelle possible en cas de fuite de données clients avec réclamations civiles.
Ce que cette mission illustre
Quatre choses méritent d'être notées au-delà du cas lui-même :
1. Le pentest passif produit énormément avant même de toucher au clavier de l'attaque active. Cinq minutes de dirsearch et WPScan en mode passif, aucun bruteforce, aucune tentative d'exploitation : cinq findings critiques ou élevés remontent. Backups, panels d'admin exposés, API leaks, plugins obsolètes, tout ce qui n'aurait jamais dû se retrouver publiquement accessible. Chez la plupart des PME auditées, quelque chose remonte, souvent quelque chose de critique.
2. Le péché du fichier de sauvegarde n'est pas propre aux amateurs. C'est souvent le prestataire qui maintient le site, professionnel par ailleurs, qui laisse un jour un backup après une intervention et qui l'oublie. La solution n'est pas de compter sur la vigilance individuelle : c'est de mettre en place une règle serveur qui coupe la classe entière du problème (bloquer les extensions de backup au niveau Nginx ou Apache), et de scanner régulièrement pour détecter les régressions.
3. WordPress + Elementor n'est pas un problème en soi, la maintenance en est un. Une PME sur un stack WordPress à jour et durci reste raisonnablement sûre. Le problème n'est pas le CMS, c'est le cycle de maintenance quand personne en interne ne le pilote : plugins qui accumulent du retard, sauvegardes qui traînent, panels d'admin ouverts par confort. Le contrat avec le prestataire doit inclure explicitement la responsabilité de la maintenance de sécurité (mises à jour, coupure des interfaces sensibles, rotation des credentials).
4. L'analyse passive comme démarche commerciale honnête. Ici, aucun mandat initial. La démarche est du responsible disclosure : un pentester regarde ce qui est publiquement exposé, remonte les findings au dirigeant, propose un rapport formel et éventuellement un accompagnement plus large. Ça ne remplace pas un pentest actif cadré, mais ça permet à une PME de découvrir gratuitement (ou pour un coût très bas) qu'elle fuit son SI, avant qu'un attaquant ne le fasse pour de vrai.
Votre site a-t-il été audité de cette façon ?
Audit web complet avec content discovery agressif, configuration serveur, comptes admin, base clients. À partir de 2 800 € HT pour une PME de 10 à 50 personnes.
Demander un devis audit web → Échange 30 min


