hacktricks/network-services-pentesting/pentesting-web/nginx.md

18 KiB
Raw Blame History

Nginx

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Natychmiastowa konfiguracja do oceny podatności i testów penetracyjnych. Uruchom pełne testy penetracyjne z dowolnego miejsca za pomocą 20+ narzędzi i funkcji, które obejmują rozpoznanie, aż po raportowanie. Nie zastępujemy pentesterów - rozwijamy niestandardowe narzędzia, moduły wykrywania i eksploatacji, aby umożliwić im zagłębienie się głębiej, przejęcie kontroli i dobrą zabawę.

{% embed url="https://pentest-tools.com/" %}

Brakujące miejsce root

Podstawy konfigurowania katalogu głównego Nginx

Podczas konfigurowania serwera Nginx, dyrektywa root odgrywa kluczową rolę, definiując katalog bazowy, z którego są serwowane pliki. Rozważ poniższy przykład:

server {
root /etc/nginx;

location /hello.txt {
try_files $uri $uri/ =404;
proxy_pass http://127.0.0.1:8080/;
}
}

W tej konfiguracji /etc/nginx jest określony jako katalog główny. Ta konfiguracja umożliwia dostęp do plików w określonym katalogu głównym, takich jak /hello.txt. Jednakże ważne jest zauważenie, że zdefiniowana jest tylko określona lokalizacja (/hello.txt). Brak konfiguracji dla lokalizacji głównej (location / {...}). Ta omissja oznacza, że dyrektywa root jest stosowana globalnie, umożliwiając żądania do ścieżki głównej / w celu uzyskania dostępu do plików znajdujących się w /etc/nginx.

Z tej konfiguracji wynika istotne zagrożenie dla bezpieczeństwa. Prosty żądanie GET, na przykład GET /nginx.conf, może ujawnić poufne informacje poprzez udostępnienie pliku konfiguracyjnego Nginx znajdującego się w /etc/nginx/nginx.conf. Ustawienie roota na mniej wrażliwy katalog, na przykład /etc, może zmniejszyć to ryzyko, ale nadal może umożliwiać niezamierzony dostęp do innych istotnych plików, w tym innych plików konfiguracyjnych, logów dostępu, a nawet zaszyfrowanych poświadczeń używanych do autentykacji podstawowej protokołu HTTP.

Konfiguracja Alias LFI

W plikach konfiguracyjnych Nginx konieczna jest dokładna inspekcja dyrektyw "location". Podatność znana jako Local File Inclusion (LFI) może zostać nieumyślnie wprowadzona poprzez konfigurację, która przypomina poniższy przykład:

location /imgs {
alias /path/images/;
}

Ta konfiguracja jest podatna na ataki LFI, ponieważ serwer interpretuje żądania takie jak /imgs../flag.txt jako próbę dostępu do plików spoza zamierzonego katalogu, efektywnie rozwiązując się do /path/images/../flag.txt. Ta wada pozwala atakującym na pobieranie plików z systemu plików serwera, do których nie powinno być dostępu przez sieć.

Aby złagodzić tę podatność, konfiguracja powinna zostać dostosowana do:

location /imgs/ {
alias /path/images/;
}

Więcej informacji: https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/

Testy Accunetix:

alias../ => HTTP status code 403
alias.../ => HTTP status code 404
alias../../ => HTTP status code 403
alias../../../../../../../../../../../ => HTTP status code 400
alias../ => HTTP status code 403

Niebezpieczne ograniczenie ścieżki

Sprawdź następującą stronę, aby dowiedzieć się, jak ominąć dyrektywy takie jak:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Niestabilne użycie zmiennej / Podział żądania HTTP

{% hint style="danger" %} Narażone zmienne $uri i $document_uri mogą zostać naprawione poprzez ich zastąpienie przez $request_uri.

Regex może również być podatne, na przykład:

location ~ /docs/([^/])? { … $1 … } - Narażone

location ~ /docs/([^/\s])? { … $1 … } - Niepodatne (sprawdzanie spacji)

location ~ /docs/(.*)? { … $1 … } - Niepodatne {% endhint %}

Przykład podatności w konfiguracji Nginx jest przedstawiony poniżej:

location / {
return 302 https://example.com$uri;
}

Znaki \r (powrót karetki) i \n (nowa linia) oznaczają nowe znaki w żądaniach HTTP, a ich zaszyfrowane w formie URL są reprezentowane jako %0d%0a. Włączenie tych znaków w żądaniu (np. http://localhost/%0d%0aDetectify:%20clrf) do źle skonfigurowanego serwera skutkuje wydaniem przez serwer nowego nagłówka o nazwie Detectify. Dzieje się tak, ponieważ zmienna $uri dekoduje zaszyfrowane w formie URL znaki nowej linii, co prowadzi do nieoczekiwanego nagłówka w odpowiedzi:

HTTP/1.1 302 Moved Temporarily
Server: nginx/1.19.3
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: https://example.com/
Detectify: clrf

Dowiedz się więcej o ryzyku wstrzykiwania CRLF i podziału odpowiedzi na https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.

Ta technika jest również wyjaśniona w tej prezentacji z przykładami podatności i mechanizmami wykrywania. Na przykład, aby wykryć tę konfigurację z perspektywy blackbox, można użyć tych żądań:

  • https://example.com/%20X - Dowolny kod HTTP
  • https://example.com/%20H - 400 Bad Request

Jeśli jest podatny, pierwsze żądanie zwróci "X", ponieważ "X" to dowolna metoda HTTP, a drugie spowoduje błąd, ponieważ "H" nie jest poprawną metodą. Serwer otrzyma coś w rodzaju: GET / H HTTP/1.1, co spowoduje błąd.

Inne przykłady wykrywania to:

  • http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x - Dowolny kod HTTP
  • http://company.tld/%20HTTP/1.1%0D%0AHost:%20x - 400 Bad Request

Niektóre znalezione podatne konfiguracje przedstawione w tej prezentacji to:

  • Zauważ, jak $uri jest ustawione tak, jak jest w końcowym adresie URL.
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
  • Zauważ, jak ponownie $uri znajduje się w adresie URL (tym razem wewnątrz parametru)
location ~ ^/dna/payment {
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
proxy_pass http://$back;
  • Teraz w AWS S3
location /s3/ {
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
}

Dowolna zmienna

Odkryto, że dane dostarczone przez użytkownika mogą być traktowane jako zmienna Nginx w określonych okolicznościach. Przyczyna tego zachowania pozostaje w pewnym stopniu niejasna, ale nie jest rzadka ani łatwa do zweryfikowania. To anomalie zostało podkreślone w raporcie bezpieczeństwa na HackerOne, który można zobaczyć tutaj. Dalsze dochodzenie w sprawie komunikatu o błędzie doprowadziło do zidentyfikowania jego występowania w module filtru SSI kodu źródłowego Nginx, wskazując na Server Side Includes (SSI) jako główną przyczynę.

Aby wykryć tę błędną konfigurację, można wykonać następujące polecenie, które polega na ustawieniu nagłówka referer w celu przetestowania drukowania zmiennej:

$ curl -H Referer: bar http://localhost/foo$http_referer | grep foobar

Skanowania dla tej konfiguracji na różnych systemach ujawniły wiele przypadków, gdzie zmienne Nginx mogły być wydrukowane przez użytkownika. Jednak spadek liczby podatnych przypadków sugeruje, że wysiłki w celu załatania tego problemu były do pewnego stopnia skuteczne.

Odczyt surowej odpowiedzi z backendu

Nginx oferuje funkcję poprzez proxy_pass, która pozwala na przechwytywanie błędów i nagłówków HTTP generowanych przez backend, mając na celu ukrycie wewnętrznych komunikatów o błędach i nagłówków. Jest to osiągane poprzez serwowanie Nginx niestandardowych stron błędów w odpowiedzi na błędy backendu. Jednak pojawiają się wyzwania, gdy Nginx napotyka nieprawidłowe żądanie HTTP. Takie żądanie jest przekazywane do backendu w otrzymanej postaci, a surowa odpowiedź backendu jest następnie bezpośrednio wysyłana do klienta bez interwencji Nginx.

Rozważmy przykładowy scenariusz dotyczący aplikacji uWSGI:

def application(environ, start_response):
start_response('500 Error', [('Content-Type', 'text/html'), ('Secret-Header', 'secret-info')])
return [b"Secret info, should not be visible!"]

Aby to zarządzać, używane są konkretne dyrektywy w konfiguracji Nginx:

http {
error_page 500 /html/error.html;
proxy_intercept_errors on;
proxy_hide_header Secret-Header;
}
  • proxy_intercept_errors: Ta dyrektywa umożliwia Nginxowi obsługę niestandardowej odpowiedzi dla odpowiedzi z backendu z kodem stanu większym niż 300. Zapewnia, że dla naszej przykładowej aplikacji uWSGI odpowiedź 500 Error jest przechwytywana i obsługiwana przez Nginx.
  • proxy_hide_header: Jak sugeruje nazwa, ta dyrektywa ukrywa określone nagłówki HTTP przed klientem, poprawiając prywatność i bezpieczeństwo.

Gdy zostanie wysłane prawidłowe żądanie GET, Nginx przetwarza je normalnie, zwracając standardową odpowiedź błędu, nie ujawniając żadnych poufnych nagłówków. Jednakże nieprawidłowe żądanie HTTP omija ten mechanizm, co skutkuje ujawnieniem surowych odpowiedzi z backendu, w tym poufnych nagłówków i komunikatów błędów.

merge_slashes ustawione na off

Domyślnie dyrektywa merge_slashes Nginxa jest ustawiona na on, co kompresuje wiele ukośników w przekierowaniu URL do pojedynczego ukośnika. Ta funkcja, podczas upraszczania przetwarzania URL, może niechcący ukrywać podatności w aplikacjach za Nginx, zwłaszcza tych podatnych na ataki lokalnego dołączania plików (LFI). Eksperci ds. bezpieczeństwa Danny Robinson i Rotem Bar zwrócili uwagę na potencjalne ryzyko związane z tym domyślnym zachowaniem, zwłaszcza gdy Nginx działa jako odwrotny proxy.

Aby zmniejszyć takie ryzyko, zaleca się wyłączenie dyrektywy merge_slashes dla aplikacji podatnych na te podatności. Zapewnia to, że Nginx przekazuje żądania do aplikacji bez zmiany struktury URL, nie maskując żadnych istniejących problemów z bezpieczeństwem.

Aby uzyskać więcej informacji, sprawdź Danny Robinson i Rotem Bar.

Wartość domyślna w dyrektywie Map

W konfiguracji Nginx, dyrektywa map często odgrywa rolę w kontroli autoryzacji. Powszechnym błędem jest nieokreślenie wartości domyślnej, co może prowadzić do nieautoryzowanego dostępu. Na przykład:

http {
map $uri $mappocallow {
/map-poc/private 0;
/map-poc/secret 0;
/map-poc/public 1;
}
}
server {
location /map-poc {
if ($mappocallow = 0) {return 403;}
return 200 "Hello. It is private area: $mappocallow";
}
}

Bez default, złośliwy użytkownik może ominąć zabezpieczenia, uzyskując dostęp do niezdefiniowanego URI wewnątrz /map-poc. Podręcznik Nginx zaleca ustawienie wartości domyślnej, aby uniknąć takich problemów.

Podatność na DNS Spoofing

Podatność na DNS spoofing w przypadku Nginx jest wykonalna w określonych warunkach. Jeśli atakujący zna serwer DNS używany przez Nginx i może przechwycić jego zapytania DNS, może sfałszować rekordy DNS. Metoda ta jednak nie działa, jeśli Nginx jest skonfigurowany do korzystania z localhost (127.0.0.1) do rozwiązywania nazw DNS. Nginx pozwala określić serwer DNS w następujący sposób:

resolver 8.8.8.8;

Dyrektywy proxy_pass i internal

Dyrektywa proxy_pass jest wykorzystywana do przekierowywania żądań do innych serwerów, zarówno wewnętrznie, jak i zewnętrznie. Dyrektywa internal zapewnia, że określone lokalizacje są dostępne tylko w obrębie Nginx. Chociaż te dyrektywy same w sobie nie stanowią podatności, ich konfiguracja wymaga dokładnego zbadania, aby zapobiec lukom w zabezpieczeniach.

proxy_set_header Upgrade & Connection

Jeśli serwer nginx jest skonfigurowany do przekazywania nagłówków Upgrade i Connection, atak h2c Smuggling może zostać przeprowadzony w celu uzyskania dostępu do chronionych/wewnętrznych punktów końcowych.

{% hint style="danger" %} Ta podatność pozwoliłaby atakującemu ustanowić bezpośrednie połączenie z punktem końcowym proxy_pass (http://backend:9999 w tym przypadku), którego zawartość nie zostanie sprawdzona przez nginx. {% endhint %}

Przykład podatnej konfiguracji do kradzieży /flag znajdziesz tutaj:

server {
listen       443 ssl;
server_name  localhost;

ssl_certificate       /usr/local/nginx/conf/cert.pem;
ssl_certificate_key   /usr/local/nginx/conf/privkey.pem;

location / {
proxy_pass http://backend:9999;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
}

location /flag {
deny all;
}

{% hint style="warning" %} Zauważ, że nawet jeśli proxy_pass wskazywał na określoną ścieżkę, taką jak http://backend:9999/socket.io, połączenie zostanie nawiązane z http://backend:9999, więc możesz skontaktować się z dowolną inną ścieżką wewnątrz tego wewnętrznego punktu końcowego. Dlatego nie ma znaczenia, czy ścieżka jest określona w adresie URL proxy_pass. {% endhint %}

Wypróbuj to samodzielnie

Detectify stworzył repozytorium na GitHubie, gdzie możesz użyć Dockera, aby skonfigurować własny podatny serwer testowy Nginx z niektórymi błędami konfiguracyjnymi omówionymi w tym artykule i spróbować je znaleźć samodzielnie!

https://github.com/detectify/vulnerable-nginx

Narzędzia do analizy statycznej

GIXY

Gixy to narzędzie do analizy konfiguracji Nginx. Głównym celem Gixy jest zapobieganie błędom konfiguracji związanych z bezpieczeństwem i automatyzacja wykrywania wad.

Nginxpwner

Nginxpwner to proste narzędzie do wyszukiwania powszechnych błędów konfiguracyjnych i podatności Nginx.

Odnośniki

Natychmiastowa dostępność konfiguracji do oceny podatności i testów penetracyjnych. Uruchom pełny test penetracyjny z dowolnego miejsca za pomocą ponad 20 narzędzi i funkcji, które obejmują rozpoznanie, raportowanie. Nie zastępujemy pentesterów - rozwijamy niestandardowe narzędzia, moduły wykrywania i eksploatacji, aby umożliwić im zagłębienie się głębiej, zdobycie dostępu i dobrą zabawę.

{% embed url="https://pentest-tools.com/" %}

Dowiedz się, jak hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks: