Vous êtes sur la page 1sur 11

Sécurité des bases de Données,

Injection SQL

Ce TP, vous propose de jouer avec DVWA : https://dvwa.co.uk/ pour découvrir les injections
SQL à travers l’utilisation de Burp Suite.

Ce TP suppose que vous avez une version fonctionnelle de DVWA, pour cela vous pouvez
soit l’exécuter dans un VM / docker, soit la mettre sur un serveur Apache.
(Evitez dans tous les cas qu’elle soit visible depuis le web)

Dans ce TP, nous nous concentrerons sur les injections SQL comme ce sont celles qui
concernent les bases de données. Mais n’hésitez pas à expérimenter avec le reste si vous
êtes curieux.

Les attaques vont être faites par le prisme de Burp suite :


https://portswigger.net/burp/communitydownload

Si vous êtes joueurs, il est possible de le faire directement avec les outils de développeur du
navigateur (Shift + CTRL + J sous Chrome, Ctrl + Shift + I Sous Firefox)

Cliquez sur Sql Injection dans le menu à gauche pour démarrer le challenge

Niveau facile
Comprendre la page en face de nous
Nous accédons à une page nous permettant de soumettre un ID utilisateur qui est un entier
(positif). Lorsque nous soumettons l'ID, nous obtenons les informations sur l'utilisateur.
Si nous soumettons un ID utilisateur invalide, nous obtenons une réponse vide (rien ne
s'affiche).

Lorsque nous cliquons sur Submit, une requête GET est envoyée au serveur avec l'ID de
l'utilisateur dans le paramètre id :

GET /vulnerabilities/sqli/?id=1&Submit=Submit
On peur redécouvrir cette requête dans Burp Proxy > HTTP history.

Exploiter la vulnérabilité
Pour vérifier si une application est vulnérable à l'injection SQL, nous avons vu que souvent il
suffit d’entrer un guillemet simple ' comme paramètre et voir comment l'application se
comporte. Dans notre cas, l'application lance une erreur, il y a donc une forte probabilité que
l'application soit vulnérable à l'injection SQL.

Le message d'erreur indique que MariaDB est utilisé. Dans MariaDB, les commentaires sont
souvent utilisés avec le caractère # . Nous essayons une injection avec la requête 1' OR 1=1 #
qui devrait résoudre la commande SQL en quelque chose comme SELECT * FROM users
where id='1' OR 1=1 # .

Si cela fonctionne, la commande SELECT devrait sélectionner chaque utilisateur existant.


Nous envoyons notre requête pour la tester et parvenons à obtenir les résultats attendus :
Nous devons souvent essayer plusieurs injections pour en obtenir une qui fonctionne.

(Si besoin, un github liste de nombreuses charges utiles : PayloadAllTheThings).

Pour tester automatiquement toutes les possibilités, il est possible de jouer avec Burp
Intruder.

Code vulnérable
Voici le code source sur le serveur :

// Get input
$id = $_REQUEST[ 'id' ];

// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id =
'$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die(
'<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ?
mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res =
mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname:
{$last}</pre>";
}

mysqli_close($GLOBALS["___mysqli_ston"]);
}
Le code vulnérable est la ligne suivante :

$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' ;";
Puisque l'entrée de l'utilisateur est simplement concaténée à la commande sans être vérifiée
ou assainie (sanitizée), cela nous permet de passer des commandes arbitraires.

Assainissement
Nous avons vu qu’une contre-mesure naïve consistait à rechercher des mots-clés spéciaux tels
que ; , # , -- ou dans la saisie de l'utilisateur. Dans notre cas, nous nous attendons à un
nombre entier positif et nous devrions vérifier que c'est ce que nous avons obtenu.

Niveau moyen
Au niveau moyen, l'application est presque identique à celle du niveau bas, sauf que nous ne
pouvons pas entrer l'identifiant de l'utilisateur nous-mêmes, nous devons utiliser une liste
déroulante.

Dans Burp Suite Proxy > HTTP history nous récupérons la requête envoyée :

POST /vulnerabilities/sqli/ HTTP/1.1


Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101
Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost/vulnerabilities/sqli/
Content-Type: application/x-www-form-urlencoded
Content-Length: 18
DNT: 1
Connection: close
Cookie: PHPSESSID=kakd53qkpnrki4bbd1t0o8j3v2; security=medium
Upgrade-Insecure-Requests: 1

id=1&Submit=Submit
Nous pouvons voir que c'est une requête POST qui envoie l'identifiant de l'utilisateur dans le
paramètre id .

Exploitation de la vulnérabilité
Pour exploiter cette vulnérabilité, nous pouvons essayer de contourner la liste déroulante et
modifier la requête envoyée directement dans Burp Suite. Pour ce faire, nous faisons un clic
droit sur la requête envoyée dans Proxy > HTTP history et envoyons la requête au répéteur.

A partir de là, nous modifions la requête pour essayer quelques injections. Nous pouvons
faire un clic droit sur la zone de texte et sélectionner " URL encode as you type" pour laisser
Burp gérer l'encodage de l'URL pour nous.

Après avoir testé plusieurs injections, nous trouvons que la suivante fonctionne comme nous
l'espérions 1 OR 1 = 1# .

Le serveur a exécuté notre requête et a sélectionné et affiché chaque utilisateur.

