SQL Injection : démonstration, explications.
Réponse AJAX

Introduction

Ce TP et le mini-site associé permettent de montrer le fonctionnement de l'injection SQL.

À partir d'une page qui affiche des films, nous allons cracker les mots de passe des utilisateurs du site.

Conditions pour pouvoir réaliser l'injection SQL qui permet de lire n'importe quelles données des tables :

  1. Le développeur a oublié d'appliquer real_escape_string (ou équivalent) dans les valeurs envoyées aux requêtes SQL,
  2. Ou bien il utilise des valeurs numériques dans les WHERE sans avoir pris les précautions suffisantes,
  3. Les résultats du SELECT sont affichés dans le navigateur.

Il y a aussi d'autres cas que la lecture des données, par exemple la destruction sauvage. Remplacez :

DELETE FROM user WHERE id = 1 ;

Par :

DELETE FROM user WHERE id = 1 or true ;

Mise en pratique

Découverte du site de test

Allez sur allosql.bts-sio.com. Ce site permet de rechercher, selon un extrait du titre, un film parmi 84 000.

Testez la recherche en tapant par exemple "alien" ou ce que vous voulez dans la zone de recherche.

Est-ce que le développeur a utilisé real_escape_string ?

Essayez la recherche avec un guillemet double puis un guillemet simple.

Obtenez-vous une erreur ? Laquelle ?

Votre réponse n°1

Avec le guillemet double ou le simple ? (C'est important : cela vous indique le délimiteur de chaines de caractères utilisé par le développeur.)

Votre réponse n°2

Ce boulet de développeur a-t-il réaffiché la requête SQL en même temps que l'erreur ?

Votre réponse n°3

Il nous donne donc une indication précieuse : le nom de la table. Quel est-il ?

Votre réponse n°4

Cette erreur nous indique que le gros boulet de débutant de développeur qui a fait ce site a oublié d'utiliser real_escape_string, on va donc pouvoir jouer un peu.

Déterminer le nombre de champs sélectionnés dans le SELECT

La requête que vous avez vu s'afficher est (en surligné jaune, ce que vous avez saisi dans la recherche) :
select * from film where titre like '%'%' limit 0,20

Comprenez bien l'importance des couleurs :

Remarquez également le commentaire MySQL --  : c'est bien tiret tiret espace, si vous oubliez l'espace vous aurez des erreurs de syntaxe.

Pour déterminer le nombre de champs, vous allez successivement exécuter ces requêtes (grâce à l'injection SQL), jusqu'à ne plus obtenir d'erreur (deux SELECT réunis par un UNION doivent renvoyer le même nombre de champs) :
select * from film where titre like '%' union select 1 -- %' limit 0,20
select * from film where titre like '%' union select 1,2 -- %' limit 0,20
select * from film where titre like '%' union select 1,2,3 -- %' limit 0,20
select * from film where titre like '%' union select 1,2,3,4 -- %' limit 0,20
select * from film where titre like '%' union select 1,2,3,4,5 -- %' limit 0,20
...

Combien de champs dans le union select pour ne plus obtenir d'erreur ?

Votre réponse n°5

Le deuxième SELECT, avec lequel nous allons jouer, devra toujours renvoyer ce nombre de champs, sous peine de réobtenir l'erreur "The used SELECT statements have a different number of columns".

Vous remarquez que la recherche nous affiche tous les films, ça n'est pas pratique pour observer nos résultats. Exécutez donc la requête :
select * from film where titre like '%xyz' union select 1,2,3,4 -- %' limit 0,20
Dans la suite du TP nous garderons toujours ce xyz' qui permet de ne pas être gêné pas la liste des films.

Le résultat du deuxième SELECT étant maintenant plus lisible, dites quels sont les champs qui s'affichent à l'écran (est-ce que le 1 s'affiche ? Est-ce que le 2 s'affiche ? Etc.) (par la suite, il sera inutile de jouer avec les champs qui ne s'affichent pas).

Votre réponse n°6

Trouver le nom de la base de données

Grâce à la BDD interne à MySQL information_schema, accessible par tous les utilisateurs, nous allons trouver le nom de la base de données.

Grâce à l'injection SQL, exécutez la requête qui vous permet de connaitre toutes les BDD qui contiennent une table film :
select * from film where titre like '%xyz' union select 1,table_schema,table_name,4 from information_schema.tables where table_name='film' -- %' limit 0,20

Bien que la requête vous ai envoyé plusieurs résultats, soyez déductifs et notez ici le nom de la BDD qui nous intéresse :

Votre réponse n°7

Trouver toutes les tables de la base de données

Avec un principe très proche de la requête précédente, nous allons trouver toutes les tables contenues dans cette base de données. Exécutez la requête :
select * from film where titre like '%xyz' union select 1,table_schema,table_name,4 from information_schema.tables where table_schema='spastore_sqlinjection' -- %' limit 0,20

Notez ici le nom de la deuxième table contenue dans cette BDD :

Votre réponse n°8

Trouvez les champs de la table user

Cette base de donnée information_schema nous est très utile ! Dans sa table COLUMNS, trouvez la liste des champs de la table user :
select * from film where titre like '%xyz' union SELECT 1, TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION FROM information_schema.COLUMNS WHERE table_schema = 'spastore_sqlinjection' AND table_name = 'user'-- %' limit 0,20

Notez ici la liste des champs de la table user :

Votre réponse n°9

Trouvez les login et les mot de passe des utilisateurs

À vous de jouer : essayez de construire la requête SQL Injection qui va vous donner les identifiants des utilisateurs (login, mots de passe).

Notez ici la requête (ou l'extrait que vous avez saisi dans la zone de recherche) :

Votre réponse n°10

Notez les login et mots de passe des utilisateurs :

Votre réponse n°11

Quel est le cryptage utilisé ?

Votre réponse n°12

Il ne reste plus qu'à aller sur un site de crackage de mots de passe, par exemple crackstation.net/, et lui donner nos hash.

Notez ici chaque utilisateur et le mot de passe en clair associé :

Votre réponse n°13

Protégez-vous... de l'injection SQL

Et de peur qu'un pirate arrive quand même à trouver une faille :