Bezpieczeństwo web, SQL Injection – Wstrzykiwanie zapytań, które nie wyświetlają danych w UI

W bardziej skomplikowanych systemach, wszelkie zapytania SQL nie są wyświetlane bezpośrednio na stronie. W prostych stronach internetowych zwykle, rezultat zapytania SQL może być wyświetlony w formie np. tabeli. W aplikacjach webowych jest wiele warstw usług między stroną internetową a DAL. Ponadto, część zapytań po prostu nie jest wyświetlanych np.:

SELECT count(1) where UserName='Piotr' AND Password='1234'

Powyższe zapytanie, może być wykonane jako proces autoryzacji. Nawet jeśli uda nam się coś wstrzyknąć, nie będziemy o tym wiedzieć,  ani nie zobaczymy danych, które chcieliśmy uzyskać. Czy to znaczy, że w tych sytuacjach aplikacja jest zawsze odporna na SQL Injection?

Jest dokładnie odwrotnie. Proste aplikacje zwykle używają ORM (np. Entity Framework) i nie generują dynamicznych zapytań. W przypadku skomplikowanych systemów, łatwo ulec złudzeniu, że logika wykonywana głęboko w back-end (np. w systemie kolejkowym) jest bezpieczna. Inne zagrożenie to dane pochodzące z wewnętrznego systemu, które są traktowane przez programistów jako bezpieczne. Każdy argument, nawet pochodzący z wewnętrznego systemu powinien być postrzegany jako możliwość SQL Injection.

Dzisiaj przyjrzymy się technikom, które umożliwiają przeprowadzenie SQL Injection, nawet jeśli zapytanie jest ukryte głęboko w BE. Zakładamy, że system jest podatny na SQL Injection i musimy w jakiś sposób tylko wyprowadzić dane z niego ponieważ nie ma możliwości wyświetlenia ich w standardowej tabeli.

1. Zewnętrzny zapis danych
Niektóre silniki baz danych umożliwiają zapis danych do zewnętrznej bazy. W SQL Server do dyspozycji jest OpenRowSet.
W MySQL można zapisać wynik zapytania w pliku tekstowym za pomocą

SELECT ... INTO OUTFILE

Więcej informacji tutaj:
https://dev.mysql.com/doc/refman/5.1/en/select-into.html

Pomimo, że bezpośrednio danych nie widać na wynikowej stronie, to możemy wstrzyknąć zapytanie, którego rezultat zostanie zapisany w naszej bazie danych lub w pliku tekstowym w przypadku MySQL. W praktyce, ma to dość ograniczone możliwości ze względu na firewall.

2. Stopniowe odgadywanie danych

Innym sposobem jest tak zmodyfikowanie zapytania, aby w każdej iteracji można byłoby odgadnąć jeden znak. Przykład:

SELECT count(1) where UserName='admin' AND substring(Password,0,1) == 'A'

Wystarczy, że odgadniemy pierwszy znak hasła. Jeśli hasło nie zaczyna się od ‘A’, wtedy dostaniemy komunikat o błędzie autoryzacji. Wtedy możemy spróbować ponownie, np.:

SELECT count(1) where UserName='admin' AND substring(Password,0,1) == 'B'

Załóżmy, że udało nam się zalogować jako admin. Oznacza to, że hasło admina zaczyna się od ‘B’. Kolejna iteracja będzie wyglądać zatem:

SELECT count(1) where UserName='admin' AND substring(Password,1,1) == 'A'

O wiele łatwiej jest odgadnąć jeden znak, niż całe hasło.

3. Spowodowanie błędu
Zwykle jak wiemy, że aplikacja jest podatna na atak, wtedy można zastanowić się jak to wykorzystać. Problem w tym, że skoro aplikacja nie wyświetla żadnych danych, czasami decydujące jest odkrycie, czy przeprowadzony atak w ogóle może przynieść jakieś zagrożenia. Jeśli chcemy przekonać się, że nasze zapytanie rzeczywiście zostało wykonane, wtedy możemy spowodować błąd. Na przykład rozważmy schemat zapytania:

