mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
318 lines
18 KiB
Markdown
318 lines
18 KiB
Markdown
# Nginx
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
|
||
## Missing root location <a href="#missing-root-location" id="missing-root-location"></a>
|
||
|
||
Quando si configura il server Nginx, la **direttiva root** gioca un ruolo fondamentale definendo la directory di base da cui vengono serviti i file. Considera l'esempio qui sotto:
|
||
```bash
|
||
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 la directory radice. Questa impostazione consente l'accesso ai file all'interno della directory radice specificata, come `/hello.txt`. Tuttavia, è fondamentale notare che è definita solo una posizione specifica (`/hello.txt`). Non c'è configurazione per la posizione radice (`location / {...}`). Questa omissione significa che la direttiva root si applica globalmente, consentendo alle richieste al percorso radice `/` di accedere ai file sotto `/etc/nginx`.
|
||
|
||
Una considerazione critica per la sicurezza deriva da questa configurazione. 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 accessi non intenzionali ad altri file critici, inclusi altri file di configurazione, log di accesso e persino credenziali crittografate utilizzate per l'autenticazione di base HTTP.
|
||
|
||
## Alias LFI Misconfiguration <a href="#alias-lfi-misconfiguration" id="alias-lfi-misconfiguration"></a>
|
||
|
||
Nei file di configurazione di Nginx, è necessaria un'attenta ispezione delle direttive "location". Una vulnerabilità nota come Local File Inclusion (LFI) può essere introdotta involontariamente attraverso una configurazione che assomiglia alla seguente:
|
||
```
|
||
location /imgs {
|
||
alias /path/images/;
|
||
}
|
||
```
|
||
Questa configurazione è soggetta ad attacchi LFI a causa del server che 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`. Questo difetto consente agli attaccanti di recuperare file dal filesystem del server che non dovrebbero essere accessibili tramite il web.
|
||
|
||
Per mitigare questa vulnerabilità, la configurazione dovrebbe essere regolata per:
|
||
```
|
||
location /imgs/ {
|
||
alias /path/images/;
|
||
}
|
||
```
|
||
Maggiore informazione: [https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/](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 del percorso non sicuro <a href="#unsafe-variable-use" id="unsafe-variable-use"></a>
|
||
|
||
Controlla la seguente pagina per imparare a bypassare direttive come:
|
||
```plaintext
|
||
location = /admin {
|
||
deny all;
|
||
}
|
||
|
||
location = /admin/ {
|
||
deny all;
|
||
}
|
||
```
|
||
{{#ref}}
|
||
../../pentesting-web/proxy-waf-protections-bypass.md
|
||
{{#endref}}
|
||
|
||
## Uso non sicuro delle variabili / Suddivisione della richiesta HTTP <a href="#unsafe-variable-use" id="unsafe-variable-use"></a>
|
||
|
||
> [!CAUTION]
|
||
> Variabili vulnerabili `$uri` e `$document_uri` e questo può essere risolto sostituendole con `$request_uri`.
|
||
>
|
||
> Un regex può anche essere vulnerabile come:
|
||
>
|
||
> `location ~ /docs/([^/])? { … $1 … }` - Vulnerabile
|
||
>
|
||
> `location ~ /docs/([^/\s])? { … $1 … }` - Non vulnerabile (controllo degli 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) significano caratteri di nuova linea nelle richieste HTTP, e le loro forme codificate in URL sono rappresentate come `%0d%0a`. Includere questi caratteri in una richiesta (ad esempio, `http://localhost/%0d%0aDetectify:%20clrf`) a un server mal configurato porta il server a emettere un nuovo header chiamato `Detectify`. Questo accade perché la variabile $uri decodifica i caratteri di nuova linea codificati in URL, portando a un header imprevisto 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
|
||
```
|
||
Impara di più sui rischi dell'iniezione CRLF e della divisione della risposta su [https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/](https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/).
|
||
|
||
Inoltre, questa tecnica è [**spiegata in questo intervento**](https://www.youtube.com/watch?v=gWQyWdZbdoY&list=PL0xCSYnG_iTtJe2V6PQqamBF73n7-f1Nr&index=77) con alcuni esempi vulnerabili e meccanismi di rilevamento. Ad esempio, per rilevare questa misconfigurazione da una prospettiva blackbox, potresti utilizzare queste richieste:
|
||
|
||
- `https://example.com/%20X` - Qualsiasi codice HTTP
|
||
- `https://example.com/%20H` - 400 Bad Request
|
||
|
||
Se vulnerabile, il primo restituirà "X" poiché è qualsiasi metodo HTTP e il secondo restituirà un errore poiché H non è un metodo valido. Quindi il server riceverà qualcosa come: `GET / H HTTP/1.1` e questo attiverà l'errore.
|
||
|
||
Altri esempi di rilevamento potrebbero essere:
|
||
|
||
- `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 intervento erano:
|
||
|
||
- Nota come **`$uri`** è impostato così com'è nell'URL finale.
|
||
```
|
||
location ^~ /lite/api/ {
|
||
proxy_pass http://lite-backend$uri$is_args$args;
|
||
}
|
||
```
|
||
- Nota come di nuovo **`$uri`** è 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;
|
||
}
|
||
```
|
||
### 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 piuttosto elusiva, eppure non è rara né facile da verificare. Questa anomalia è stata evidenziata in un rapporto di sicurezza su HackerOne, che può essere visualizzato [qui](https://hackerone.com/reports/370094). Ulteriori indagini sul messaggio di errore hanno portato all'identificazione della sua occorrenza all'interno del [modulo di filtro SSI del codice di Nginx](https://github.com/nginx/nginx/blob/2187586207e1465d289ae64cedc829719a048a39/src/http/modules/ngx_http_ssi_filter_module.c#L365), individuando le Server Side Includes (SSI) come causa principale.
|
||
|
||
Per **rilevare questa misconfigurazione**, è possibile eseguire il seguente comando, che prevede l'impostazione di un'intestazione referer per testare la stampa delle variabili:
|
||
```bash
|
||
$ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar’
|
||
```
|
||
Scans for this misconfiguration across systems revealed multiple instances where Nginx variables could be printed by a user. However, a decrease in the number of vulnerable instances suggests that efforts to patch this issue have been somewhat successful.
|
||
|
||
### Using try_files with $URI$ARGS variables
|
||
|
||
Following Nginx misconfiguration can lead to an LFI vulnerability:
|
||
```
|
||
location / {
|
||
try_files $uri$args $uri$args/ /index.html;
|
||
}
|
||
```
|
||
Nella nostra configurazione abbiamo la direttiva `try_files` che viene utilizzata per controllare l'esistenza di file in un ordine specificato. Nginx servirà il primo che troverà. La sintassi di 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 altro URI o una pagina di errore specifica.
|
||
|
||
Tuttavia, quando si utilizzano le variabili `$uri$args` in questa direttiva, Nginx cercherà un file che corrisponde all'URI della richiesta combinato con eventuali argomenti della stringa di query. 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
|
||
```
|
||
Utilizzando il nostro payload, eseguiremo l'escape della 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 utilizzando la configurazione menzionata sopra:
|
||

|
||
|
||
## Lettura della risposta raw del backend
|
||
|
||
Nginx offre una funzionalità tramite `proxy_pass` che consente l'intercettazione degli errori e degli header HTTP prodotti dal backend, con l'obiettivo di nascondere i messaggi di errore interni e gli header. Questo viene realizzato da Nginx servendo pagine di errore personalizzate in risposta agli errori del backend. Tuttavia, sorgono sfide quando Nginx incontra una richiesta HTTP non valida. Tale richiesta viene inoltrata al backend così come ricevuta, e la risposta raw del backend viene quindi inviata direttamente al client senza l'intervento di Nginx.
|
||
|
||
Considera un esempio di scenario che coinvolge un'applicazione uWSGI:
|
||
```python
|
||
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**](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors): Questa direttiva consente a Nginx di servire una risposta personalizzata per le risposte del backend con un codice di stato superiore a 300. Garantisce che, per il nostro esempio di applicazione uWSGI, una risposta `500 Error` venga intercettata e gestita da Nginx.
|
||
- [**proxy_hide_header**](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header): Come suggerisce il nome, questa direttiva nasconde gli header HTTP specificati dal client, migliorando la privacy e la sicurezza.
|
||
|
||
Quando viene effettuata una richiesta `GET` valida, Nginx la elabora normalmente, restituendo una risposta di errore standard senza rivelare alcun header segreto. Tuttavia, una richiesta HTTP non valida bypassa questo meccanismo, risultando nell'esposizione delle risposte raw del backend, inclusi header segreti e messaggi di errore.
|
||
|
||
## merge_slashes impostato su off
|
||
|
||
Per impostazione predefinita, la **direttiva `merge_slashes` di Nginx** è impostata su **`on`**, che comprime più barre oblique in un URL in una singola barra. Questa funzionalità, pur semplificando l'elaborazione degli URL, può inavvertitamente nascondere vulnerabilità nelle applicazioni dietro Nginx, in particolare quelle soggette ad attacchi di inclusione di file locali (LFI). Gli esperti di sicurezza **Danny Robinson e Rotem Bar** hanno evidenziato i potenziali rischi associati a questo comportamento predefinito, specialmente quando Nginx funge da reverse-proxy.
|
||
|
||
Per mitigare tali rischi, si raccomanda 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 dell'URL, evitando così di mascherare eventuali problemi di sicurezza sottostanti.
|
||
|
||
Per ulteriori informazioni, controlla [Danny Robinson e Rotem Bar](https://medium.com/appsflyer/nginx-may-be-protecting-your-applications-from-traversal-attacks-without-you-even-knowing-b08f882fd43d).
|
||
|
||
### **Intestazioni di risposta Maclicious**
|
||
|
||
Come mostrato in [**questo writeup**](https://mizu.re/post/cors-playground), ci sono alcune intestazioni che, se presenti nella risposta del server web, cambieranno il comportamento del proxy Nginx. Puoi controllarle [**nei documenti**](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/):
|
||
|
||
- `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 set di caratteri per la risposta quando si utilizza X-Accel-Redirect.
|
||
- `X-Accel-Expires`: Imposta il tempo di scadenza per la risposta quando si utilizza X-Accel-Redirect.
|
||
- `X-Accel-Limit-Rate`: Limita la velocità di trasferimento per le risposte quando si utilizza X-Accel-Redirect.
|
||
|
||
Ad esempio, l'intestazione **`X-Accel-Redirect`** causerà un **reindirizzamento** interno in nginx. Quindi avere una configurazione nginx con qualcosa come **`root /`** e una risposta dal server web con **`X-Accel-Redirect: .env`** farà sì che nginx invii il contenuto di **`/.env`** (Path Traversal).
|
||
|
||
### **Valore predefinito nella direttiva Map**
|
||
|
||
Nella **configurazione di Nginx**, la direttiva `map` gioca spesso un ruolo nel **controllo dell'autorizzazione**. Un errore comune è non specificare un valore **predefinito**, il che potrebbe portare ad accessi non autorizzati. Ad esempio:
|
||
```yaml
|
||
http {
|
||
map $uri $mappocallow {
|
||
/map-poc/private 0;
|
||
/map-poc/secret 0;
|
||
/map-poc/public 1;
|
||
}
|
||
}
|
||
```
|
||
|
||
```yaml
|
||
server {
|
||
location /map-poc {
|
||
if ($mappocallow = 0) {return 403;}
|
||
return 200 "Hello. It is private area: $mappocallow";
|
||
}
|
||
}
|
||
```
|
||
Senza un `default`, un **utente malintenzionato** può eludere la sicurezza accedendo a un **URI non definito** all'interno di `/map-poc`. [Il manuale di Nginx](https://nginx.org/en/docs/http/ngx_http_map_module.html) consiglia di impostare un **valore predefinito** per evitare tali problemi.
|
||
|
||
### **Vulnerabilità di Spoofing DNS**
|
||
|
||
Lo spoofing DNS contro Nginx è fattibile in determinate condizioni. Se un attaccante conosce il **server DNS** utilizzato da Nginx e può intercettare le sue query DNS, può falsificare i record DNS. Questo metodo, tuttavia, è inefficace se Nginx è configurato per utilizzare **localhost (127.0.0.1)** per la risoluzione DNS. Nginx consente di specificare un server DNS come segue:
|
||
```yaml
|
||
resolver 8.8.8.8;
|
||
```
|
||
### **`proxy_pass` e direttive `internal`**
|
||
|
||
La direttiva **`proxy_pass`** viene utilizzata per reindirizzare le richieste ad altri server, sia internamente che esternamente. La direttiva **`internal`** garantisce che determinate posizioni siano accessibili solo all'interno di Nginx. Sebbene queste direttive non siano vulnerabilità di per sé, la loro configurazione richiede un'attenta analisi per prevenire lacune di sicurezza.
|
||
|
||
## proxy_set_header Upgrade & Connection
|
||
|
||
Se il server nginx è configurato per passare le intestazioni Upgrade e Connection, un [**attacco di Smuggling h2c**](../../pentesting-web/h2c-smuggling.md) potrebbe essere eseguito per accedere a endpoint protetti/interni.
|
||
|
||
> [!CAUTION]
|
||
> Questa vulnerabilità consentirebbe a un attaccante di **stabilire una connessione diretta con l'endpoint `proxy_pass`** (`http://backend:9999` in questo caso) il cui contenuto non verrà controllato da nginx.
|
||
|
||
Esempio di configurazione vulnerabile per rubare `/flag` da [qui](https://bishopfox.com/blog/h2c-smuggling-request):
|
||
```
|
||
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 **percorso** specifico come `http://backend:9999/socket.io`, la connessione sarà stabilita con `http://backend:9999`, quindi puoi **contattare qualsiasi altro percorso all'interno di quel punto finale interno. Quindi non importa se un percorso è specificato nell'URL di proxy_pass.**
|
||
|
||
## Provalo tu stesso
|
||
|
||
Detectify ha creato un repository GitHub dove puoi utilizzare Docker per impostare il tuo server di test Nginx vulnerabile con alcune delle misconfigurazioni discusse in questo articolo e provare a trovarle tu stesso!
|
||
|
||
[https://github.com/detectify/vulnerable-nginx](https://github.com/detectify/vulnerable-nginx)
|
||
|
||
## Strumenti di analisi statica
|
||
|
||
### [GIXY](https://github.com/yandex/gixy)
|
||
|
||
Gixy è uno strumento per analizzare la configurazione di Nginx. L'obiettivo principale di Gixy è prevenire la misconfigurazione della sicurezza e automatizzare il rilevamento dei difetti.
|
||
|
||
### [Nginxpwner](https://github.com/stark0de/nginxpwner)
|
||
|
||
Nginxpwner è uno strumento semplice per cercare comuni misconfigurazioni e vulnerabilità di Nginx.
|
||
|
||
## Riferimenti
|
||
|
||
- [**https://blog.detectify.com/2020/11/10/common-nginx-misconfigurations/**](https://blog.detectify.com/2020/11/10/common-nginx-misconfigurations/)
|
||
- [**http://blog.zorinaq.com/nginx-resolver-vulns/**](http://blog.zorinaq.com/nginx-resolver-vulns/)
|
||
- [**https://github.com/yandex/gixy/issues/115**](https://github.com/yandex/gixy/issues/115)
|
||
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|