
Laboratoire Docker PoC : enchaînement de contournement d'upload de fichier + XSS stockée pour créer des comptes administrateurs. Ressource éducative pour testeurs d'intrusion.
Une application web volontairement vulnérable démontrant comment un contournement d'upload de fichier s'enchaîne avec une XSS stockée pour créer des comptes administrateurs backdoor, même lorsque les protections CSP, CORS et CSRF sont en place.
Article complet : Blog KurtiseBear
Ceci est un laboratoire éducatif pour la formation en sécurité défensive. Ne le déployez pas dans un endroit accessible publiquement.
L'application possède de véritables contrôles de sécurité :
'self' (mais avec 'unsafe-inline' et 'unsafe-eval')Un attaquant disposant d'un compte utilisateur à faible privilège enchaîne deux vulnérabilités pour contourner tous ces contrôles :
Contournement d'upload de fichier -- Le formulaire d'upload restreint aux fichiers .pdf via un attribut accept côté client, mais le serveur n'effectue aucune validation du type de fichier. Un attaquant upload un fichier .js contenant du JavaScript. Le point de terminaison de téléchargement le sert depuis la même origine, donc CSP et CORS ne le bloquent pas.
XSS stockée via le sujet du message -- La fonction de messagerie stocke les entrées utilisateur sans nettoyage. La boîte de réception de l'administrateur affiche le sujet du message sous forme de HTML brut. La charge utile XSS utilise un gestionnaire `` pour récupérer le script uploadé et l'eval(). CSP l'autorise car 'unsafe-inline' et 'unsafe-eval' sont permis.
Absence de CSRF sur le point de terminaison API -- L'API de gestion des utilisateurs (/api/manage-user.php) ne valide pas les tokens CSRF, même si les points de terminaison de formulaires le font. La charge utile XSS appelle cette API en utilisant la session de l'administrateur de même origine. Même si CSRF était présent, du JavaScript de même origine pourrait lire le token depuis le DOM.
Le résultat : lorsqu'un administrateur ouvre sa boîte de réception, la XSS se déclenche, le JavaScript crée un compte administrateur backdoor en utilisant la session de l'administrateur. Toutes les défenses sont en place et fonctionnent. La chaîne fonctionne car elle ne quitte jamais l'origine.
docker-compose up -d
Attendez 10 à 15 secondes que MySQL s'initialise, puis visitez http://localhost:8080
| Rôle | Mot de passe | |
|---|---|---|
| Admin | [email protected] | admin |
| Utilisateur | [email protected] | user |
Naviguez vers http://localhost:8080 et connectez-vous avec [email protected] / user.
Allez dans Upload Files. Le formulaire indique « PDF uniquement » mais ne l'applique que côté client. Soit :
accept=".pdf" de l'entrée fichier, ouUploadez le fichier payload.js fourni (ou le vôtre). Notez l'ID de fichier retourné (ex. 1).
Le fichier uploadé est désormais servi depuis /api/download.php?file_id=1 sur la même origine. CSP ne bloquera pas les requêtes vers ce point de terminaison car il s'agit de 'self'.
Allez dans Send Message. Dans le champ sujet, saisissez :
r.blob()).then(b=>b.text()).then(eval)">
(Remplacez 1 par l'ID de fichier réel de l'étape 2.)
Mettez n'importe quoi dans le corps. Cochez priorité si vous voulez qu'il soit en haut de la boîte de réception. Envoyez.
Le gestionnaire onerror fonctionne car CSP autorise 'unsafe-inline'. Le eval() fonctionne car CSP autorise 'unsafe-eval'. La récupération vers le point de terminaison de téléchargement fonctionne car il est de même origine.
Déconnectez-vous. Connectez-vous en tant que [email protected] / admin. Allez dans Inbox.
Le sujet du message est rendu en HTML brut. La balise `` ne parvient pas à se charger, le gestionnaire onerror se déclenche, récupère la charge utile uploadée, et eval() l'exécute. La charge utile effectue un POST vers /api/manage-user.php en utilisant le cookie de session de l'administrateur (attaché automatiquement pour les requêtes de même origine). Aucun token CSRF nécessaire car le point de terminaison API n'en vérifie pas.
Allez dans Users. Vous devriez voir un nouvel utilisateur : BackdoorAdmin avec le rôle admin et l'email [email protected].
Déconnectez-vous et connectez-vous avec [email protected] / Compromised1! pour confirmer.
CSP bloque les scripts externes
--> Mais la charge utile est hébergée sur la même origine via l'upload de fichier
--> Et unsafe-inline/unsafe-eval permettent le gestionnaire onerror et eval()
CORS bloque les requêtes cross-origin
--> Mais chaque requête de la chaîne est de même origine
Les tokens CSRF protègent les soumissions de formulaires
--> Mais le point de terminaison API ne les valide pas
--> Et même s'il le faisait, du JS de même origine peut lire les tokens depuis le DOM
Les cookies de session ont des protections standard
--> Mais les requêtes de même origine les transportent automatiquement
Les défenses fonctionnent toutes correctement. Elles sont conçues pour arrêter les attaques cross-origin. Cette chaîne ne quitte jamais l'origine.
Ce qui briserait réellement cette chaîne :
Validation du type de fichier côté serveur -- Vérifiez le type MIME, l'extension du fichier et les octets magiques. Ne faites pas confiance au client. Cela empêche l'attaquant d'héberger une charge utile sur votre origine.
Encodage de sortie -- Utilisez htmlspecialchars() sur toutes les sorties contrôlées par l'utilisateur. La boîte de réception affiche $row['subject'] brut. Cela tue complètement la XSS.
CSP strict -- Supprimez 'unsafe-inline' et 'unsafe-eval'. Utilisez des nonces ou des hachages pour les scripts en ligne légitimes. Cela bloque le gestionnaire onerror et eval().
Content-Disposition: attachment -- Forcez le téléchargement au lieu du rendu en ligne pour les fichiers uploadés par l'utilisateur. Cela empêche le navigateur d'interpréter le contenu uploadé.
CSRF sur tous les points de terminaison modifiant l'état -- Y compris les points de terminaison API, pas seulement les formulaires.
Contrôles d'accès sur les uploads -- L'API de téléchargement sert n'importe quel fichier à n'importe quel utilisateur authentifié. Les fichiers devraient être limités à leur propriétaire.
docker-compose down -v
Cette application est volontairement vulnérable. Elle est conçue uniquement à des fins éducatives et de formation en sécurité défensive. Ne la déployez pas sur un réseau accessible à des utilisateurs non fiables. N'utilisez pas ces techniques contre des systèmes sans autorisation écrite explicite.