SELECT A from B where C

A zostanie wyłącznie wtedy, kiedy warunek C jest spełniony na tabeli B. Z kolei warunek C zostanie sprawdzony wyłącznie, kiedy zapytanie jest wykonywane.
Zwykle powyższą technikę stosuje się z punktem numer 2. W przykładzie pokazanym w punkcie drugim nie jest to potrzebne bo w przypadku nieprawidłowego hasła po prostu nie nastąpi autoryzacja. Czasami jednak nie możemy liczyć nawet na taką informacje i wtedy można wywołać błąd. A w jaki sposób najprościej wyrzucić wyjątek? Spójrzmy:

SELECT 1/0 from Users WHERE ...

4. Opóźnienie wykonania

Punkt 2 i 3 mają sens wyłącznie kiedy w jakiś sposób błąd autoryzacji (punkt 2) lub błąd wykonania zapytania (punkt 3) jest przekazywany z powrotem do użytkownika. Nie zawsze jednak ma to miejsce, ale wciąż aplikacja może być podatna na SQL Injection. Co jeśli następujące zapytanie zostanie wstrzyknięte?

if substring(Password,0,1)) = 'A'  waitfor delay '0:0:10'

Możemy obserwować czas przetwarzania zapytania. Jeśli będzie one dłuższe o 10 sekund, prawdopodobne jest, że nasz warunek został spełniony czyli pierwszy znak hasła to litera A.

2 thoughts on “Bezpieczeństwo web, SQL Injection – Wstrzykiwanie zapytań, które nie wyświetlają danych w UI”

  1. Srsly? Czy naprawde jeszcze ludzie “recznie” buduja zapytania w DAL? Albo ja jestem jakis nienormalny, gdyz od okolic roku 2000 wykorzystuje w zasadzie wylacznie procedury skladowane, gdzie eksponowane sa jedynie konkretne zestawy parametrow, i nie pamietam abym kiedykolwiek w procedurze sklejal recznie zapytanie, ktore mozna tak zhakowac.

    Mam wrazenie, ze wiekszosc artykulow o SQL Injection jest albo robiona na sile, albo traktuje wylacznie o przypadkach typu “Hello World”, ktore w realnym scenariuszu nigdy nie maja miejsca.

    Przyklad z Twojego tekstu: hakowanie hasla. Czy spotkales sie u siebie badz u Klienta z trzymaniem hasel otwartym tekstem ? Jak dla mnie ten przyklad jest albo mega naciagany, albo ktos kto rzeczywiscie takie rzeczy robi powinien miec dozywotni zakaz dotykania sie do klawiatury.

  2. Panie Piotrze, dziękuje za bardzo fajny cykl i generalnie całą zawartość bloga, wiele można się nauczyć pomimo iż każdy ma większe bądź mniejsze doświadczenie. Proszę nie przejmować się komentarzami takich @Igor-ów

    @Igor…
    Myślę iż za dużo się wymądrzasz, a tak naprawdę wiesz bardzo niewiele. Może podasz adres swojego bloga i się coś nauczymy ?
    Realnie nie ma żadnego znaczenia czy hasło jest haszowane jeśli możesz wstrzyknąć OR 1=1 albo bardziej misterne zapytania i zalogować się na konto użytkownika albo odczytać jego mail, imię,nazwisko – po czym wysłać spreparowany mail. Użytkownik i jego hasła to najsłabsze ogniwo każdego systemu ( ala D.Tusk user:admin,pass:admin) i najczęściej właśnie to końcowy użytkownik staje się ofiarą ataku poprzez spreparowane maile bądź też brutal force. Tak więc Igor pomimo Twojego 20-letniego doświadczenia, sporo możesz się jeszcze nauczyć a nie ufać bezmyślnie pozornie bezpiecznemu systemowi… Każdy kiedyś zaczynał, i każdy nie był expertem od pierwszego dnia.

Leave a Reply

Your email address will not be published.