Jak zostać ekspertem od SQL Injection – cz.4

Seria o SQL Injection:
Jak zostać ekspertem od SQL Injection – cz. 1
Jak zostać ekspertem od SQL Injection – cz. 2
Jak zostać ekspertem od SQL Injection – cz. 3
Jak zostać ekspertem od SQL Injection – cz. 4
Jak zostać ekspertem od SQL Injection – cz. 5

W poprzedniej części serii Jak zostać ekspertem od SQL Injection – cz. 3 omówiłem najważniejsze informacje o zastosowaniu bardziej wyrafinowanych technik SQL Injection do omijania zabezpieczeń.

Zastanawiasz się, czy to wystarczy do zostania Ekspertem od SQL Injection? Wiedzę z poprzedniej części bardzo skutecznie wykorzystywałem podczas moich testów penetracyjnych i gwarantuję Ci, że jest niesamowicie skuteczna!

W tej części natomiast zajmiemy się analizą wybranych fragmentów kodu PHP/MySQL i opiszę co jest nieprawidłowego w prezentowanych aplikacjach. Pokażę Ci przykładową tabelę bazy danych oraz kilka skryptów PHP.

Zobaczysz, gdzie tkwi błąd analizując źródło jego powstania. Zapraszam do lektury!

Analiza podatności

Poniżej przedstawiłem kilka różnych fragmentów pseudokodu PHP, odwołujących się do bazy danych. Każdy z fragmentów kodu jest podatny na atak SQL Injection.

Analizowane fragmenty kodu wraz ze zmiennymi w nich używanymi należy traktować w całości jako aplikację webową, pomijając różne możliwości filtracji zmiennych, które nie są przedstawione na przykładach, włącznie z zewnętrznymi zabezpieczeniami oraz bezpieczną konfiguracją interpretera PHP.

W celu zobrazowania problemu założyłem, że konfiguracja serwera WWW oraz interpretera PHP nie jest poprawna i nie są wykorzystujemy funkcji zabezpieczających przed możliwością manipulacji danymi, chyba że w przykładzie podano inaczej.

Założenie takie jest uzasadnione ze względu na przenośność aplikacji napisanych w PHP między różnymi platformami, z różną docelową konfiguracją.

Struktura tabeli tabela:

Przyjmuję, że tabela o nazwie tabela będzie zawierać cztery pola:
1. id,
2. login,
3. haslo,
4. Dane

Załóżmy, że w bazie istnieje jeden rekord o numerze id=1. Poprawne zapytanie SQL do bazy będzie wyglądać następująco:

SELECT dane FROM tabela WHERE id=1

Przykład 1:

<?php
mysql_query("SELECT dane FROM tabela WHERE id=’$zmienna’");
?>

Błąd programistyczny w powyższym przykładzie polega na użyciu zmiennej, która nigdzie wcześniej nie jest zainicjowana. Zmienna zmienna, może zostać podmieniona przez atakującego i wykorzystana do wykonania niedozwolonego zapytania SQL. Atakujący, aby poznać hasło może posłużyć się następującym kodem podstawionym za zmienną zmienna:

