Testy penetracyjne: dekompozycja aplikacji

Powrót do tematu testów penetracyjnych. Co zrobić, by test nie był wyrywkowy? Jak zagwarantować, że aplikacja zostanie sprawdzona dokładnie (oczywiście z uwzględnieniem ograniczeń czasowych)? Cóż, trzeba zrozumieć aplikację. A najlepiej rozłożyć ją na części składowe. Na przykład zidentyfikować punkty wejścia.

Podstawowa zasada...

Podstawowa zasada: aplikacja może zostać zaatakowana, jeśli intruz ma możliwość interakcji z nią. Bez interakcji ciężko mówić o możliwości ataku. A interakcja możliwa jest przez punkty wejścia. Koncepcja punktów wejścia oraz przepływu sterowania/danych jest intensywnie wykorzystywana w procesie modelowania zagrożeń. Pewna uproszczona forma sprawdza się, moim zdaniem, również przy testach penetracyjnych aplikacji webowej.

Punkty wejścia w praktyce

Jeśli patrzymy na aplikację webową, można znaleźć następujące punkty wejścia:

Nie jest to pełna lista, bo brakuje na niej na przykład bazy danych, plików konfiguracyjnych aplikacji, ewentualnych usług łączących badaną aplikację z backendem. Do wymienionych tutaj punktów wejścia intruz działający z sieci Internet zwykle nie ma dostępu. Oczywiście sytuacja się zmienia, jeśli okaże się, że baza danych jest również dostępna w sieci, a hasło do niej wcale nie jest takie trudne.

Poszczególne punkty wejścia mogą nakładać się na siebie. Dla przykładu może wyglądać to w sposób następujący:

  1. adres 192.168.1.100,
    1. port 80,
      1. /produkty
      2. szukaj,
      3. szczegóły,
    2. port 443,
      1. /login
      2. /settings
      3. zapisz,
      4. zmień hasło,

Jest to przykład prostej aplikacji, która pozwala na przeglądnięcie listy produktów, po uprzednim uwierzytelnieniu się (po SSL). W ramach przeglądania produktów możliwe jest ich wyszukiwanie (akcja szukaj), oraz obejrzenie szczegółów interesującego produktu (akcja szczegóły). Poza uwierzytelnieniem po SSL dostępne jest również proste menu, które pozwala na zmianę podstawowych ustawień i zmianę hasła.

Jak widać podstawowym punktem wejścia jest adres IP, na nim z kolei dwa otwarte porty (80 i 443), a na nich ścieżki i akcje dostępne w ramach ścieżek. Pełne rozpisanie/rozrysowanie aplikacji w ten sposób może być pracochłonne, warto to jednak zrobić. Dla mnie do tego zadania dobrze sprawdza się FreeMind, choć podejrzewam, że na przykład Visio sprawdzało by się równie dobrze.

Teraz dla każdego punktu wejścia można określić przeprowadzane testy. W przypadku adresu IP (czyli w zasadzie serwera) może to być na przykład skanowanie portów, w celu ustalenia, czy są dostępne jakieś zbędne usługi. Dla otwartych portów to w znacznym stopniu analiza dostępnych usług, wersji oprogramowania, konfiguracji, reakcji na nieoczekiwane sytuacje. Dla punktów wejścia w samej aplikacji to przede wszystkim analiza przekazywanych do aplikacji parametrów. Przykładowo dla przypadku 1.2.1 będą to przykładowo dwa parametry plogin_ i ppassword_ , dla przypadku 1.1.1.2 może to być pid_ określający identyfikator produktu.

Dla każdego parametru w ramach każdego punktu wejścia wykonywana jest grupa testów, ale jakie są to testy, to już zależy od konkretnego przypadku. W przykładzie 1.1.1.2 prawdopodobnie byłyby to testy związane z sql injection , bo prawdopodobnie parametr ten jest wstawiany w warunek zapytania SQL wyciągający informację o danym produkcie:

(...) WHERE id=identyfikator_produktu

W zależności od tego, czy pid_ jest walidowane oraz tego w jaki sposób wartość parametru jest wstawiana do zapytania, w aplikacji może istnieć możliwość wykonania własnego kodu SQL...

Kto ma dostęp?

Przy analizie punktów wejścia warto określić, kto ma do poszczególnych punktów dostęp. W szczególności, czy są to:

Im bardziej “otwarta” jest dana funkcjonalność (dostęp do niej ma większa grupa osób), tym dokładniej powinna być sprawdzona. Podobnie można określić, która z funkcji jest wykorzystywana najczęściej. Tutaj w grę wchodzi czysta statystyka, im więcej użytkowników często korzysta z danej funkcji, tym większa szansa, że któryś z nich będzie miał “złe zamiary”, znajdzie i wykorzysta podatność. Z drugiej strony, im bardziej “zaufany” użytkownik, tym ryzyko związane z ewentualną podatnością może być mniejsze. Przykładowo po co administrator aplikacji miałby wykorzystywać sql injection w interfejsie administracyjnym, jeśli w ramach swoich obowiązków ma bezpośredni dostęp do bazy.

Warto zwrócić uwagę, że identyfikacja podatności nie jest jednocześnie analizą ryzyka. Znalezione podatności można jeszcze wycenić określając związane z daną podatnością ryzyko. To jednak też zupełnie oddzielny temat, choć tutaj ponownie wspomnę o metodologii DREAD, która mimo swoich niedoskonałości, jest mimo wszystko lepsza, niż brak jakiejkolwiek metodologii.

Punkty wejścia to nie wszystko

Analiza wszystkich punktów wejścia to nie wszystko, choć pozwala na identyfikację sporej liczby podatności. Przez większość czasu zadanie to nie jest ani zbyt odkrywcze, ani pasjonujące. Jeśli jednak testy są przeprowadzane na zasadzie “radosnego bughuntingu”, może się nagle okazać, że w jakiejś misternie ukrytej, sporadycznie używanej funkcji znajduje się podatność, która pozwala na ujawnienie wszystkich danych z bazy. Podejście oparte na gruntownej analizie aplikacji zmniejsza szansę, że ta funkcja zostanie pominięta.

Kolejna istotna kwestia to przypadki użycia , a w szczególności próby postępowania w sposób inny od oczekiwanego, ale o tym to już w kolejnym odcinku. No i zostaje zawsze jeszcze coś takiego, jak intuicja (zwana również wrodzoną zdolnością do skutecznego szukania dziury w całym).

Oryginał tego wpisu dostępny jest pod adresem Testy penetracyjne: dekompozycja aplikacji

Autor: Paweł Goleń