Zlouporaba ranjivosti računalnih sustava |
Exploit |
Vrste exploita |
Buffer overflow |
Heap overflow |
Integer overflow |
Format string attack |
SQL injection |
Cross-site scripting |
7.1. Vrste napada
7.1.1. Zaobilaženje autorizacije
7.1.2 Korištenje SELECT naredbe
7.1.3. Korištenje INSERT naredbe
7.1.4. Korištenje SQL Server pohranjenih procedura
7.2. Kako smanjiti mogućnost eksploatacije?
7.3. Primjeri SQL injekcije
SQL injekcija (engl. SQL injection) je tehnika koja eksploatira sigurnosnu ranjivost koja se događa u sloju baze podataka aplikacije. Najčešće se eksploatiraju web aplikacije koje u svojim SQL upitima koriste podatke koje je isporučio korisnik, ali bez prethodnog ispitivanja da li ti isti korisnički podaci sadrže neke potenijalno štetne znakova poput navodnika, točke-zarez i sl.
SQL injekcija je tehnika koja se sastoji od upisivanja odgovarajućeg teksta u polja obrasca koja aplikacija koristi u svojim SQL upitima, tako da upiti iz baze vrate podatke koje inače ne bi. Ova metoda, kao i većina hakerskih postupaka, počiva na metodi pokušaja i pogrešaka i temelji se na pogađanju strukture SQL upita i imena atributa i tablica. Opisat ćemo neke vrste ovakvih napada.
Najjednostavnija tehnika SQL injekcije je zaobilaženje prijave (engl. logon form). Pogledajmo sljedeći programski kôd:
SQLQuery = "SELECT Username FROM Users
WHERE Username = ‘" & strUsername & "‘
AND Password = ‘" & strPassword & "‘"
strAuthCheck = GetQueryResult(SQLQuery)
If strAuthCheck = ""
Then boolAuthenticated = False
Else boolAuthenticated = True
End If
Nakon što korisnik preda korisničko ime i lozinku ispituje se tablica Users da bi se doznalo da li postoji red sa sa tim korisničkim imenom i lozinkom. Ako je takav red pronađen, tada se korisničko ime pohranjuje u varijablu strAuthCheck, koja označava da je korisnik trebao autentificiran. Ako ne postoji red koji sadrži zadane korisničke podatke, strAuthCheck će biti prazan i korisnik se neće autentificirati.
Ako strUsername i strPassword nemaju ograničenja, tj. mogu sadržavati bilokakve znakove, pa tada može modificirati struktura aktualnog SQL upita tako da se ''prođe'' autentifikaciju iako valjano korisničko ime i lozinka nisu poznati. Da bi ovo pobliže objasnili, pogledajmo sljedeći primjer:
Primjer 1. Ukoliko korisnik ispuni polje korisničkog imena i lozinke obrasca sa podacima:
Login: ‘ OR ‘‘=‘
Password: ‘ OR ‘‘=‘
Gore naveden SQL upit će poprimiti sljedeći oblik:
SELECT Username FROM Users
WHERE Username = ‘‘
OR ‘‘=‘‘
AND Password = ‘‘
OR ‘‘=‘‘
Umjesto da uspoređujemo podatke koje je predao korisnik sa onima u tablici Users, upit uspoređuje istinitost relacije ‘‘=‘‘, rezultat čega će naravno uvijek biti istina. S obzirom da su svi uvjeti, u WHERE dijelu SQL upita, zadovoljeni, aplikacija će odabrati korisničko ime iz prvog reda tablice koja se pretražuje (u ovom slučaju to je tablica Users). Izabrano korisničko ime će se pridružiti varijabli strAuthCheck koja će osigurati autentifikaciju.
U nekim situacijama, trebamo na temelju povratne poruke koja opisuje pogrešku primjeniti obrnuti inžinjering na SQL upite koji su ranjivi. Da bi to učinili, moramo znati kako protumačiti poruku koja opisuje grešku i kako u skladu s tim promjeniti injection string.
Prva pogreška koju obično susrećemo je sintaksna pogreška (engl. sintax error). Sintaksna pogreška označava da upit ne odgovara strukturi ispravnog SQL upita. Prva stvar koju moramo utvrditi je, da li je moguća injekcija bez izbjegavanja navodnika, ako jest radi se o direktnoj injekciji.
U slučaju direktne injekcije, kojigod argument predamo koristit će se u SQL upitu bez bilokakve izmjene. Direktne vrijednosti mogu biti numeričke vrijednosti koje se koriste u WHERE dijelu upita ili argumenti SQL naredbe poput naziva tablice ili atributa tablice u bazi podataka. U svim ostalim slučajevima u injection string-u nužno je koristiti navodnike.
SELECT naredba se koristi za dohvaćanje informacija iz baze podataka. Da bi natjerali da poslužitelj dohvati druge zapise, osim onih koji su namjeravani, potrebno je izmijeniti where dio SQL upita tako da mu dodamo naredbu UNION SELECT koja će omogućiti da rezultat bude unija izvornog i novog SQL upita. Pretpostavimo da je zadana skripta sa sljedećim programskim kôdom:
SQLString = "SELECT Ime, Prezime FROM Zaposlenici
WHERE Grad = ‘" & strCity & "‘"
Ako koristimo injection string oblika:
‘ UNION ALL SELECT DrugiAtribut FROM DrugaTablica WHERE ‘‘=‘
Poslužitelju baze podataka će biti poslan ovaj SQL upit:
SELECT Ime, Prezime FROM Zaposlenici
WHERE Grad = ‘‘
UNION ALL
SELECT DrugiAtribut FROM DrugaTablica
WHERE ‘‘=‘‘
Mehanizam baze podataka će pregledati tablicu Zaposlenici tražeći red gdje je atribut Grad postavljen na ''ništa''. Budući da ga neće pronaći, neće vratiti nikakve informacije. Jedine informacije koje će upit vratiti bit će iz drugog, injektiranog SQL upita. U ovom primjeru smo pretpostavili da ne postoji zaposlenik koji nema vrijednost atributa Grad. U nekim slučajevima ''ništa'' neće funkcionirati jer postoje zapisi u bazi koji koriste ''ništa'' u odgovarajućem atributu. U tom slučaju potrebno je samo upisati vrijednost koja se ne pojavljuje u tablici.
Neki poslužitelji baze podataka vraćaju dio upita koji sadrži sintaksnu pogrešku. Ovisno o strukturi upita, pojedini injektirani niz će dobaviti korisne informacije, dok drugi neće.
Moguće je manipulirati injektirani upit tako da polako, ali konačno sigurno, vrati željenu informaciju. To se postiže dodavanjem dodatnih uvjeta u WHERE dio upita koji će spriječiti odabir određenih redova tablice. Pretpostavimo da je početni injection string izgledao ovako:
‘ UNION ALL SELECT PrviAtribut, DrugiAtribut, TreciAtribut
FROM Tablica
WHERE ‘‘=‘
Neka je rezultat ovog upita 'prvi', 'drugi' i 'treci'. Sljedeći injection string bi izgledao ovako:
‘ UNION ALL SELECT PrviAtribut, DrugiAtribut, TreciAtribut
FROM Tablica
WHERE PrviAtribut NOT IN (‘prvi’)
AND DrugiAtribut NOT IN (‘drugi’)
AND TreciAtribut NOT IN (‘treci’)
AND ‘‘=‘
Dio NOT IN() osigurava da povratna informacija budu podaci koje još ne znamo (u ovom slučaju drugi red tablice Tablica).
Naredba INSERT se koristi za dodavanje n-torki u bazu podataka. U Web aplikacijama se obično koristi za registeaciju korisnika, dodavanje proizvoda u ''kolica'' pri online-kupovini i sl. Provjeravanje ranjivosti sa INSERT naredbom je slično onom sa WHERE. Korištenje ove naredbe nije preporučljivo ukoliko se želi izbjeći detekcija napada.
Pretpostavimo da web stranica sadrži neku vrstu obrasca za registraciju, u kojoj je potrebno upisati ime, adresu, broj telefona itd. Nakon predaje obrasca, preusmjerujemo se na stranicu koja prikazuje predane podatke uz opciju izmjene tih podataka ili nešto slično. Ovo je vrlo važno, jer da bi mogli iskoristiti INSERT ranjivost moramo moći vidjeti predane podatke. Nije važno u kojem obliku.
Naredba INSERT ima ovakvu strukturu:
INSERT INTO Tablica VALUES (‘jedan’, ‘dva’, ‘tri’)
Ukoliko se želi manipulirati podacima koji su predani kao argumenti u VALUES dijelu naredbe, kako bi se dohvatili neki drugi podaci, potrebno je koristiti podupite. Pogledajmo sljedeći primjer:
SQLString = "INSERT INTO ImeTablice VALUES (‘" & strJedan & "‘, ‘" & strDva & "‘, ‘" & strTri & "‘)"
Ako ispunimo obrazac na sljedeći način:
Name:‘+(SELECT TOP 1 ImeAtributa FROM ImeTablice)+‘
Email: bla@bla.com
Broj_telefona: 333-333-3333
Dobit ćemo naredbu:
INSERT INTO ImeTablice VALUES (‘‘ + (SELECT TOP 1 ImeAtributa FROM ImeTablice) + ‘‘, ‘bla@bla.com’, ‘333-333-3333’)
Na stranici gdje možemo vidjeti predane podatke, umjesto imena pisat će vrijednost atributa strJedan. Da nismo koristili TOP 1 u injection string-u, dobili bi poruku da je došlo do pogreške jer je podupit vratio previše redova. Da bi dohvatili ostale redove koristimo NOT IN().
Microsoft SQL Server instalacija ima više od 1000 pohranjenih procedura. Ukoliko napadač pokušava upotrijebiti napad SQL injekcijom na Web aplikaciju koja koristi SQL Server, pohranjene procedure mogu se pokazati izvaredno korisnima. Ovisno o dozvolama pristupa korisnika u bazi podataka koje koristi web aplikacija, neke, sve ili čak nitijedna od tih pocedura se može koristi.
Injekcija pomoću pohranjenih procedura izgleda otprilike ovako:
simplequoted.asp?city=seattle’;
EXEC master.dbo.xp_cmdshell ‘cmd.exe dir c:
Na početku je dan valjan argument, nakon njega slijedi jednostruki navodnik i ;. Poslijednji argument pohranjene procedure nema završni navodnik. Ovakav ulaz će zadovoljiti potrebe sintakse. Postoji mogućnost da će u ulazu biti potrebne zagrade ili dodatni WHERE uvjeti i sl. ali nije potrebno se brinuti o usklađenosti atributa ili tipova podataka.
master.dbo.xp_cmdshell je jedna od najznačajnijih pohranjenih procedura. Uzima samo jedan argument koji je naredba koju želimo izvršiti na korisničkoj razini SQL Servera.
xp_cmdshell {‘command_string’} [, no_output]
Korisnik web aplikacije, međutim, gotovo nikad neće imati dozvolu za izvođenje ove pohranjene procedure.
Još jedna vrlo korisna procedura je master.dbo.sp_makewebtask:
sp_makewebtask[@outputfile=]‘outputfile’,[@query=] ‘query’
Argumenti ove procedure su izlazna datoteka i SQL upit. sp_makewebtask uzima zadani upit i kao rezultat daje web stranicu koja sadrži rezultat upita.
Ne postoji neki siguran način koji bi spriječio SQL injekciju, ali postoje načini da se smanjiti vjerojatnost njenog događanja. U nastavku su dani neki od tih načina.
Provjeravati ulaz: Vrlo je važno provjeravati ulazne podatke koje je predao korisnik kako bi se osiguralo da ne sadrže opasne kôdove, bez obzira radi li se o SQL-u ili HTML-u. Umjesto brisanja ''loših dijelova'', jer je vjerojatnost da ćemo se sjetiti svega što može ugroziti sigurnost vrlo malena, preporuča se brisanje svega osim ''dobrih dijelova''.
Zabraniti navodnike i escape znakove u ulazu: No usprkos činjenici da lako možemo provjeriti email ili telefonski broj, nije preporučljivo izbaciti navodnike iz polja imena zbog postojanja prezimena poput O'Reilly. Postoje alati koji vrše provjeru da su navodnici ''dobro napisani'' i koji povećavaju sigurnost, ali ne sprječavaju u potpunosti napad.
Koristiti ograničene parametre: U slučaju ove metode zaštite SQL upiti sadrže prazna mjesta koja su označena upitnikom i upit se prevodi u interni obrazac.
Ograničiti pristup bazi podataka i odvojiti korisnike: Potrebno je, što je moguće više, ograničiti prava web aplikacije na pristup bazi podataka: dozvoliti pristup samo tablici korisnika i to isključivo kroz SELECT naredbu.
Koristiti pohranjene procedure za pristup bazi podataka: Ako ih poslužitelj podržava, preporuča se da aplikacija koristi SQL pohranjene procedure za pristup bazi, jer je na taj način moguće spriječiti napad (pod pretpostavkom da su pohranjene procedure dobro napisane).
Izolirati web poslužitelja: Potrebno je projektirati infrastrukturu mreže sa pretpostavkom da će napadač na neki način uspjeti dobiti sve dozvole pristupa poslužitelju, te je potrebno ograničiti načine da se to iskoristi da bi se iskompromitiralo nešto drugo.
Podesiti prijavljivanje pogrešaka: Standardne postavke prijave pogrešaka u nekim radnim okruženjima uključuju informacije o traženju pogrešaka u programu (engl. debugging).
Primjeri SQL injekcije su mnogobrojni, jer je ovo jedan od najčešćih oblika napada in internetu. Navest ćemo nekoliko primjera:
LITERATURA
autor: Marijana Zelanto, 0036400264