1′ union select haslo from tabela/*

Wartość id w tym przypadku jest ujemna aby pierwszy człon zapytania SQL nic nie zwrócił, a drugi człon po operatorze UNION zwrócił interesującą wartość, czyli hasło. Wartość id nie musi   mieć   takiej   postaci, która powoduje, że pierwszy człon zwraca wartość NULL w przypadku, gdy skrypt wyświetla wszystkie rezultaty pochodzące z zapytania SQL, a nie jedynie jeden rekord.

Jeśli przyjmiemy, że adresem podatnej strony WWW będzie:

http://127.0.0.1/test.php

Wówczas, atakujący może posłużyć się następującym adresem URL w celu zaatakowania podatnej aplikacji:

http://127.0.0.1/test.php?zmienna=­1′ union select haslo from tabela/*

Całe zmodyfikowane zapytanie wygląda następująco:

“SELECT dane FROM tabela WHERE id=’­1′ union select haslo from tabela/*’”

W powyższym przykładzie warto zwrócić uwagę na zmienną id umieszczoną w pojedynczych apostrofach.
Taki sposób zapisu zmiennej w zapytaniu ma znaczenie w przypadku wykorzystania dyrektywy magic_quotes_gpc()=on lub użycia wewnątrz skryptu funkcji addslashes(), przyjmującej jako argument zmienną, która ma być eskape’owana.


Dyrektywa magic_quotes_gpc() oraz funkcja addslashes() są jednoznaczne pod względem wpływu na dane wprowadzone z zewnątrz i powodują poprzedzenie niebezpiecznych symboli znakiem backslash \. Powoduje to, że niebezpieczne znaki takie jak:

Apostrof, cudzysłów, znak końca linii  oraz backslash są niwelowane, i  nie mogą  być użyte przez skrypt (wystąpi błąd wykonania zapytania).

Gdy dyrektywa magic_quotes_gpc() jest ustawiona w pliku konfiguracyjnym PHP lub zostanie użyta funkcja addslashes(), w przypadku prób ataku SQL Injection atakujący nie otrzyma rezultatu spreparowanego zapytania SQL. Skrypt zwróci błąd, ponieważ w zapytaniu otwarty ciąg znaków jednym cudzysłowem nie będzie zamknięty i zapytanie nie zostanie wykonane.

Jeżeli natomiast nie zostanie użyta funkcja eskape’ująca lub parser PHP nie będzie odpowiednio skonfigurowany, atak będzie skuteczny.

WW powyższym przykładzie w zapytaniu po słowie tabela występują dwa znaki: / oraz *. Jest to jedna z form komentarza stosowana w celu zniwelowania części zapytania. Atakujący umieszczając takie dwa znaki komentuje ostatni apostrof w zapytaniu SQL, który inaczej spowodowałby błąd zapytania.

Dozwolone formy komentarza w języku SQL to:

1. /**/ komentuje tekst pomiędzy znakami *,
2. # komentuje wszystko co znajduje się za tym znakiem,
3. ­–­ komentuje wszystko co znajduje się za tym znakiem.

Przykład 2:

<?php
mysql_query("SELECT dane FROM tabela WHERE id=$zmienna");
?>

Przykład 2 jest bardzo podobny do przykładu 1, z tą różnicą, że zmienna zmienna nie jest objęta znakami apostrofu. Taki skrypt jest znacznie niebezpieczniejszy niż ten z przykładu 1, ponieważ użycie dyrektywy magic_quotes_gpc() lub funkcji addslashes() nie spowoduje zmniejszenia ryzyka skuteczności ataku. Dzieje się tak, ponieważ atakujący nie będzie musiał używać apostrofów, aby przeprowadzić skuteczny atak.

W celu modyfikacji zapytania atakujący może podstawić za zmienną id następującą wartość:

id=­1 union select haslo from tabela

Adres URL, jaki może być użyty do poznania zawartości pola haslo tabeli może wyglądać następująco:

http://127.0.0.1/test.php?zmienna=­1 union select haslo from tabela

Po uruchomieniu skryptu poprzez tak spreparowany adres URL zapytanie zostanie zmodyfikowane w następujący sposób:

“SELECT dane FROM tabela WHERE id=­1 union select haslo from tabela”

Jak można zauważyć zapytanie nie zawiera na końcu znaku komentarza, co dodatkowo powoduje zwiększoną skuteczność przeprowadzenia ataku. Gdyby atakujący zmuszony był do użycia znaków komentarza, łatwiej dałoby się skonfigurować mechanizmy wykrywania włamań do reagowania na takie komentarze. W tym przypadku zadanie wykrycia ataku jest znacznie utrudnione.

Przykład 3:

<?php
mysql_query('SELECT dane FROM tabela WHERE id=”$zmienna”');
?>

Przykład 3 jest podobny do przykładu 1 z tą różnicą, iż wartość zmiennej zmienna ujęta jest w znaki   cudzysłowu, a nie apostrofu. Taki sposób kodowania również jest spotykany wśród programistów. Podatność takiego skryptu na ataki SQL Injection jest taka sama, jak w przypadku skryptu 1.

Przykład 4:

