Nginx

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Brak lokalizacji root

Podczas konfigurowania serwera Nginx, root directive 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 wyznaczony jako katalog root. Ta konfiguracja pozwala na dostęp do plików w określonym katalogu root, takich jak /hello.txt. Jednak ważne jest, że zdefiniowano tylko konkretną lokalizację (/hello.txt). Nie ma konfiguracji dla lokalizacji root (location / {...}). Ten brak oznacza, że dyrektywa root ma zastosowanie globalne, umożliwiając żądaniom do ścieżki root / dostęp do plików pod /etc/nginx.

Z tej konfiguracji wynika istotne zagrożenie bezpieczeństwa. Proste żądanie GET, np. GET /nginx.conf, może ujawnić wrażliwe informacje przez serwowanie pliku konfiguracyjnego Nginx znajdującego się pod /etc/nginx/nginx.conf. Ustawienie root na mniej wrażliwy katalog, np. /etc, może zmniejszyć to ryzyko, jednak nadal może pozwolić na niezamierzony dostęp do innych krytycznych plików, w tym innych plików konfiguracyjnych, logów dostępu, a nawet zaszyfrowanych poświadczeń używanych do HTTP basic authentication.

Błędna konfiguracja Alias LFI

W plikach konfiguracyjnych Nginx warto dokładnie sprawdzić dyrektywy “location”. Luka znana jako Local File Inclusion (LFI) może zostać niezamierzenie wprowadzona przez konfigurację przypominającą następującą:

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 poza zamierzonym katalogiem, skutecznie rozwiązując je do /path/images/../flag.txt. Ta luka pozwala atakującym na pobieranie plików z systemu plików serwera, które nie powinny być dostępne przez WWW.

Aby złagodzić tę podatność, konfigurację należy dostosować w następujący sposób:

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

Niezabezpieczone ograniczenia ścieżek

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

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Proxy / WAF Protections Bypass

Niebezpieczne użycie zmiennych / HTTP Request Splitting

Caution

Vulnerable variables $uri and $document_uri and this can be fixed by replacing them with $request_uri.

A regex can also be vulnerable like:

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

location ~ /docs/([^/\s])? { … $1 … } - niepodatne (sprawdza spacje)

location ~ /docs/(.*)? { … $1 … } - niepodatne

Poniżej przykład ilustrujący podatność w konfiguracji Nginx:

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