Vulnérabilité
La vulnérabilité est la même que précédemment, côté serveur, le code concatène l'entrée
utilisateur à la commande SQL, permettant à l'attaquant de passer du code SQL arbitraire.

$query = "SELECT first_name, last_name FROM users WHERE user_id = $id ;";
Ce qui est nouveau, c'est la protection côté client. Mais il ne faut pas croire qu’un utilisateur
est contraint de respecter les valeurs d’un menu déroulant, ce n’est pas un contrôle suffisant.
Cela empêche certainement l'utilisateur ordinaire de le faire et constitue une bonne
conception de l'expérience utilisateur ; cependant, un attaquant sait comment intercepter et
modifier les requêtes et peut facilement contourner ce type de protection.

Répétons
Ne faites jamais confiance à l'entrée de l'utilisateur, même si vous avez mis en place une
validation côté client ! Comme la validation se trouve du côté du client, ce dernier peut
facilement l'altérer. Une meilleure approche aurait été de vérifier du côté du serveur que la
donnée est effectivement un entier.

Niveau élevé
Nous arrivons maintenant sur une page contenant un lien "cliquez ici pour changer votre
identifiant". Lorsque nous cliquons sur le lien, une fenêtre pop-up apparaît où nous pouvons
soumettre notre nouvel identifiant.

Voici la requête POST envoyée pour changer l'ID :

POST /vulnerabilities/sqli/session-input.php HTTP/1.1


Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101
Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost/vulnerabilities/sqli/session-input.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 19
Connection: close
Cookie: PHPSESSID=4bkgc3r169bu025v0kh3iv6pe3; security=high
Upgrade-Insecure-Requests: 1

id=33&Submit=Submit

Lorsque l'ID est modifié, la page répond avec le texte : "Session ID : 33".

Lorsque nous entrons la chaîne de caractères 1 , la page ID affiche alors :


Lorsque nous entrons la chaîne ' comme ID, la page ne se recharge pas correctement, nous
obtenons une page blanche avec des choses étranges.

Trouver l'exploit

Double demande
Maintenant, à partir du résultat des tests précédents, nous avons l'intuition que l'application
est vulnérable à l'injection SQL ; cependant, nous devons encore trouver le moyen d'exploiter
cette SQLi.

Pour ce faire, nous allons continuer avec Burp. La difficulté ici est que la requête ne donne
pas une réponse directe. Lorsque nous regardons l'historique HTTP dans Burp suite, nous
pouvons voir que la réponse à la première requête envoyée est la suivante :

<body>
<div id="container">Session ID: 2
<br />
<br />
<br />
<script>window.opener.location.reload(true);</script>
<form action="#" method="POST">
<input type="text" size="15" name="id">
<input type="submit" name="Submit" value="Submit">
</form>
<hr />
<br />
<button onclick="self.close();">Close</button>
</div>
</body>
Cette page en recharge une autre avec window.opener.location.reload(true) ; ce qui
déclenche l'envoi d'une autre requête :
GET /vulnerabilities/sqli/ HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko/20100101
Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost/security.php
DNT: 1
Connection: close
Cookie: PHPSESSID=ocm7g1qt0oenj27l7poubqroq2; security=high
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache
Et enfin, cette requête affiche les informations que nous recherchons.

Configuration des macros


Nous devons programmer Burp pour qu'il envoie automatiquement la seconde requête
lorsque la première a été envoyée, afin que Burp puisse analyser les informations de la
seconde requête.

Pour ce faire :

1. Project Options > Sessions > Macros > Add


2. Sélectionnez la deuxième requête, celle qui appelle GET /vulnerabilities/sqli/

3. Cliquez sur OK
4. Dans la fenêtre de l'éditeur de macros, donnez un nom à la macro et cliquez sur OK.
5. Project Options > Sessions > Sessions Handling Rules > Add
6. Dans Rules Actions, cliquez sur Add > Run a post request macro.
7. Sélectionnez la macro nouvellement créée
8. Dans Scope > Tools Scope, sélectionnez uniquement Intruder et Repeater.
9. Dans Scope > URL Scope, sélectionnez Use Use suite scope
10. Dans Details, donnez un nom à votre règle et cliquez sur OK.
11. Sélectionnez votre règle et cliquez sur Up pour qu'elle soit la première.
En raison de l'étape 9. vous devez également définir votre portée cible.
Configuration de l'intrus
Maintenant nous pouvons configurer l'intrus Burp pour trouver notre exploit. Nous
définissons notre position comme ceci :

id=1'+§payload§
Et nous chargeons le fichier sqli-error-based.txt.

Ensuite, nous lançons l'attaque et recherchons des réponses de grande taille. Nous pouvons
rendre la réponse html pour voir en un coup d'œil si l'injection a fonctionné ou non.
Dans notre cas, l'injection OR 1=1— a fonctionné correctement.

Vulnérabilité
La vulnérabilité est la même. Le développeur a pensé que parce que la réponse ne nous est
pas directement donnée, nous ne pouvons pas mettre en place des moyens automatiques de
recherche d'injection.

Assainissement
Le développeur doit utiliser des instructions préparées pour nettoyer les entrées de
l'utilisateur avant d'exécuter les requêtes SQL.

Niveau impossible
Dans le niveau impossible, le développeur utilise une instruction préparée avec un jeton anti-
csrf. A cause de cela, nous ne pouvons pas effectuer une injection SQL.

Vous aimerez peut-être aussi