<?php
mysql_query("SELECT dane FROM tabela WHERE id = ’”.TABLICA_ASOCJACYJNA ['zmienna']."'”);
?>

W przykładach 1-­3 źródło pochodzenia zmiennych nie było jasno określone. Zmienne wprowadzone do skryptu mogą zostać wysłane jedną z trzech metod:

1. GET – zmienne przekazane tą metodą widoczne są w adresie URL,
2. POST – zmienne przekazane tą metodą nie są widoczne w adresie URL, często przekazane są w formularzach internetowych,
3. COOKIE – zmienne przekazane są do formularza za pomocą ciasteczek.

W przykładzie 4 użyta w pseudokodzie TABLICA_ASOCJACYJNA oznacza jedną z trzech tablic asocjacyjnych użytych
do przekazania zmiennych – $_GET, $_POST lub $_COOKIE.
W tym przykładzie, chociaż miejsce pochodzenia zmiennej jest jawnie zadeklarowane, zmienna ta tak jak w poprzednich przykładach nie jest oczyszczana z niebezpiecznych znaków. Zmienna ujęta została w znaki pojedynczych apostrofów, tak jak na przykładzie 1, co bez odpowiedniego użycia funkcji oczyszczających nie zapewnia bezpieczeństwa. W tym przypadku atakujący może użyć następującego adresu URL, aby poznać zawartość kolumny zawierającej hasło:

http://127.0.0.1/test.php?zmienna=­1′ union select haslo from tabela/*

Tym razem atak będzie skuteczny wyłącznie, jeśli programista zadeklaruje pochodzenie zmiennej zmienna, z żądania GET. Gdy programista zadeklaruje pochodzenie danych ze zmiennej wysłanej metoda POST, dla atakującego nie sprawi to żadnej przeszkody. Istnieje możliwość napisania prostego formularza w skrypcie HTML, który prześle odpowiednio spreparowane zapytanie do skryptu przy użyciu metody POST.
W Internecie dostępne są również różnorodne dodatki do przeglądarek oraz programy pośredniczące proxy, umożliwiające wysłanie danych do skryptu dowolną metodą GETPOST, oraz COOKIE.

Przykład 5:

<?php
mysql_query("SELECT dane FROM tabela WHERE id = TABLICA_ASOCJACYJNA['zmienna']");
?>

W przykładzie 5 pochodzenie użytej zmiennej jest jawnie wskazane, lecz zmienna ta nie jest odpowiednio oczyszczana z potencjalnie niebezpiecznych znaków. Zmienna pochodząca z zewnątrz nie jest ujęta w cudzysłów ani znaki apostrofu, podobnie w przykładzie 2. Sposób przeprowadzenia ataku, będzie identyczny jak ten z przykładu 2. W przypadku wykorzystania przez programistę metody GET, w celu pobrania danych zewnątrz. W przypadku metod POST oraz COOKIE, atakujący, ma możliwość spreparowania żądania, przy pomocy odpowiednich serwerów pośredniczących proxy lub dodatków do przeglądarek.

Przykład 6:

<?php
mysql_query('SELECT dane FROM tabela WHERE id = ”'.TABLICA_ASOCJACYJNA ['zmienna'].'”');
?>

Przykład 6 ilustruje fragment kodu równie niepoprawnie napisanego, jak fragment kodu z przykładu 4. Różnica polega na użyciu znaków cudzysłowu, zamiast znaków apostrofu do ograniczenia  zmiennej pochodzącej z zewnątrz skryptu. Sposób ataku na taki skrypt jest identyczny z tym opisanych w przykładzie 4.

Przykład 7:

W przykładzie 7 założono, że w pliku konfiguracyjnym parsera PHP, ustawiono włączoną dyrektywę magic_quotes_gpc()
magic_quotes_gpc()=on

<?php
$zmienna=addslashes(TABLICA_ASOCJACYJNA[$zmienna]);
mysql_query("SELECT dane FROM tabela WHERE id=$zmienna");
?>

W powyższym przykładzie zastosowano funkcję addslashes(), eskape’ ującą niedozwolone znaki pochodzące z zewnątrz, przy wykorzystaniu jednej z trzech metod: GET, POST, COOKIE. W tym przykładzie mogłoby się wydawać, że skrypt jest prawidłowo zabezpieczony przed atakami typu SQL Injection, lecz popełniony tutaj został poważny błąd.
Jeżeli atakujący użyje apostrofu w spreparowanym żądaniu do serwera, dyrektywa magic_quotes_gpc() spowoduje, że znak ten zostanie poprzedzony znakiem backslash, ale to samo wykona funkcja addslashes() nałożona na zmienną, co spowoduje, że jeden znak backslash zniweluje działanie drugiego i w efekcie zmienne nie będą w ogóle oczyszczane.

Jeżeli atakujący wyśle do serwera żądanie GET, zawierające fragment spreparowanego zapytania SQL w postaci:

http://127.0.0.1/test.php?zmienna=­1′ UNION SELECT haslo FROM tabela

Zamieni się ono w następującą postać:

http://127.0.0.1/test.php?zmienna=­1\\’ UNION SELECT haslo FROM tabela

Pierwszy ze znaków backslash zniesie działanie drugiego ze znaków, co w efekcie spowoduje wykonanie następującego zapytania SQL:

SELECT dane FROM tabela WHERE id=­1 UNION SELECT haslo FROM tabela

Atak się powiedzie. Kolejnym błędem z przykładu 7 jest brak ujęcia zmiennej zmienna z zapytania SQL w apostrof lub cudzysłów. W tym przypadku atakujący nawet nie musi wykorzystywać błędu z dublowaniem się funkcji oczyszczających.

Nie musi po prostu używać apostrofu ani cudzysłowu do zamykania zapytania.

Przykład 8:

<?php
if (IsSet(TABLICA_ASOCJACYJNA['zmienna']))
{
$zmienna = intval(TABLICA_ASOCJACYJNA['zmienna']);
}
mysql query("SELECT dane FROM tabela WHERE id=$zmienna");
?>

W przykładzie 8 użyto funkcji intval(), która rzutuje dane wprowadzone metodą GETPOST lub  COOKIE, na typ całkowity. Atakujący nie może użyć operatora UNION ani instrukcji SELECT, ponieważ funkcja  intval(), zamieni je na wartość liczbową. Zabezpieczenie tego typu jest odpowiednie, jeśli istnieje pewność, że dane są typu liczbowego. W skrypcie sprawdzane jest ustawienie zmiennej za pomocą jednego z trzech typów żądania HTTP. Następnie pod zmienną  zmienna  podstawiona jet wartość liczbowa z tablicy asocjacyjnej.

Błąd w tym skrypcie polega na sprawdzeniu, czy dane pochodzą tylko z jednego miejsca i jedynie takie dane są rzutowane. Jeżeli do pobrania danych zostanie wykorzystana metoda COOKIE, atakujący może użyć metody POST, a dane przesłane  takim żądaniem nie będą rzutowane, chociaż zostaną wykorzystane w zapytaniu SQL. Zmienna „zmienna” nie jest tu także ujęta w znaki apostrofów ani cudzysłowów, co jest kolejnym błędem.

Przykład 9:

<?php
if (IsSet(TABLICA_ASOCJACYJNA['zmienna']))
{
if (!get_magic_quotes_gpc())
{
$email = addslashes(TABLICA_ASOCJACYJNA['zmienna']);
}
else
{
$email = TABLICA_ASOCJACYJNA['zmienna'];
}
}
mysql_query("DELETE from tabela WHERE id='$zmienna'");
?>

W przykładzie 9 użyto zaprzeczenia funkcji get_magic_quotes(), w celu uniknięcia dublowania się znaków eskape’ujących, które są przyczyną niwelowania zabezpieczenia w postaci backslasha poprzedzającego niedozwolony znak w zapytaniu skierowanym do serwera. Jeżeli serwer skonfigurowano, z włączoną dyrektywą magic_quotes_gpc(), zmienna zmienna nie zostanie objęta funkcją addslashes(). W przeciwnym przypadku, jedynie funkcja addslashes() będzie używana do niwelowania działania niedozwolonych znaków.

Błąd w tym przykładzie polega na tym, że zapytanie SQL, jest wywoływane poza zasięgiem działania warunku sprawdzającego. W tym przypadku, jeżeli dane dostaną się do skryptu z innego miejsca niż jest to sprawdzane, mogą nie zostać objęte działaniem dyrektywy magic_quotes_gpc(), i atak może się udać.

Podsumowanie

W części czwartej serii JAK ZOSTAĆ EKSPERTEM OD SQL INJECTION pokazałem Ci jak wygląda przyczyna błędów opisywanych w częściach 1-3. Możesz zobaczyć praktyczne przykłady kodu źródłowego oraz bazy danych, co pozwala lepiej zobrazować istotę błędów.

W tym momencie po dogłębnym zrozumieniu treści z serii 1-4 jestem przekonany, że posiadasz już wystarczającą wiedzę – ekspercką wiedzę!

Co dalej? Dalej już tylko pozostaje działać – ja pokażę Ci wkrótce – w kolejnej części w jaki sposób stworzyć własny PoC.

Jeżeli spodobał Ci się artykuł, udostępnij go dalej oraz podziel się swoimi przemyśleniami w komentarzu.

Co w kolejnej części

W następnej części poradnika o tym JAK ZOSTAĆ EKSPERTEM OD SQL INJECTION wykorzystamy dotychczas zdobytą wiedzę do stworzenia własnego PoC. Zostańcie ze mną!

5 2 votes
Ocena artykułu
Subscribe
Powiadom o
guest
0 komentarzy
Inline Feedbacks
View all comments
0
Zależy mi na Twojej opinii poniżej 😀x