Znaki \r (Carriage Return) i \n (Line Feed) oznaczają znaki nowej linii w żądaniach HTTP, a ich postaci zakodowane w URL są reprezentowane jako %0d%0a. Dołączenie tych znaków w żądaniu (np. http://localhost/%0d%0aDetectify:%20clrf) do błędnie skonfigurowanego serwera powoduje, że serwer wystawia nowy nagłówek o nazwie Detectify. Dzieje się tak, ponieważ zmienna $uri dekoduje zakodowane w 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 związanym z CRLF injection i response splitting na https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.

Ta technika jest także wyjaśniona w tym wykładzie wraz z przykładami podatności i mechanizmami wykrywania. Na przykład, aby wykryć tę błędną konfigurację z perspektywy blackbox, możesz użyć następujących żądań:

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

Jeśli serwer jest podatny, pierwszy przypadek zwróci odpowiedź, ponieważ “X” może być dowolną metodą HTTP, a drugi spowoduje błąd, ponieważ H nie jest prawidłową metodą. W efekcie serwer otrzyma coś w stylu: GET / H HTTP/1.1 i to wywoła 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 podatne konfiguracje przedstawione w tym wykładzie to:

  • Zwróć uwagę, że $uri jest używane bez zmian w końcowym URL
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
  • Zwróć uwagę, że ponownie $uri występuje w URL (tym razem jako wartość 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 pewnych okolicznościach. Przyczyna tego zachowania pozostaje częściowo niejasna, jednak nie jest ono rzadkie ani proste do zweryfikowania. Ta anomalia została opisana w raporcie bezpieczeństwa na HackerOne, który można zobaczyć here. Dalsze badania komunikatu o błędzie doprowadziły do zidentyfikowania jej występowania w SSI filter module of Nginx’s codebase, wskazując Server Side Includes (SSI) jako źródło problemu.

Aby wykryć tę błędną konfigurację, można wykonać następujące polecenie, które polega na ustawieniu nagłówka Referer w celu sprawdzenia, czy zmienna zostanie wypisana:

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

Skanowania tej nieprawidłowej konfiguracji w różnych systemach ujawniły wiele instancji, w których zmienne Nginx mogły być wyświetlone przez użytkownika. Jednak zmniejszenie liczby podatnych instancji sugeruje, że działania naprawcze były w pewnym stopniu skuteczne.

Użycie try_files z zmiennymi $URI$ARGS

Poniższa nieprawidłowa konfiguracja Nginx może prowadzić do podatności LFI:

location / {
try_files $uri$args $uri$args/ /index.html;
}

W naszej konfiguracji mamy dyrektywę try_files, która służy do sprawdzania istnienia plików w określonej kolejności. Nginx zwróci pierwszy plik, który znajdzie. Podstawowa składnia dyrektywy try_files wygląda następująco:

try_files file1 file2 ... fileN fallback;

Nginx sprawdzi istnienie każdego pliku w określonej kolejności. Jeśli plik istnieje, zostanie on natychmiast zwrócony. Jeśli żaden z określonych plików nie istnieje, żądanie zostanie przekazane do opcji fallback, która może być innym URI lub konkretną stroną błędu.

Jednakże, używając zmiennych $uri$args w tej dyrektywie, Nginx spróbuje znaleźć plik pasujący do URI żądania połączonego z dowolnymi argumentami query string. W związku z tym możemy wykorzystać tę konfigurację:

http {
server {
root /var/www/html/public;

location / {
try_files $uri$args $uri$args/ /index.html;
}
}
}

Z następującym payloadem:

GET /?../../../../../../../../etc/passwd HTTP/1.1
Host: example.com

Używając naszego payloadu wydostaniemy się z katalogu root (zdefiniowanego w konfiguracji Nginx) i załadujemy plik /etc/passwd. W logach debugowania możemy zaobserwować, jak Nginx próbuje kolejnych plików:

...SNIP...

2025/07/11 15:49:16 [debug] 79694#79694: *4 trying to use file: "/../../../../../../../../etc/passwd" "/var/www/html/public/../../../../../../../../etc/passwd"
2025/07/11 15:49:16 [debug] 79694#79694: *4 try file uri: "/../../../../../../../../etc/passwd"

...SNIP...

2025/07/11 15:49:16 [debug] 79694#79694: *4 http filename: "/var/www/html/public/../../../../../../../../etc/passwd"

...SNIP...

2025/07/11 15:49:16 [debug] 79694#79694: *4 HTTP/1.1 200 OK

PoC przeciwko Nginx używając konfiguracji wspomnianej powyżej: Example burp request

Odczyt surowej odpowiedzi backendu

Nginx oferuje funkcję poprzez proxy_pass, która umożliwia 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. Osiąga się to przez to, że Nginx serwuje niestandardowe strony błędów w odpowiedzi na błędy backendu. Jednak problemy pojawiają się, gdy Nginx napotka nieprawidłowe żądanie HTTP. Takie żądanie jest przesyłane do backendu w niezmienionej formie, a surowa odpowiedź backendu jest następnie bezpośrednio wysyłana do klienta bez ingerencji Nginx.

Rozważmy przykładowy scenariusz z aplikacją 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 obsłużyć, w konfiguracji Nginx używane są konkretne dyrektywy:

http {
error_page 500 /html/error.html;
proxy_intercept_errors on;
proxy_hide_header Secret-Header;
}
  • proxy_intercept_errors: Dyrektywa ta pozwala Nginx na zwracanie niestandardowej odpowiedzi dla odpowiedzi backendu z kodem statusu większym niż 300. Zapewnia, że dla naszej przykładowej aplikacji uWSGI odpowiedź 500 Error zostanie przechwycona i obsłużona przez Nginx.
  • proxy_hide_header: Jak sama nazwa wskazuje, ta dyrektywa ukrywa określone nagłówki HTTP przed klientem, zwiększając prywatność i bezpieczeństwo.

Gdy wysyłane jest poprawne żądanie GET, Nginx przetwarza je normalnie, zwracając standardową odpowiedź błędu bez ujawniania żadnych tajnych nagłówków. Jednak nieprawidłowe żądanie HTTP omija ten mechanizm, co skutkuje ujawnieniem surowych odpowiedzi backendu, w tym tajnych nagłówków i komunikatów o błędach.

merge_slashes set to off

Domyślnie dyrektywa merge_slashes w Nginx jest ustawiona na on, co kompresuje wiele ukośników w URL do pojedynczego ukośnika. Funkcja ta, choć upraszcza przetwarzanie URL, może nieumyślnie maskować luki w zabezpieczeniach aplikacji stojących za Nginx, szczególnie tych podatnych na ataki local file inclusion (LFI). Eksperci ds. bezpieczeństwa Danny Robinson and Rotem Bar wskazali na potencjalne ryzyko związane z tym domyślnym zachowaniem, szczególnie gdy Nginx działa jako reverse-proxy.

Aby złagodzić takie ryzyko, zaleca się wyłączenie dyrektywy merge_slashes dla aplikacji podatnych na te luki. Zapewnia to, że Nginx przekazuje żądania do aplikacji bez zmiany struktury URL, nie maskując w ten sposób ewentualnych problemów bezpieczeństwa.

For more information check Danny Robinson and Rotem Bar.

Złośliwe nagłówki odpowiedzi

Jak pokazano w this writeup, istnieją pewne nagłówki, które jeśli pojawią się w odpowiedzi serwera WWW, zmienią zachowanie proxy Nginx. Możesz je sprawdzić in the docs:

  • X-Accel-Redirect: Wskazuje Nginxowi, aby wewnętrznie przekierował żądanie do wskazanej lokalizacji.
  • X-Accel-Buffering: Kontroluje, czy Nginx powinien buforować odpowiedź, czy nie.
  • X-Accel-Charset: Ustawia zestaw znaków dla odpowiedzi przy użyciu X-Accel-Redirect.
  • X-Accel-Expires: Ustawia czas wygaśnięcia odpowiedzi przy użyciu X-Accel-Redirect.
  • X-Accel-Limit-Rate: Ogranicza szybkość transferu odpowiedzi przy użyciu X-Accel-Redirect.

Na przykład nagłówek X-Accel-Redirect spowoduje wewnętrzne przekierowanie w Nginx. Zatem posiadanie konfiguracji Nginx z czymś takim jak root / i odpowiedzi serwera WWW z X-Accel-Redirect: .env spowoduje, że Nginx wyśle zawartość /.env (Path Traversal).

Wartość domyślna w dyrektywie map

W konfiguracji Nginx dyrektywa map często odgrywa rolę w kontroli autoryzacji. Częstym błędem jest nieokreślenie wartości wartość domyślna, 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, a złośliwy użytkownik może ominąć zabezpieczenia, uzyskując dostęp do niezdefiniowanego URI w obrębie /map-poc. The Nginx manual zaleca ustawienie wartości domyślnej, aby uniknąć takich problemów.

DNS Spoofing Vulnerability

DNS spoofing przeciwko Nginx jest możliwy w określonych warunkach. Jeśli atakujący zna DNS server używany przez Nginx i potrafi przechwycić jego zapytania DNS, może spoof DNS records. Metoda ta jednak jest nieskuteczna, jeśli Nginx jest skonfigurowany do używania localhost (127.0.0.1) do rozwiązywania DNS. Nginx pozwala określić serwer DNS w następujący sposób:

resolver 8.8.8.8;

proxy_pass and internal Dyrektywy

Dyrektywa proxy_pass służy do przekierowywania żądań do innych serwerów, zarówno wewnętrznych, jak i zewnętrznych. Dyrektywa internal zapewnia, że niektóre lokalizacje są dostępne tylko wewnątrz Nginx. Chociaż same dyrektywy nie są lukami, ich konfiguracja wymaga dokładnej analizy, aby zapobiec błędom bezpieczeństwa.

proxy_set_header Upgrade & Connection

Jeśli serwer nginx jest skonfigurowany do przekazywania nagłówków Upgrade i Connection, można przeprowadzić h2c Smuggling attack, aby uzyskać dostęp do chronionych/wewnętrznych punktów końcowych.

Caution

Ta luka pozwoli atakującemu na nawiązanie bezpośredniego połączenia z punktem końcowym proxy_pass (http://backend:9999 w tym przypadku), którego zawartość nie będzie sprawdzana przez nginx.

Przykład podatnej konfiguracji umożliwiającej kradzież /flag pochodzi stąd: 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;
}

Warning

Zwróć uwagę, że nawet jeśli proxy_pass wskazywał konkretną ś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 endpointu. Innymi słowy, nie ma znaczenia, czy w URL proxy_pass jest określona ścieżka.

Moduł HTTP/3 QUIC — zdalny DoS i leak (2024)

W 2024 Nginx ujawnił CVE-2024-31079, CVE-2024-32760, CVE-2024-34161 i CVE-2024-35200, pokazując że pojedyncza wroga sesja QUIC może spowodować awarię procesów worker lub leak pamięci, gdy eksperymentalny ngx_http_v3_module jest skompilowany i odsłonięty jest socket listen ... quic. Dotknięte buildy to 1.25.0–1.25.5 i 1.26.0, podczas gdy 1.27.0/1.26.1 zawierają poprawki; ujawnienie pamięci (CVE-2024-34161) dodatkowo wymaga MTU większych niż 4096 bajtów, aby uwidocznić dane wrażliwe (szczegóły w advisory nginx z 2024 r. cytowanym poniżej).

Wskazówki do rozpoznania i eksploatacji

  • HTTP/3 jest opt-in, więc skanuj odpowiedzi Alt-Svc: h3=":443" lub wykonuj brute-force QUIC handshake’y na UDP/443; po potwierdzeniu fuzzuj handshake i ramki STREAM przy użyciu niestandardowych payloadów quiche-client/nghttp3, aby spowodować awarie procesów worker i wymusić leak w logach.
  • Szybko zidentyfikuj obsługę celu za pomocą:
nginx -V 2>&1 | grep -i http_v3
rg -n "listen .*quic" /etc/nginx/

TLS session resumption bypass of client cert auth (CVE-2025-23419)

W komunikacie z lutego 2025 ujawniono, że nginx 1.11.4–1.27.3 zbudowany z OpenSSL pozwala na ponowne użycie sesji TLS 1.3 z jednego name-based virtual host w innym, dzięki czemu client, który negocjował host bez wymaganego certyfikatu, może odtworzyć ticket/PSK i wejść do vhost chronionego przez ssl_verify_client on;, całkowicie pomijając mTLS. Błąd występuje zawsze, gdy wiele virtual hosts współdzieli ten sam TLS 1.3 session cache i tickets (zob. advisory nginx z 2025 poniżej).

Playbook atakującego

# 1. Create a TLS session on the public vhost and save the session ticket
openssl s_client -connect public.example.com:443 -sess_out ticket.pem

# 2. Replay that session ticket against the mTLS vhost before it expires
openssl s_client -connect admin.example.com:443 -sess_in ticket.pem -ign_eof

Jeśli target jest podatny, drugi handshake kończy się bez przedstawienia certyfikatu klienta, ujawniając chronione lokalizacje.

Co audytować

  • Mieszane server_name blocks które współdzielą ssl_session_cache shared:SSL oraz ssl_session_tickets on;.
  • Bloki Admin/API, które oczekują mTLS, ale dziedziczą ustawienia współdzielonej pamięci sesji/biletów z publicznych hostów.
  • Automatyzacja, która globalnie włącza wznowienie sesji TLS 1.3 (np. role Ansible) bez uwzględnienia izolacji vhost.

HTTP/2 Rapid Reset resilience (CVE-2023-44487 behavior)

The HTTP/2 Rapid Reset attack (CVE-2023-44487) nadal wpływa na nginx, gdy operatorzy podnoszą keepalive_requests lub http2_max_concurrent_streams ponad wartości domyślne: atakujący otwiera jedno połączenie HTTP/2, zalewa je tysiącami strumieni, a następnie natychmiast wysyła ramki RST_STREAM, dzięki czemu sufit współbieżności nigdy nie jest osiągnięty, podczas gdy CPU ciągle pracuje nad logiką zamykania. Nginx defaults (128 concurrent streams, 1000 keepalive requests) ograniczają promień rażenia; znaczne podniesienie tych limitów sprawia, że łatwo jest wykończyć workerów nawet z jednego klienta (zob. analizę F5 wymienioną poniżej).

Wskazówki wykrywania

# Highlight risky knobs
rg -n "http2_max_concurrent_streams" /etc/nginx/
rg -n "keepalive_requests" /etc/nginx/

Hosty, które ujawniają wyjątkowo wysokie wartości tych dyrektyw, są głównymi celami: jeden klient HTTP/2 może w kółko tworzyć strumienie i natychmiast wysyłać ramki RST_STREAM, aby utrzymać CPU na wysokim obciążeniu bez przekroczenia limitu współbieżności.

Wypróbuj samodzielnie

Detectify stworzył repozytorium na GitHub, w którym możesz użyć Docker, aby skonfigurować własny podatny serwer testowy Nginx zawierający niektóre z nieprawidłowych konfiguracji omówionych w tym artykule i spróbować je samodzielnie znaleźć!

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 konfiguracyjnym wpływającym na bezpieczeństwo oraz automatyzacja wykrywania wad.

Nginxpwner

Nginxpwner to proste narzędzie do wyszukiwania powszechnych nieprawidłowych konfiguracji Nginx i podatności.

References

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks