Wykrywanie XSS
Ten artykuł jest częścią serii o zagrożeniu XSS:
W tym artykule skupimy się na metodach wykrywania podatności typu XSS. Dowiesz się, w jaki sposób identyfikować potencjalnie zagrożone elementy aplikacji oraz jak weryfikować, czy rzeczywiście są one zagrożeniem.Zachęcam również do przeczytania pierwszego wpisy – o tym czym jest XSS i dlaczego jest groźny. W szczególności, gdy nie jesteś jeszcze zaznajomiony z tematem.
Ręcznie testowanie
Zacznijmy od tego, w jaki sposób samodzielnie wykrywać i weryfikować podatności XSS w aplikacji. Cały proces możemy podzielić na kilka następujących części.
Identyfikacja potencjalnego miejsca
Pierwszym krokiem zawsze jest analiza aplikacji (lub danej funkcjonalności) pod kątem miejsc, które potencjalnie mogą stać się punktem wejścia dla ataku.
W przypadku podatności XSS są to wszelkie miejsca, poprzez które użytkownik może wstawić do systemu dane tekstowe. W szczególności w sytuacji, gdy te dane są później dostępne dla innego użytkownika (lub użytkowników) w tej samej bądź innej aplikacji.
Dla uproszczenia można założyć, że niebezpieczne są wszelkie dane przekazywane:
- w adresie URLu,
- poprzez pola tekstowe w aplikacji,
- przez parametry requestów na API,
- poprzez upload plików.
Dla przykładu rozważmy aplikację – sklep internetowy. Załóżmy, że zidentyfikowaliśmy 3 potencjalne miejsca ataku w naszej aplikacji. Dla uproszczenia skupiamy się na wybranych przypadkach (w takiej aplikacji może istnieć dużo więcej “wejść” do systemu).
- parametr w URL przekazujący kod produktu
/item/[product_code]
- parametr w URL przekazujący nazwę do wyszukiwarki
?search=[search_phrase]
- imię, nazwisko i komentarz do zamówienia – jako pola tekstowe do wpisania.
Klasyfikacja podatności
Zidentyfikowane potencjalne podatne miejsce w aplikacji trzeba zaklasyfikować. Należy zacząć od przemyślenia, gdzie w aplikacji są dostępne wprowadzone przez nas dane. W zależności od tego będziemy mogli zaklasyfikować do jakiego rodzaju XSS należy dana podatność. Jeżeli:
- wprowadzony tekst wyświetla się od razu na ekranie, źródło tekstu jest zawarte w treści requestu HTTP (np. query parameter, header, User-Agent, itp.) to Reflected XSS;
- wprowadzony tekst zapisuje się do bazy danych i może się wyświetlić innemu użytkownikowi to Stored XSS;
- jeżeli wprowadzony tekst jest przetwarzany przez JavaScript i dopiero potem wyświetlany na ekranie to DOM-based XSS. W tym przypadku tekst może przyjść bezpośrednio z requestu lub z serwera. Dlatego można powiedzieć, że nie jest to osobny typ, lecz niejako dodatkowe utrudnienie w weryfikacji takiej podatności.
Najprościej to zweryfikować, gdy znamy kod aplikacji. Na szczęście nawet jeżeli to nie my ją stworzyliśmy, nadal możemy dokonać takiego sprawdzenia. Wystarczy odpowiedzieć sobie na dwa pytania:
- czy jest możliwość, że tekst wpisany przez jednego użytkownika zostanie wyświetlony innemu użytkownikowi?
- czy parametry requestu zawarte w adresie URL są wyświetlane na stronie?
W ten sposób zbadaliśmy z jakiego rodzaju podatnością możemy mieć do czynienia. Wróćmy do przykładu sklepu internetowego.
- parametr w URL przekazujący kod produktu
/item/[product_code]
– Reflected XSS, - parametr w URL przekazujący nazwę do wyszukiwarki
?search=[search_phrase]
– Reflected XSS, - imię, nazwisko i komentarz do zamówienia – jako pola tekstowe do wpisania – Stored XSS.
Weryfikacja podatności
Samo wyświetlenie wprowadzonego tekstu na stronie jeszcze nie oznacza problemów. To bardzo popularna i wygodna z punktu widzenia użytkownika praktyka.Dla przykładu Google tak wyświetla tekst, którego poszukujemy: https://www.google.com/search?q=test
Jeżeli takie wyświetlanie jest zrobione dobrze, nie stanowi problemu bezpieczeństwa.Najprostszą metodą na weryfikację, czy aplikacja jest podatna na XSS jest wykonania w ten sposób kodu, który uruchomi się w przeglądarce. Najłatwiej to zrobić, próbując po prostu uruchomić kod alert(1)
, który wyświetli okienko z wiadomością.
Bardzo trudno coś takiego przegapić podczas testowania, dzięki czemu łatwo można zweryfikować podatność.
Najprostszy przykład to próba wstawienia ciągu <script>alert(1)</script> w pole tekstowe lub parametr URL. W totalnie niezabezpieczonych aplikacjach to powinno zadziałać. Pod warunkiem że ten tekst jest bezpośrednio wstawiany w kod HTML, a nie w atrybut, kod CSS, itp. Wielu przypadkach istnieje jakaś przynajmniej podstawowa ochrona przed XSS, więc możemy być zmuszeni do użycia bardziej skomplikowanych tekstów. Na szczęście nie musimy tutaj wszystkiego wymyślać i próbować różnych kombinacji. Z pomocą przychodzą nam zestawienia takie jak https://owasp.org/www-community/xss-filter-evasion-cheatsheet. Zawierają one gotową listę formuł, które mogą służyć do obejścia filtrów XSS i wykonania kodu. Warto skorzystać z takiej pomocy przy weryfikacji.
Patrząc na nasz przykład, możemy po kolei sprawdzać, jak reaguje aplikacja na wstawianie różnego rodzaju wektorów ataku w miejsca o potencjalnej podatności. Jeżeli zobaczymy okienko z alertem przeglądarki, to znaleźliśmy podatność.Bardziej skomplikowanym przykładem jest przypadek trzeci, gdzie mamy powiązanie pomiędzy dwoma systemami. W ogólności wystarczy wstawić w pole podlegające podatności złośliwy kod i zapisać go do bazy. Następnie trzeba uruchomić drugą aplikację, w której można podejrzeć dane i po kolei przeglądać zapisane teksty. Jeżeli dla jakiegokolwiek rekordu zobaczymy na ekranie okienko alertu – znaleźliśmy podatność.
Narzędzia wspomagające
Gdybyśmy chcieli zweryfikować każde potencjalne miejsce w aplikacji, używając wielu różnych schematów tekstów, zajęłoby nam to sporo czasu. Zamiast tego dużo lepiej jest skorzystać z gotowych narzędzi.
Jednym z takich narzędzi jest OWASP ZAP (tutaj pełen opis możliwości tego programu []). Posiada on funkcje fuzzingu, co pozwala nam uruchomić określone funkcje (requesty sieciowe) w systemie dla wielu różnych tekstów wejściowych. Co więcej OWASP ZAP ma dostępne (do pobrania) słowniki zawierające najpopularniejsze wektory ataku XSS. Dzięki temu w przypadku podatności Stored XSS możemy bardzo szybko wypełnić bazę danymi zawierającymi różnorodne niebezpieczne teksty.
Poniżej skrócona instrukcja, jak to zrobić.
OWASP ZAP – fuzzing XSS
Zaczynamy od zidentyfikowanie wszystkich requestów wykonywanych przez nasz system.
Następnie znajdujemy interesujący nas request i przechodzimy do podglądu jego szczegółów.
Tam możemy zaznaczyć określony fragment requestu (który podejrzewamy o bycie potencjalnie podatnym miejscem), kliknąć prawym przyciskiem myszy i wybrać “Fuzz…”
W ten sposób otworzymy okno Fuzzera. W naszym przypadku wybieramy Payloads…
Następnie dodajemy payload.
Wybierając odpowiedni zbiór danych, które będą podstawiane pod zaznaczony fragment requestu.
Po zatwierdzeniu Fuzzingu będziemy mieli zapełniona bazę różnego rodzaju złośliwymi tekstami.
Żeby mieć dostęp do większej ilości słowników ataków XSS można zainstalować wtyczkę https://www.zaproxy.org/docs/desktop/addons/fuzzdb-offensive/
Podsumowanie
Podatności typu XSS wydają się być proste. Być może cały ten schemat wydaje się nieco przekomplikowany. Z jednej strony ciężko obecnie znaleźć podatności XSS tak proste jak <script>alert(1)</script>
, bo wiele aplikacji ma pewne podstawowe zabezpieczenia. Z drugiej jednak strony istnienie podatności XSS otwiera pole do popisu bardzo niebezpiecznym atakom o potencjalnie dużym wpływie na użytkowników systemu (np. kradzież tokenu wszystkim adminom systemu). Warto zatem poświęcić trochę energii na poszukiwanie tego typu podatności. A jak już ją znajdziemy, to prawidłowo ją poprawić (co opisuje w artykule Zabezpieczenie przed XSS).
Powiązane: