Nginx

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Posizione root mancante

Quando si configura il server Nginx, la root directive svolge un ruolo fondamentale definendo la directory base da cui vengono serviti i file. Considera l’esempio seguente:

server {
root /etc/nginx;

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

In questa configurazione, /etc/nginx è designata come directory root. Questa impostazione permette l’accesso ai file all’interno della root specificata, ad esempio /hello.txt. È tuttavia importante notare che è definita solo una location specifica (/hello.txt). Non esiste una configurazione per la location root (location / {...}). Questa omissione fa sì che la direttiva root si applichi globalmente, consentendo alle richieste al path root / di accedere ai file sotto /etc/nginx.

Questa configurazione solleva una considerazione critica di sicurezza. Una semplice richiesta GET, come GET /nginx.conf, potrebbe esporre informazioni sensibili servendo il file di configurazione di Nginx situato in /etc/nginx/nginx.conf. Impostare la root su una directory meno sensibile, come /etc, potrebbe mitigare questo rischio, ma potrebbe comunque permettere l’accesso non intenzionale ad altri file critici, inclusi altri file di configurazione, access log e persino credenziali cifrate usate per HTTP basic authentication.

Alias LFI - Errata di configurazione

Nei file di configurazione di Nginx è necessario ispezionare attentamente le direttive location. Una vulnerabilità nota come Local File Inclusion (LFI) può essere introdotta involontariamente tramite una configurazione che assomiglia alla seguente:

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

Questa configurazione è soggetta ad attacchi LFI perché il server interpreta richieste come /imgs../flag.txt come un tentativo di accedere a file al di fuori della directory prevista, risolvendo effettivamente in /path/images/../flag.txt. Questa falla permette agli attaccanti di recuperare file dal filesystem del server che non dovrebbero essere accessibili via web.

Per mitigare questa vulnerabilità, la configurazione dovrebbe essere modificata per:

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

Maggiori informazioni: https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/

Test di 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

Restrizione di percorso non sicura

Consulta la pagina seguente per imparare come effettuare il bypass di direttive come:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Proxy / WAF Protections Bypass

Uso non sicuro di variabili / HTTP Request Splitting

Caution

Variabili vulnerabili $uri and $document_uri e questo può essere risolto sostituendole con $request_uri.

Anche una regex può essere vulnerabile come:

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

location ~ /docs/([^/\s])? { … $1 … } - Non vulnerabile (controllando gli spazi)

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

Una vulnerabilità nella configurazione di Nginx è dimostrata dall’esempio seguente:

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

I caratteri \r (Carriage Return) e \n (Line Feed) indicano i caratteri di nuova linea nelle richieste HTTP, e le loro forme URL-encoded sono rappresentate come %0d%0a. L’inclusione di questi caratteri in una richiesta (ad esempio http://localhost/%0d%0aDetectify:%20clrf) a un server mal configurato provoca che il server emetta un nuovo header chiamato Detectify. Questo accade perché la variabile $uri decodifica i caratteri di nuova linea codificati nell’URL, portando a un header inatteso nella risposta:

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

Per saperne di più sui rischi di CRLF injection e response splitting visita https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/.

Also this technique is explained in this talk con alcuni esempi vulnerabili e meccanismi di detection. Per esempio, per individuare questa misconfigurazione da una prospettiva blackbox potresti inviare queste richieste:

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

Se vulnerabile, la prima risponderà in quanto “X” è un qualsiasi metodo HTTP e la seconda restituirà un errore perché H non è un metodo valido. Quindi il server riceverà qualcosa come: GET / H HTTP/1.1 e questo farà scattare l’errore.

Altri esempi di detection sarebbero:

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

Alcune configurazioni vulnerabili trovate e presentate in quel talk erano:

  • Nota come $uri viene impostato così com’è nell’URL finale
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
  • Nota come ancora una volta $uri sia nell’URL (questa volta all’interno di un parametro)
location ~ ^/dna/payment {
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
proxy_pass http://$back;
  • Ora in AWS S3
location /s3/ {
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
}

Qualsiasi variabile

È stato scoperto che i dati forniti dall’utente potrebbero essere trattati come una variabile Nginx in certe circostanze. La causa di questo comportamento rimane in parte sfuggente, tuttavia non è rara né semplice da verificare. Questa anomalia è stata evidenziata in un report di sicurezza su HackerOne, consultabile qui. Ulteriori indagini sul messaggio di errore hanno portato all’identificazione della sua occorrenza all’interno del SSI filter module of Nginx’s codebase, individuando Server Side Includes (SSI) come causa principale.

Per rilevare questa errata configurazione, è possibile eseguire il seguente comando, che prevede l’impostazione dell’header Referer per testare la stampa della variabile:

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

Le scansioni per questa misconfigurazione su diversi sistemi hanno rivelato più istanze in cui variabili di Nginx potevano essere visualizzate da un utente. Tuttavia, una diminuzione del numero di istanze vulnerabili suggerisce che gli sforzi per correggere questo problema sono stati in qualche misura efficaci.

Utilizzo di try_files con variabili $URI$ARGS

La seguente misconfigurazione di Nginx può portare a una vulnerabilità LFI:

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

Nella nostra configurazione abbiamo la direttiva try_files che viene usata per verificare l’esistenza di file in un ordine specificato. Nginx servirà il primo che trova. La sintassi base della direttiva try_files è la seguente:

try_files file1 file2 ... fileN fallback;

Nginx controllerà l’esistenza di ciascun file nell’ordine specificato. Se un file esiste, verrà servito immediatamente. Se nessuno dei file specificati esiste, la richiesta verrà inoltrata all’opzione di fallback, che può essere un altro URI o una pagina di errore specifica.

Tuttavia, quando si usano le variabili $uri$args in questa direttiva, Nginx tenterà di cercare un file che corrisponda all’URI richiesto combinato con eventuali argomenti della query string. Perciò possiamo sfruttare questa configurazione:

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

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

Con il seguente payload:

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

Usando il nostro payload usciremo dalla root directory (definita nella configurazione di Nginx) e caricheremo il file /etc/passwd. Nei log di debug possiamo osservare come Nginx prova i file:

...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 contro Nginx usando la configurazione menzionata sopra: Esempio di richiesta Burp

Lettura della risposta raw del backend

Nginx offre una funzionalità tramite proxy_pass che permette l’intercettazione di errori e header HTTP prodotti dal backend, con lo scopo di nascondere messaggi di errore interni e header. Questo viene realizzato da Nginx servendo pagine di errore personalizzate in risposta a errori del backend. Tuttavia, sorgono problemi quando Nginx riceve una richiesta HTTP non valida. Tale richiesta viene inoltrata al backend così com’è, e la risposta raw del backend viene poi inviata direttamente al client senza l’intervento di Nginx.

Considera uno scenario di esempio che coinvolge un’applicazione 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!"]

Per gestire questo, vengono usate direttive specifiche nella configurazione di Nginx:

http {
error_page 500 /html/error.html;
proxy_intercept_errors on;
proxy_hide_header Secret-Header;
}
  • proxy_intercept_errors: Questa direttiva permette a Nginx di servire una risposta personalizzata per le risposte del backend con un codice di stato maggiore di 300. Garantisce che, per la nostra applicazione uWSGI, una 500 Error venga intercettata e gestita da Nginx.
  • proxy_hide_header: Come suggerisce il nome, questa direttiva nasconde specifici header HTTP al client, migliorando privacy e sicurezza.

Quando viene effettuata una richiesta valida GET, Nginx la elabora normalmente, restituendo una risposta di errore standard senza rivelare eventuali header segreti. Tuttavia, una richiesta HTTP non valida bypassa questo meccanismo, risultando nell’esposizione delle risposte grezze del backend, inclusi header segreti e messaggi di errore.

merge_slashes impostato su off

Per impostazione predefinita, la merge_slashes directive di Nginx è impostata su on, il che comprime più slash consecutivi in una URL in un singolo slash. Questa funzionalità, pur semplificando l’elaborazione delle URL, può involontariamente nascondere vulnerabilità nelle applicazioni dietro Nginx, in particolare quelle soggette a attacchi di local file inclusion (LFI). Gli esperti di sicurezza Danny Robinson and Rotem Bar hanno evidenziato i rischi potenziali associati a questo comportamento di default, specialmente quando Nginx agisce come reverse-proxy.

Per mitigare tali rischi, si consiglia di disattivare la direttiva merge_slashes per le applicazioni suscettibili a queste vulnerabilità. Questo garantisce che Nginx inoltri le richieste all’applicazione senza alterare la struttura della URL, evitando così di mascherare eventuali problemi di sicurezza sottostanti.

Per ulteriori informazioni consulta Danny Robinson and Rotem Bar.

Header di risposta Maclicious

Come mostrato in this writeup, ci sono certi header che se presenti nella risposta del web server cambieranno il comportamento del proxy Nginx. Puoi verificarli in the docs:

  • X-Accel-Redirect: Indica a Nginx di reindirizzare internamente una richiesta a una posizione specificata.
  • X-Accel-Buffering: Controlla se Nginx deve bufferizzare la risposta o meno.
  • X-Accel-Charset: Imposta il character set per la risposta quando si usa X-Accel-Redirect.
  • X-Accel-Expires: Imposta il tempo di scadenza per la risposta quando si usa X-Accel-Redirect.
  • X-Accel-Limit-Rate: Limita la velocità di trasferimento per le risposte quando si usa X-Accel-Redirect.

Per esempio, l’header X-Accel-Redirect causerà un redirect interno in nginx. Quindi avere una configurazione nginx con qualcosa come root / e una risposta dal web server con X-Accel-Redirect: .env farà sì che nginx invii il contenuto di /.env (Path Traversal).

Valore di default nella direttiva map

Nella Nginx configuration, la direttiva map spesso gioca un ruolo nel authorization control. Un errore comune è non specificare un valore default, il che potrebbe portare ad accessi non autorizzati. Per esempio:

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";
}
}

Senza un default, un utente malintenzionato può aggirare la sicurezza accedendo a un URI non definito all’interno di /map-poc. The Nginx manual consiglia di impostare un valore predefinito per evitare tali problemi.

DNS Spoofing Vulnerability

Il DNS spoofing contro Nginx è fattibile in determinate condizioni. Se un attaccante conosce il DNS server usato da Nginx e può intercettare le sue query DNS, può falsificare i record DNS. Questo metodo, tuttavia, è inefficace se Nginx è configurato per usare localhost (127.0.0.1) per la risoluzione DNS. Nginx permette di specificare un DNS server come segue:

resolver 8.8.8.8;

proxy_pass e internal Direttive

La direttiva proxy_pass viene utilizzata per reindirizzare le richieste verso altri server, sia internamente che esternamente. La direttiva internal garantisce che determinate location siano accessibili solo all’interno di Nginx. Pur non essendo vulnerabilità di per sé, la loro configurazione richiede un’attenta verifica per evitare falle di sicurezza.

proxy_set_header Upgrade & Connection

Se il server nginx è configurato per passare le intestazioni Upgrade e Connection, potrebbe essere eseguito un h2c Smuggling attack per accedere a endpoint protetti/interni.

Caution

Questa vulnerabilità permetterebbe a un attacker di stabilire una connessione diretta con l’endpoint proxy_pass (http://backend:9999 in questo caso) il cui contenuto non verrà controllato da nginx.

Example of vulnerable configuration to steal /flag from here:

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

Nota che anche se il proxy_pass puntasse a un path specifico come http://backend:9999/socket.io la connessione verrà stabilita con http://backend:9999 quindi puoi contattare qualsiasi altro path all’interno di quell’endpoint interno. Quindi non importa se un path è specificato nell’URL di proxy_pass.

Modulo HTTP/3 QUIC: DoS remoto & leak (2024)

Durante il 2024 Nginx ha divulgato CVE-2024-31079, CVE-2024-32760, CVE-2024-34161 e CVE-2024-35200 mostrando che una singola sessione QUIC ostile può far crashare i processi worker o causare leak di memoria ogni volta che il modulo sperimentale ngx_http_v3_module è compilato e viene esposta una socket listen ... quic. Le build impattate sono 1.25.0–1.25.5 e 1.26.0, mentre 1.27.0/1.26.1 includono le patch; la disclosure di memoria (CVE-2024-34161) richiede inoltre MTU maggiori di 4096 byte per far emergere dati sensibili (dettagli nell’advisory nginx 2024 referenziato sotto).

Recon & exploitation hints

  • HTTP/3 è opt-in, quindi scansiona per risposte Alt-Svc: h3=":443" o fai brute-force dei handshake QUIC su UDP/443; una volta confermato, fuzzifica l’handshake e i frame STREAM con payload custom quiche-client/nghttp3 per causare crash dei worker e forzare il leak nei log.
  • Identifica rapidamente il supporto del target con:
nginx -V 2>&1 | grep -i http_v3
rg -n "listen .*quic" /etc/nginx/

Bypass della ripresa della sessione TLS per l’autenticazione con certificato client (CVE-2025-23419)

Un advisory di febbraio 2025 ha rivelato che nginx 1.11.4–1.27.3 compilato con OpenSSL consente di riutilizzare una sessione TLS 1.3 da un virtual host basato sul nome all’interno di un altro, quindi un client che ha negoziato un host senza certificato può riprodurre il ticket/PSK per saltare in un vhost protetto con ssl_verify_client on; e bypassare completamente l’mTLS. Il bug si verifica ogni volta che più virtual host condividono la stessa cache di sessione TLS 1.3 e i ticket (vedi l’advisory nginx del 2025 referenziato sotto).

Playbook dell’attaccante

# 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

Se il target è vulnerabile, il secondo handshake si completa senza presentare un certificato client, rivelando percorsi protetti.

Cosa controllare

  • Blocchi server_name misti che condividono ssl_session_cache shared:SSL oltre a ssl_session_tickets on;.
  • Blocchi Admin/API che si aspettano mTLS ma ereditano impostazioni di session cache/ticket condivise da host pubblici.
  • Automazione che abilita la session resumption di TLS 1.3 globalmente (es. Ansible roles) senza considerare l’isolamento dei vhost.

Resilienza a HTTP/2 Rapid Reset (comportamento CVE-2023-44487)

L’attacco HTTP/2 Rapid Reset (CVE-2023-44487) continua ad interessare nginx quando gli operatori alzano keepalive_requests o http2_max_concurrent_streams oltre i valori di default: un attaccante apre una singola connessione HTTP/2, la inonda con migliaia di stream, poi emette immediatamente frame RST_STREAM in modo che il tetto di concurrency non venga mai raggiunto mentre la CPU continua a lavorare sulla logica di teardown. I default di nginx (128 concurrent streams, 1000 keepalive requests) mantengono il raggio d’azione ridotto; aumentare significativamente questi limiti rende banale affamare i worker anche da un singolo client (vedi l’analisi di F5 referenziata sotto).

Suggerimenti per il rilevamento

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

Host che rivelano valori insolitamente alti per quelle direttive sono bersagli ideali: un client HTTP/2 può ciclare la creazione di stream e inviare istantanei frame RST_STREAM per tenere la CPU al massimo senza superare il limite di concorrenza.

Provalo tu stesso

Detectify ha creato un repository GitHub dove puoi usare Docker per configurare il tuo server di test Nginx vulnerabile con alcune delle misconfigurazioni discusse in questo articolo e provare a trovarle da solo!

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

Strumenti di analisi statica

gixy-ng & Gixy-Next & GIXY

  • Gixy-Next (un fork aggiornato di GIXY) è uno strumento per analizzare le configurazioni Nginx, con l’obiettivo di trovare vulnerabilità, direttive insicure e misconfigurazioni rischiose. Individua anche misconfigurazioni che influenzano le prestazioni e rileva opportunità di hardening mancate, permettendo la rilevazione automatica di difetti.
  • gixy-ng (il fork attivamente mantenuto di GIXY) è uno strumento per analizzare le configurazioni Nginx, con l’obiettivo di trovare vulnerabilità, direttive insicure e misconfigurazioni rischiose. Individua anche misconfigurazioni che influenzano le prestazioni e rileva opportunità di hardening mancate, permettendo la rilevazione automatica di difetti.

Nginxpwner

Nginxpwner è uno strumento semplice per cercare comuni misconfigurazioni e vulnerabilità di Nginx.

Riferimenti

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks