Atak typu SQL Injection

Jednym z najpopularniejszych ataków na aplikacje webowe jest atak SQL Injection. Jak łatwo się domyślić, tego typu atak może być zastosowany w przypadku gdy atakujący ma do czynienia z modelem aplikacji, do której podpięta jest baza danych.

Na czym polega atak SQL Injection?

Atak polega na takim wstrzykiwaniu zapytań SQL (np. do parametrów aplikacji) aby baza danych reagowała w określony sposób. Celem może być wyświetlenie poświadczeń użytkowników bądź wyświetlenie innych poufnych danych.

Przykładowy scenariusz:

Dla uproszczenia, niech przykładem będzie panel logowania do danej aplikacji www.

Jak widać, do zalogowania się, potrzebne są dwie dane: nazwa użytkownika (User-Id) oraz hasło (Password).

W jaki sposób aplikacja sprawdza, czy dany użytkownik o podanym haśle istnieje i czy powinien być uwierzytelniony?

Przykładowo, powyższa aplikacja może być podpięta do tabeli o nazwie users, która zawiera w swoich rekordach wszystkich użytkowników wraz z hasłami i poziomami uprawnień. W takiej sytuacji po wpisaniu nazwy użytkownika i hasła, następuje wyszukiwanie w tabeli users, czy istnieje użytkownik o nazwie jaka została wpisana w panelu, który posiada hasło, które zostało wpisane w polu Password (na ten moment czytelnik, celowo, nie będzie wprowadzany w tematykę funkcji hashujących). Jeśli odpowiedź jest pozytywna, czyli istnieje taki rekord (user) o określonych atrybutach (hasło) wówczas użytkownik uznawany jest jako uwierzytelniony.

Podsumowując, wykonywane jest zapytanie w bazie:

select * from Users where user_id=’$user’ and password = ‘$password’.

Mając powyższe na uwadze i wiedząc, że język SQL jest to język bazujący na składniach logicznych, można podejrzewać, że istnieje w miarę prosty sposób aby „oszukać” aplikację w kontekście uwierzytelniania użytkowników, która korzysta z zapytań SQL, poprzez złośliwe wykorzystanie ‘logiczności’ języka SQL.

Anatomia ataku SQL Injection

Korzystając z wiedzy o zapytaniu select * from Users WHERE user_id=’$user’ AND password = ‘$password’ oraz mając na uwadze, że język SQL jest językiem logicznym, trywialnym jest, że aby to zapytanie dało logiczną jedynkę (czyli prawdę) to po obu stronach spójnika logicznego AND muszą być prawdziwe zdania. Czyli zarówno user_id musi być prawdziwy jak i password musi być prawdziwe.

Dla lepszego zrozumienia, warto przytoczyć dwa spójniki logiczne, które są często wykorzystywane w składniach SQL i które będą potrzebne do wytyczenia odpowiedniego payloada, który spowoduje „ominięcie” mechanizmu uwierzytelnienia.

W obu powyższych tabelkach, 1 oznacza zdanie prawdziwe zaś 0 oznacza zdanie fałszywe.

Jak widać, spójnik logiczny OR daje dużo większą swobodę niż spójnik AND, ponieważ w przypadku OR wystarczy, że jedno ze zdań jest prawdziwe (wartość logiczna drugiego zdania nie ma wtedy znaczenia).

Patrząc na poniższy przykład payloada, który da nieautoryzowany dostęp (dostęp bez znajomości, ani odpowiedniej nazwy użytkownika, ani prawidłowego hasła!) widać jak łatwo można ominąć mechanizm uwierzytelniania.

Przedstawiony payload działa w następujący sposób – baza wyświetla wszystkie wyniki z tabeli Users, gdzie nazwa użytkownika to ‘’ (dwa apostrofy) lub 1=1. Wszystko co jest po /* uznawane jest jako komentarz, zatem nie będzie brane pod uwagę jako składowa zapytania.

Skupiając się na części nazwa użytkownika to ‘’ OR 1=1, atakujący dostaje zdanie logiczne poprawne, ponieważ jedynka zawsze równa się jedynce a spójnik logiczny OR powoduje, że pozostałe składowe zapytania (inne niż 1=1) nie mają znaczenia. W efekcie tego, że to zapytanie jest logicznie poprawne, użytkownik zostanie uwierzytelniony – nie znając, ani nazwy użytkownika, ani hasła.