Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
OWASP Top Ten 2021: A05: Security Misconfiguration. Przegląd przypadków
Security Misconfiguration nie jest nowym punktem w OWASP TOP 10. Wręcz przeciwnie – pojawił się w każdej wersji tego standardu za wyjątkiem wydania z 2010 roku. Jego zakres jednak w każdej wersji odrobinę się zmienia. Najistotniejszą różnicą w najnowszej wersji OWASP Top Ten (z 2021 roku) w porównaniu do poprzedniej jest fakt, że teraz tutaj wlicza się podatność XXE (którą na Sekuraku opisywaliśmy kilka razy).
Zacznijmy jednak od podstaw. Mówiąc najbardziej ogólnie Security Misconfiguration dotyczy wszelkich błędów lub ryzyk bezpieczeństwa wynikających ze złej konfiguracji usług sieciowych, serwera lub jakichkolwiek innych komponentów. Poniżej kilka typowych przykładów (za OWASP-em):
- Brak hardeningu usług sieciowych lub niewłaściwie ustawione uprawnienia w usługach chmurowych,
- Włączenie niepotrzebnych funkcji (np. otwarcie niepotrzebnych portów, usług, stron, kont lub uprawnień),
- Stosowanie kont o domyślnych nazwach użytkowników i hasłach,
- Wyświetlanie stack trace’ów zawierających zbyt szczegółowe informacje o aplikacji lub środowisku,
- Nieodpowiednia konfiguracja serwerów aplikacyjnych, frameworków (np. Struts, Spring, ASP.NET), bibliotek i baz danych,
- Niewysyłanie tzw. nagłówków bezpieczeństwa.
Przejdziemy teraz przez kilka tego typu błędów oraz zobaczymy na konkretnych przykładach, dlaczego mogą stanowić one ryzyka.
Wyświetlanie dokładnej treści wyjątków
Przykład #1
To prawdopodobnie najczęściej występujący problem z kategorii Security Misconfiguration. Jego objawem jest fakt, że w momencie wystąpienia błędu/wyjątku po stronie aplikacji, treść tego wyjątku oraz stos wywołań (stack trace) jest zwracany użytkownikowi. Przykładowo poniżej autentyczny wyjątek zindeksowany przez Google gdzieś w domenie gov.pl
:
Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 1615 Prepared statement needs to be re-prepared in /home/sa-warszawa/ftp/oswiadczenia_csv.php:121
Stack trace:
#0 /home/sa-warszawa/ftp/oswiadczenia_csv.php(121): PDOStatement->execute()
#1 /home/sa-warszawa/ftp/index.php(196): include_once('/home/sa-warsza...')
#2 {main}
thrown in /home/sa-warszawa/ftp/oswiadczenia_csv.php on line 121
Tego typu wyjątek zdradza nam od razu kilka informacji:
- Wiemy, że aplikacja jest napisana w PHP,
- Znamy dokładne ścieżki do plików na serwerze,
- Wiemy, że aplikacja pod spodem korzysta z bazy danych MySQL/MariaDB (świadczy o tym charakterystyczny tekst komunikatu o błędzie).
Powyższe informacje nie są może bezpośrednio przydatne napastnikowi, ale mogą ułatwić przeprowadzenie innych ataków. Załóżmy, że w aplikacji występuje podatność Path Traversal (pozwalająca na odczyt dowolnych plików na dysku serwera), wówczas napastnik wie już, w których katalogach może szukać plików.
Przykład #2
Kolejnym ciekawym przykładem obrazującym jakie informacje można wyciągnąć ze stack trace jest strona beanstack.io. Poniżej fragment wyjątku z tej strony:
java.lang.IllegalStateException: On-the-fly migration has not been activated for this thread. Check servlet filters.
at com.continental.coremedia.migration.OnTheFlyMigrationController.resolveBean(OnTheFlyMigrationController.java:45)
at com.coremedia.objectserver.web.AbstractViewController.handleRequestInternal(AbstractViewController.java:169)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
[...]
Tym razem nie uzyskujemy dokładnych ścieżek do plików na dysku serwera, ale poznajemy nazwy pakietów, klas i metod Javy oraz nazwy plików wraz z numerami linii.
Na powyższym błędu szybko możemy zauważyć, że aplikacja korzysta z frameworka Spring. Ale okazuje się, że można też ustalić jego dokładną wersję! Nazwy metod i ich numery linii mogą się różnić pomiędzy poszczególnymi wersjami frameworka – i ta subtelna różnica pozwala ustalić, jaka dokładne wersja (lub jaki zakres wersji) jest używany na serwerze. Na podstawie stack trace’a zacytowanego wyżej, beanstack jest w stanie ustalić, że wersja Springa to 3.2.x.
Przykład #3
Wyświetlanie treści wyjątków bywa też bardzo pomocne w wykorzystaniu SQL Injection (i innych podobnych podatności). Ze względu na specyfikę niektórych aplikacji, czasem nie można wykorzystać SQL Injection w najszybszym wariancie, tj. tzw. UNION-based SQL Injection. Jeśli jednak napastnik widzi treści wyjątków, może ich nadużyć do wydobycia danych z bazy. Jest to tzw. error based SQL Injection. Wiele lat temu opisywaliśmy na Sekuraku możliwość użycia funkcji EXTRACTVALUE
w MySQL/MariaDB do tego celu.
Ale może zobaczmy przykład z innej bazy danych, tj. PostgreSQL. Jeśli napastnik dysponuje możliwością wykorzystania SQL Injection i aplikacja wyświetla komunikaty o błędach, wówczas może poznać wersję bazy danych używając następującego zapytania:
SELECT CAST(VERSION() AS INT)
Postgres spróbuje rzutować wynik wykonywania funkcji VERSION()
na typ liczbowy, co zakończy się niepowodzeniem (jako że wersja zawiera znaki niebędące cyframi). I wyrzuci wyjątek podobny do:
ERROR: invalid input syntax for type integer: „PostgreSQL 13.4 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.4.1 20200928 (Red Hat 8.4.1-1), 64-bit„
W ten oto sposób napastnik może poznać wynik wykonywania swojego zapytania. Oczywiście w miejsce wyciągania wersji, możliwe jest wydobycie dowolnych innych danych z bazy.
Ujawnienie wersji oprogramowania
Drugim najsłynniejszym reprezentantem błędów z serii Security Misconfiguration jest ujawnianie wersji oprogramowania. Często tego typu informacje można znaleźć w nagłówkach HTTP takich jak Server
czy X-Powered-By
.
Wyobraźmy sobie, że napastnik bada bezpieczeństwo pewnej aplikacji webowej, która w odpowiedzi zwraca następujący nagłówek HTTP:
Server: Apache/2.4.49
Naturalny następny krok to przeszukanie Internetu pod kątem występowania znanych podatności w tej wersji Apache i wylądowanie np. na Sekuraku, z którego dowiaduje się, że jest ona podatna na RCE oraz Path Traversal. Napastnik ma więc easy-win i może od razu wykonać złośliwy kod na serwerze lub odczytać dowolne pliki.
W takim przypadku ujawnienie typu serwera i jego wersji bardzo ułatwia zadanie napastnikom, bo niejako „kawa na ławę” dostają konkretne informacje o oprogramowaniu. Zwróćmy jednak uwagę, że clou problemu jest tutaj fakt, że ta wersja Apache jest zainstalowana na serwerze. Niezależnie od tego, czy dokładna wersja jest ujawniona czy nie, podatność nadal występuje.
Pamiętajmy zatem, że samo „schowanie” informacji o wersji nie rozwiązuje naszego problemu bezpieczeństwa. Zdeterminowany napastnik mógłby tak czy owak spróbować przejść po wszystkich znanych exploitach na różne wersje serwera Apache i prędzej czy później trafiłby na ten konkretny. Dlatego istotny jest fakt aktualizacji oprogramowania, jeśli występuje w nim znany błąd bezpieczeństwa (tego dotyczy też inny punkt z OWASP Top Ten: A06: Vulnerable and Outdated Components), a nie tylko „przemilczenie” faktu, że taka wersja jest używana.
XXE – XML eXternal Entity
W poprzedniej wersji OWASP Top Ten, podatność XXE miała swój własny punkt. Teraz jest częścią Security Misconfiguration. Zacznijmy jednak od szybkiego omówienia czym ta podatność jest.
W standardzie XML-u niektóre znaki możemy pisać w postaci tzw. encji. Np. jeśli chcemy w środku atrybutu XML-owego umieścić znak <
, to musimy enkodować go do postaci <
. Analogicznie, znak "
będziemy musieli czasem zapisywać w postaci encji "
. Tego typu encji jest jeszcze więcej. To co jednak jest istotne z punktu widzenia podatności bezpieczeństwa, to fakt, że encje można również definiować sobie samemu.
Przykładowo, rozważmy poniższy plik XML.
<!DOCTYPE x [
<!ENTITY s "Witamy na Sekuraku!">
]>
<root>
&s;
</root>
Po przetworzeniu tego pliku, zawartością tagu <root>
będzie tekst znajdujący się w encji &s;
. Ta encja została zdefiniowana w drugiej linii. Więc w środku <root>
znajdzie się tekst Witamy na Sekuraku!
.
Standard XML przewiduje dodatkowo możliwość definiowania encji w taki sposób, że zostaną załadowane z zewnętrznego pliku. Przykład:
<!DOCTYPE x [
<!ENTITY s SYSTEM "/etc/passwd">
]>
<root>
&s;
</root>
W tym przypadku słowo kluczowe SYSTEM
sprawia, że zawartość encji &s;
zostanie załadowana z zewnętrznego pliku: /etc/passwd
. W momencie, gdy serwer przetworzy taki dokument XML, napastnik pozna zawartość /etc/passwd
lub dowolnego innego pliku na dysku.
Typowa obrona przed XXE polega na wyłączeniu przetwarzania encji lub elementu <!DOCTYPE
w parserze XML. (szersze informacje na temat obrony można znaleźć na OWASP-ie).
Rzeczywiście więc podatność XXE może zostać zaklasyfikowana jako Security Misconfiguration, bowiem typowy sposób naprawy polega na zmianie konfiguracji parsera.
Ochrona przed CSRF w Spring Security
Spring to bardzo popularny framework do pisania aplikacji w Javie. Dzięki Spring Security można w swojej aplikacji łatwo zaimplementować mechanizmy ochronne przed często występującymi podatnościami, np. CSRF.
W ramach szybkiego przypomnienia: podatność CSRF polega na możliwości zmuszenia przeglądarki do wysyłania zapytań do innej aplikacji webowej, wykonując w ten sposób jakąś akcję. Przykładowo, mamy aplikację, która pod adresem https://example.com/delete-account
pozwala usunąć konto. Ta akcja wyzwalana jest metodą GET i nie wymaga dodatkowego potwierdzenia (tak, tego typu sytuacje naprawdę się zdarzają).
Wówczas dowolna inna strona w internecie mogłaby zawierać następujący fragment HTML-a:
<img src="https://example.com/delete-account">
Przeglądarka, próbując pobrać ten obrazek, wysłałaby zapytanie do https://example.com/delete-account
. Jeśli użytkownik akurat byłby zalogowany w serwisie example.com
, jego konto zostałoby usunięte…
Wspomniany wcześniej projekt Spring Security ma wbudowane zabezpieczenie przed podatnością CSRF. Polega ono na dodawaniu do zapytań dodatkowego tokena weryfikującego autentyczność zapytania.
W zależności od używanej wersji Spring Security, to zabezpieczenie może być domyślnie wyłączone (tak było dawniej), lub domyślnie włączone (tak jest w najnowszych wersjach). Jeśli więc w naszej aplikacji natrafimy na fragment kodu podobny do poniższego:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
}
To mamy kolejny przykład błędu z kategorii Security Misconfiguration – bowiem wyłączamy jeden z domyślnych mechanizmów bezpieczeństwa.
Nagłówki bezpieczeństwa
W odpowiedziach HTTP można zdefiniować szereg nagłówków, które zwiększają bezpieczeństwo aplikacji: np. takie nagłówki jak Strict-Transport-Security
, X-Content-Type-Options
czy Referrer-Policy
.
Brak ich wdrożenia może być traktowany jako niewłaściwa konfiguracja serwera. Swego czasu na Sekuraku opisywaliśmy kilka podstawowych nagłówków (i innych praktyk), które warto wdrożyć w każdej aplikacji.
Podsumowanie
W tym artykule zawarliśmy kilka przykładów błędów kwalifikujących się pod punkt Security Misconfiguration w najnowszej wersji OWASP TOP 10. Największą różnicą pomiędzy obecną wersją standardu, a poprzednimi jest fakt, że teraz do tego punktu wlicza się też podatność XXE oraz inne podobne błędy na poziomie programistycznym.
Jeśli chcesz zapisać się na szkolenie z 50% rabatem – zobacz tutaj.
— Michał Bentkowski, prowadzi szkolenie: praktyczne wprowadzenie do OWASP Top Ten
Pouczajacy artykulik.
Dziekuje!