Kilku osobom udało się znaleźć oczywistą podatność (patrz Podatności stają się oczywiste II). Jeśli komuś się jeszcze nie udało, to podpowiem, że podatny jest parametr pRadio, przy czym podatność występuje wtedy, gdy walidator (jedyny walidator to walidacja kodu pocztowego) rozpozna wpisany kod jako nieprawidłowy. Wówczas wartość przekazana w pRadio wypisywana jest w skrypcie JavaScript bez właściwego kodowania znaków specjalnych. Efekt prosty do przewidzenia - XSS. Pora na wyjaśnienia głębszego sensu tego przykładu.
Podatności stają się oczywiste III
Podatności wcale nie muszą być oczywiste (na początku)
Pierwsza rzecz, którą chciałem pokazać to fakt, że podatności stają się oczywiste, jak się już znajdzie. Tak, dokładnie to, co napisałem w tytule pierwszego wpisu na ten temat. Chodzi mi tu przede wszystkim o pewien schemat, mechanizm, który prowadzi do wystąpienia podatności. W tym przykładzie jest to wypisywanie danych w kontekście JavaScript bez odpowiedniego kodowania znaków specjalnych. W chwili znalezienia pierwszej tego typu podatności może okazać się, że schemat ten jest powtarzalny, działa również w innych miejscach. Jeśli tak jest, oznacza to, że cały schemat wymaga poprawy. Jeśli w kilku przypadkach okazuje się, że w pewnym przypadku dane wypisywane są bez encodingu, to można zakładać, że takich przypadków jest więcej. Odnosząc się do fragmentu komentarza, którego autorem jest piXi:
(...) 4. zdanie nielogiczne... trudno zalatac cos (nawet majac najlepsze procedury) jezeli sie tego "nie odnajdzie" najpierw...
Fakt braku encodingu danych wyjściowych w pewnym kontekście w kilku przypadkach (jeden schemat) powinien być wystarczającym sygnałem, by przy usuwaniu podatności wyszukać inne miejsca, w których schemat ten był zastosowany i wprowadzić stosowne poprawki, tego powinna wymagać "najlepsza procedura". Analogicznie w innych przypadkach. Kilka SQLi w miejscach, w których przez reguły walidacji przechodzi, pewnie przypadkiem, znak ' (apostrof) jest wystarczającym sygnałem, że zapytania SQL w aplikacji budowane są niepoprawnie, a prawdopodobnie jedyną warstwą ochrony przed SQLi jest walidacja danych wejściowych.
A to niespodzianka, tego jeszcze nie widziałem!
Druga rzecz, to kierowanie się wcześniejszą wiedzą/doświadczeniami. Wiele z osób próbujących znaleźć podatność testowało parametry związane z miejscami, gdzie użytkownik może wprowadzić swoje dane z GUI i szukała sposobu na oszukanie encodingu w drugim kroku. Gdy to nie działało, analogiczne próby były wykonywane z parametrami związanymi z parametrami, do wartości których użytkownik nie ma bezpośredniego dostępu (co nie znaczy, że nie może ich zmienić), nadal szukając skutków swoich działań w drugim kroku. Tak rzeczywiście zwykle (a przynajmniej bardzo często) wygląda schemat reflected XSS, w tym wypadku schemat jest jednak nieco inny.
Tu, moim zdaniem, mamy do czynienia z pewnym paradoksem. Z jednej strony im więcej przetestowanych aplikacji, tym większe doświadczenie, większe zgromadzona "baza wiedzy". Teoretycznie powinno to być pomocne, ale czasami okazuje się, że zamiast pomagać - przeszkadza. Po prostu w pewnej chwili patrząc przez pryzmat zgromadzonej "bazy wiedzy" trudno dostrzec coś nowego. Co więcej można na bazie dotychczasowych doświadczeń poczynić pewne założenia, które akurat w tym jednym konkretnym przypadku okażą się nieuprawnione. Ten temat zresztą planuję rozwinąć w przyszłości.
Ile podatności mieści się na jednym parametrze?
Trzecia kwestia to fakt, że jedne podatności zasłaniają drugie. Nigdzie nie jest powiedziane, że w jednym parametrze może wystąpić tylko jedna podatność, nie ma też normy "liczby podatności na punkt wejścia". Może okazać się, że w jednym parametrze jest komplet, XSS, SQLi oraz brak kontroli dostępu. Czasami znajdując coś "grubego", nie zwraca się już wystarczającej uwagi na potencjalnie mniejsze rzeczy. W tym (hipotetycznym) przykładzie "ważność" trzech podatności można uszeregować w sposób następujący:
- SQLi - możliwość wykonania dowolnego kodu w bazie danych, w szczególności odczyt dowolnych danych,
- brak kontroli dostępu - dostęp do cudzych danych,
- XSS - to już zależy od konkretnego scenariusza,
Może się zdarzyć, że skupiając się na stworzeniu PoC dla znalezionego SQLi, na brak kontroli dostępu lub kompletnie "mniej interesujący" XSS uwagi się już nie zwróci. Zdarzają się również sytuacje, kiedy w dwóch przypadkach na trzy (w "zbliżonych" funkcjach) występuje tylko XSS i brak kontroli dostępu, ale w tym trzecim przypadku w ramach bonusu programiści dorzucili jeszcze SQLi. W takim przypadku do głosu może dojść problem z punktu drugiego. Bazując na wcześniej zdobytej wiedzy można założyć, że również w tym przypadku występują tylko te dwie podatności, rezultatem czego może być pominięcie podatności na SQLi.
Czy słonia można zafortepianić?
Czwarta kwestia, na którą chcę zwrócić uwagę, to fakt, że trudno jest pokryć testami 100% aplikacji, każdy przypadek użycia, każdy możliwy sposób interakcji użytkownika z aplikacją, każdą możliwą kombinację parametrów na formatkach (...). Nie jest to zresztą problem wyłącznie testów bezpieczeństwa, w testach funkcjonalnych (czy szerzej - testach QA) również pokrycie aplikacji testami zwykle nie jest pełne. Część funkcji, tych najbardziej widocznych, związanych z typowymi przypadkami użycia testowanych jest dokładniej, natomiast mniej używane funkcje mogą nie być testowane wcale.
Różnica między testami funkcjonalnymi a testami bezpieczeństwa jest taka, że w przypadku testów funkcjonalnych może okazać się, że 0,3% użytkowników aplikacji dotyka jakiś błąd (nawet poważny, niech będzie to utrata danych), w przypadku pozostałych 99,7% użytkowników aplikacja działa poprawnie. Skutki podatności znajdującej się w funkcji wykorzystywanej przez 0,3% użytkowników mogą dotknąć wszystkich, również tych 99,7%, który z podatnej funkcji nie korzystają. Podkreślam jeszcze raz mogą, a nie muszą. Szczególne nieprzyjemny pod tym względem jest SQLi. Jeśli nie zostaną zastosowane dodatkowe ograniczenia w warstwie bazy danych, podatność w najbardziej zapomnianym punkcie wejścia może pozwolić na odczytanie dowolnych danych z bazy, że o ataku na system operacyjny nie wspomnę.
We wpisie Testy penetracyjne: dekompozycja aplikacji poruszałem już temat określania, które punkty wejścia powinny być testowane w pierwszej kolejności. Do tego tematu również wrócę.
I po co to wszystko?
Po co to wszystko piszę? Powód jest prosty - budowanie bezpieczeństwa aplikacji nie może opierać się tylko na wyszukiwaniu podatności i łataniu tych znalezionych. Podejście takie jest po prostu nieefektywne, choćby dlatego, że testy bezpieczeństwa nie gwarantują znalezienia wszystkich istotnych podatności, nawet tych "oczywistych". Oczywiście, można próbować usprawniać proces testowania bezpieczeństwa (i to jest drugi powód - chcę pokazać kilka obszarów, które można usprawnić), ale to nie wystarczy. Konieczna jest modyfikacja procesu tworzenia oprogramowania (tak, ja znowu o tym samym), jest już kilka wzorców, wystarczy wspomnieć o Microsoft SDL, OpenSAMM (Software Assurance Maturity Model) czy BSIMM. Testy bezpieczeństwa powinny być jedynie elementem procesu wbudowywania bezpieczeństwa w aplikację, a ich rezultaty powinny wpływać na modyfikację wcześniejszych elementów procesu. Elementem ważnym, ale nie jedynym(!) I będę powtarzał to do znudzenia, bo szukania SQLi i XSSów mam już dość.
Obecnie w ramach przewodnika po bezpieczeństwie aplikacji internetowych udostępnione jest 18 przykładów. Przykłady dotyczą różnych aspektów bezpieczeństwa oraz testowania aplikacji internetowych, po części po to, by pokazać, że testy penetracyjne wcale ni
Przesłany: Jan 13, 08:50