Voyez un site web comme un saladier. On vous le tend, et vous ne pouvez que voir ce qu’il contient. Mais vous n’êtes pas un visiteur venu admirer ce saladier. Vous êtes un pentester, un bug bounty hunter ou un hacker. Vous ne voulez pas un saladier, vous voulez en faire un lavabo ! Il va donc vous falloir deux choses : un robinet (une « source »), et une évacuation (un « sink »). Une faille XSS, c’est ça.
Chercher à exploiter une faille XSS, c’est trouver une porte d’entrée qui permette d’ajouter notre propre code à un site, et une porte de sortie pour exfiltrer des données intéressantes. Ce principe est commun aux trois groupes de XSS qui existent. Découvrons donc comment fonctionnent ces trois groupes, et comment essayer de s’en prévenir au mieux.
L’impact d’une faille XSS
Pour bien comprendre ce qu’est une faille XSS, il faut comprendre où elle fait mal. Le nom XSS signifie « Cross Site Scripting« . Il s’agit donc de l’art d’insérer un code malicieux sur un site afin d’exécuter certaines actions. À partir du moment où vous arrivez à exécuter du Javascript sur l’ordinateur d’un autre, quatre grandes options s’offrent à vous:
- Passer un message: le moins violent des quatre, simplement venir afficher un message pour faire baisser la réputation du site visé. Ou prouver que vous avez réussi à hacker le site, tout simplement
- Aller à la pêche: quel meilleur phishing que celui qui se situe sur la bonne URL ? Depuis le javascript vous pouvez réécrire l’intégralité de l’apparence du site victime (pour peu que le payload ne soit pas limité en terme de caractères). Rien de plus simple alors que de créer un faux formulaire de login qui renvoie en fait les données chez vous
- Exécuter des actions à la place d’un autre: cela nécessite un peu de repérage auparavant afin de référencer les différentes actions possibles, mais faire un call depuis la machine d’un autre utilisateur utilisera du coup son propre compte et vous permettra également d’effectuer une « vertical escalation« , donc la récupération de droits supplémentaires aux vôtres, si vous ciblez un administrateur
- Exfiltrer des données: la meilleure attaque étant souvent celle qu’on ne repère pas, vous pouvez vous contenter d’exfiltrer par exemple les cookies ou le localStorage afin d’effectuer une « session hijacking« . En replaçant vos cookies locaux par ceux récupérés d’un autre utilisateur, vous lui volerez tout simplement sa session
Les XSS Stockées
Probablement la plus dangereuse des trois catégories, une XSS stockée peut toucher un grand nombre d’utilisateurs sans action spécifique de leur part. En effet, comme leur nom l’indique, ces failles sont persistées en base de donnée. Donc elles continuent d’opérer jusqu’à ce qu’un administrateur arrive à la supprimer. Par exemple imaginez un commentaire sur un blog qui contient un payload exploitant une faille XSS. Tous les utilisateurs qui liront l’article seront affectés tant que le commentaire malicieux ne sera pas supprimé.
Un exemple connu est le ver « Samy« . Un ver qui a agi en 2005 sur MySpace et qui postait juste le message « but most of all, samy is my hero » sur votre profil. Mais il contenait en plus un morceau de Javascript qui repostait le message chez tous vos contacts qui croisaient le ver. Complètement inoffensif, il a quand même infecté plus d’un million d’utilisateurs à l’époque. Imaginez s’il avait été malicieux ?
Les XSS reflétées
Ici pas de persistance de votre payload. En revanche, il passe malgré tout par le BackEnd. Voyez-ça comme un echo que l’on lancerait à la montagne. Il revient vers nous, parfois légèrement déformé par le relief.
Ici, même si la donnée n’est pas sauvegardée, elle peut être traitée malgré tout. Notamment, justement, pour éviter les injections de type XSS. À vous donc, en tant que hacker, de comprendre comment le texte est traité pour trouver une faille qui permettra à votre payload de fonctionner.
Les reflected XSS n’agissent donc que si un utilisateur clique sur un lien malicieux, ce qui rend leur rayon d’action plus faible. Elles n’en sont cependant pas moins dangereuses pour autant.
Les DOM-Based XSS
Il est parfois difficile de les discerner de la section précédente. La différence majeure avec les reflected, c’est que dans ce cas précis le payload ne passe pas par le backend et ça n’est pas un script qui vient injecter notre payload dans le code. Une faille « DOM-based » consiste en un payload qui est à cause d’un code mal sécurisé injecté directement par le navigateur sur la page de la victime. Par exemple avec un paramètre GET de l’URL récupéré par le JS. Dans ce cas également, la portée sera moindre que pour une stockée dans la mesure où elle nécessite une action utilisateur.
S’en prévenir
Les failles XSS sont aujourd’hui encore largement exploitées et s’en prévenir est assez compliqué. Il faut réussir à anticiper comment un hacker peut 1) injecter du code malicieux et 2) exfiltrer des données. Pour cela vous pouvez mettre plusieurs process en place:
- Filtrer côté front l’entrée utilisateur
- Filtrer côté back l’entrée utilisateur (par exemple une denylist, voire une allowlist de propriétés acceptées)
- Passer un coup de « sanitizer » sur l’entrée utilisateur
- Filtrer ce que retourne le back
Cette liste n’est évidemment pas exhaustive et doit s’appliquer au cas par cas, mais en réfléchissant bien à tout ce qui peut entrer dans votre back et tout ce que vous affichez qui provient d’un utilisateur, vous réussirez à prévenir au moins une grosse majorité des failles potentielles que vous auriez pu laisser. Continuer à vous former et éprouver votre code de façon régulière reste également le meilleur moyen de corriger petit à petit ces failles.
En conclusion
Se protéger c’est avant tout comprendre comment ces trois types de failles peuvent intervenir et affecter votre site. Vous pouvez notamment vous entraîner avec des Labs tels que ceux de PortSwigger afin de voir comment elles agissent sur un site volontairement laissé vulnérable. Mais surtout vous devez garder en tête la règle d’or: Never trust user input !