mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
318 lines
17 KiB
Markdown
318 lines
17 KiB
Markdown
# Nginx
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
|
||
## Nedostajući root lokacija <a href="#missing-root-location" id="missing-root-location"></a>
|
||
|
||
Kada konfigurišete Nginx server, **root direktiva** igra ključnu ulogu definišući osnovni direktorijum iz kojeg se datoteke serviraju. Razmotrite sledeći primer:
|
||
```bash
|
||
server {
|
||
root /etc/nginx;
|
||
|
||
location /hello.txt {
|
||
try_files $uri $uri/ =404;
|
||
proxy_pass http://127.0.0.1:8080/;
|
||
}
|
||
}
|
||
```
|
||
U ovoj konfiguraciji, `/etc/nginx` je označen kao korenski direktorijum. Ova postavka omogućava pristup datotekama unutar specificiranog korenskog direktorijuma, kao što je `/hello.txt`. Međutim, važno je napomenuti da je definisana samo specifična lokacija (`/hello.txt`). Nema konfiguracije za korensku lokaciju (`location / {...}`). Ova propuštena konfiguracija znači da se korenska direktiva primenjuje globalno, omogućavajući zahteve za korenskim putem `/` da pristupaju datotekama pod `/etc/nginx`.
|
||
|
||
Kritična bezbednosna razmatranja proizilaze iz ove konfiguracije. Jednostavan `GET` zahtev, poput `GET /nginx.conf`, mogao bi otkriti osetljive informacije tako što bi poslužio Nginx konfiguracionu datoteku koja se nalazi na `/etc/nginx/nginx.conf`. Postavljanje korena na manje osetljiv direktorijum, poput `/etc`, moglo bi smanjiti ovaj rizik, ali i dalje može omogućiti nepredviđeni pristup drugim kritičnim datotekama, uključujući druge konfiguracione datoteke, logove pristupa, pa čak i šifrovane akreditive korišćene za HTTP osnovnu autentifikaciju.
|
||
|
||
## Alias LFI Misconfiguration <a href="#alias-lfi-misconfiguration" id="alias-lfi-misconfiguration"></a>
|
||
|
||
U konfiguracionim datotekama Nginx-a, potrebno je pažljivo ispitivanje "location" direktiva. Ranljivost poznata kao Local File Inclusion (LFI) može biti nenamerno uvedena kroz konfiguraciju koja liči na sledeću:
|
||
```
|
||
location /imgs {
|
||
alias /path/images/;
|
||
}
|
||
```
|
||
Ova konfiguracija je podložna LFI napadima zbog toga što server interpretira zahteve poput `/imgs../flag.txt` kao pokušaj pristupa datotekama van predviđene direktorijuma, što se efektivno rešava na `/path/images/../flag.txt`. Ova greška omogućava napadačima da preuzmu datoteke sa serverovog fajl sistema koje ne bi trebale biti dostupne putem veba.
|
||
|
||
Da bi se ublažila ova ranjivost, konfiguracija bi trebala biti prilagođena na:
|
||
```
|
||
location /imgs/ {
|
||
alias /path/images/;
|
||
}
|
||
```
|
||
Više informacija: [https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/](https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/)
|
||
|
||
Accunetix testira:
|
||
```
|
||
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
|
||
```
|
||
## Unsafe path restriction <a href="#unsafe-variable-use" id="unsafe-variable-use"></a>
|
||
|
||
Proverite sledeću stranicu da biste saznali kako da zaobiđete direktive kao što su:
|
||
```plaintext
|
||
location = /admin {
|
||
deny all;
|
||
}
|
||
|
||
location = /admin/ {
|
||
deny all;
|
||
}
|
||
```
|
||
{{#ref}}
|
||
../../pentesting-web/proxy-waf-protections-bypass.md
|
||
{{#endref}}
|
||
|
||
## Nepravilna upotreba varijabli / HTTP Request Splitting <a href="#unsafe-variable-use" id="unsafe-variable-use"></a>
|
||
|
||
> [!CAUTION]
|
||
> Ranljive varijable `$uri` i `$document_uri` i ovo se može ispraviti zamenom sa `$request_uri`.
|
||
>
|
||
> Regex može biti takođe ranjiv kao:
|
||
>
|
||
> `location ~ /docs/([^/])? { … $1 … }` - Ranjiv
|
||
>
|
||
> `location ~ /docs/([^/\s])? { … $1 … }` - Nije ranjiv (proverava razmake)
|
||
>
|
||
> `location ~ /docs/(.*)? { … $1 … }` - Nije ranjiv
|
||
|
||
Ranjivost u Nginx konfiguraciji je prikazana u sledećem primeru:
|
||
```
|
||
location / {
|
||
return 302 https://example.com$uri;
|
||
}
|
||
```
|
||
Karakteri \r (Carriage Return) i \n (Line Feed) označavaju karaktere novog reda u HTTP zahtevima, a njihovi URL-enkodirani oblici predstavljeni su kao `%0d%0a`. Uključivanje ovih karaktera u zahtev (npr., `http://localhost/%0d%0aDetectify:%20clrf`) na pogrešno konfigurisanoj serveru rezultira time da server izdaje novi header pod nazivom `Detectify`. To se dešava zato što $uri varijabla dekodira URL-enkodirane karaktere novog reda, što dovodi do neočekivanog headera u odgovoru:
|
||
```
|
||
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
|
||
```
|
||
Saznajte više o rizicima CRLF injekcije i deljenja odgovora na [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/).
|
||
|
||
Takođe, ova tehnika je [**objašnjena u ovom predavanju**](https://www.youtube.com/watch?v=gWQyWdZbdoY&list=PL0xCSYnG_iTtJe2V6PQqamBF73n7-f1Nr&index=77) sa nekim ranjivim primerima i mehanizmima detekcije. Na primer, da biste otkrili ovu pogrešnu konfiguraciju iz perspektive crne kutije, mogli biste koristiti ove zahteve:
|
||
|
||
- `https://example.com/%20X` - Bilo koji HTTP kod
|
||
- `https://example.com/%20H` - 400 Bad Request
|
||
|
||
Ako je ranjiv, prvi će se vratiti kao "X" je bilo koja HTTP metoda, a drugi će vratiti grešku jer H nije važeća metoda. Tako će server primiti nešto poput: `GET / H HTTP/1.1` i to će izazvati grešku.
|
||
|
||
Drugi primeri detekcije bi bili:
|
||
|
||
- `http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x` - Bilo koji HTTP kod
|
||
- `http://company.tld/%20HTTP/1.1%0D%0AHost:%20x` - 400 Bad Request
|
||
|
||
Neke pronađene ranjive konfiguracije predstavljene u tom predavanju su:
|
||
|
||
- Obratite pažnju kako je **`$uri`** postavljen kao što jeste u konačnom URL-u.
|
||
```
|
||
location ^~ /lite/api/ {
|
||
proxy_pass http://lite-backend$uri$is_args$args;
|
||
}
|
||
```
|
||
- Imajte na umu kako je ponovo **`$uri`** u URL-u (ovog puta unutar parametra)
|
||
```
|
||
location ~ ^/dna/payment {
|
||
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
|
||
proxy_pass http://$back;
|
||
```
|
||
- Sada u AWS S3
|
||
```
|
||
location /s3/ {
|
||
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
|
||
}
|
||
```
|
||
### Any variable
|
||
|
||
Otkriveno je da **podaci koje unosi korisnik** mogu biti tretirani kao **Nginx varijabla** pod određenim okolnostima. Uzrok ovog ponašanja ostaje donekle nejasan, ali nije retko niti jednostavno za verifikaciju. Ova anomalija je istaknuta u bezbednosnom izveštaju na HackerOne, koji se može pogledati [ovde](https://hackerone.com/reports/370094). Dalja istraga o poruci greške dovela je do identifikacije njenog pojavljivanja unutar [SSI filter modula Nginx-ovog koda](https://github.com/nginx/nginx/blob/2187586207e1465d289ae64cedc829719a048a39/src/http/modules/ngx_http_ssi_filter_module.c#L365), ukazujući na Server Side Includes (SSI) kao osnovni uzrok.
|
||
|
||
Da bi se **otkrila ova pogrešna konfiguracija**, može se izvršiti sledeća komanda, koja uključuje postavljanje referer zaglavlja za testiranje štampanja varijable:
|
||
```bash
|
||
$ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar’
|
||
```
|
||
Skeneri za ovu pogrešnu konfiguraciju širom sistema otkrili su više instanci gde su Nginx varijable mogle biti štampane od strane korisnika. Međutim, smanjenje broja ranjivih instanci sugeriše da su napori za ispravku ovog problema bili donekle uspešni.
|
||
|
||
### Korišćenje try_files sa $URI$ARGS varijablama
|
||
|
||
Sledeća Nginx pogrešna konfiguracija može dovesti do LFI ranjivosti:
|
||
```
|
||
location / {
|
||
try_files $uri$args $uri$args/ /index.html;
|
||
}
|
||
```
|
||
U našoj konfiguraciji imamo direktivu `try_files` koja se koristi za proveru postojanja fajlova u određenom redosledu. Nginx će poslužiti prvi koji pronađe. Osnovna sintaksa direktive `try_files` je sledeća:
|
||
```
|
||
try_files file1 file2 ... fileN fallback;
|
||
```
|
||
Nginx će proveriti postojanje svake datoteke u navedenom redosledu. Ako datoteka postoji, biće odmah poslužena. Ako nijedna od navedenih datoteka ne postoji, zahtev će biti prosleđen opciji za rezervu, koja može biti druga URI ili specifična stranica sa greškom.
|
||
|
||
Međutim, kada se koriste `$uri$args` promenljive u ovoj direktivi, Nginx će pokušati da potraži datoteku koja odgovara URI zahteva u kombinaciji sa bilo kojim argumentima upita. Stoga možemo iskoristiti ovu konfiguraciju:
|
||
```
|
||
http {
|
||
server {
|
||
root /var/www/html/public;
|
||
|
||
location / {
|
||
try_files $uri$args $uri$args/ /index.html;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
Sa sledećim payload-om:
|
||
```
|
||
GET /?../../../../../../../../etc/passwd HTTP/1.1
|
||
Host: example.com
|
||
```
|
||
Koristeći naš payload, izaći ćemo iz root direktorijuma (definisanog u Nginx konfiguraciji) i učitati datoteku `/etc/passwd`. U debug logovima možemo posmatrati kako Nginx pokušava datoteke:
|
||
```
|
||
...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 protiv Nginx koristeći prethodno pomenutu konfiguraciju:
|
||

|
||
|
||
## Čitanje sirovog odgovora backend-a
|
||
|
||
Nginx nudi funkciju kroz `proxy_pass` koja omogućava presretanje grešaka i HTTP zaglavlja koja proizvodi backend, sa ciljem da sakrije interne poruke greške i zaglavlja. To se postiže tako što Nginx servira prilagođene stranice greške kao odgovor na greške backend-a. Međutim, izazovi se javljaju kada Nginx naiđe na nevažeći HTTP zahtev. Takav zahtev se prosleđuje backend-u onako kako je primljen, a sirovi odgovor backend-a se zatim direktno šalje klijentu bez intervencije Nginx-a.
|
||
|
||
Razmotrite primer scenarija koji uključuje uWSGI aplikaciju:
|
||
```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!"]
|
||
```
|
||
Da bi se to upravljalo, koriste se specifične direktive u Nginx konfiguraciji:
|
||
```
|
||
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): Ova direktiva omogućava Nginxu da servira prilagođeni odgovor za pozadinske odgovore sa status kodom većim od 300. Osigurava da, za naš primer uWSGI aplikacije, `500 Error` odgovor bude presretnut i obrađen od strane Nginxa.
|
||
- [**proxy_hide_header**](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header): Kao što ime sugeriše, ova direktiva skriva određene HTTP zaglavlja od klijenta, poboljšavajući privatnost i sigurnost.
|
||
|
||
Kada se izvrši važeći `GET` zahtev, Nginx ga obrađuje normalno, vraćajući standardni odgovor o grešci bez otkrivanja bilo kakvih tajnih zaglavlja. Međutim, nevažeći HTTP zahtev zaobilazi ovaj mehanizam, što rezultira izlaganjem sirovih pozadinskih odgovora, uključujući tajna zaglavlja i poruke o grešci.
|
||
|
||
## merge_slashes postavljeno na off
|
||
|
||
Podrazumevano, Nginxova **`merge_slashes` direktiva** je postavljena na **`on`**, što kompresuje više uzastopnih kose crte u URL-u u jednu kosu crtu. Ova funkcija, iako pojednostavljuje obradu URL-a, može nenamerno prikriti ranjivosti u aplikacijama iza Nginxa, posebno onima koje su podložne napadima lokalnog uključivanja datoteka (LFI). Stručnjaci za bezbednost **Danny Robinson i Rotem Bar** su istakli potencijalne rizike povezane sa ovim podrazumevanjem, posebno kada Nginx deluje kao obrnuti proxy.
|
||
|
||
Da bi se umanjili takvi rizici, preporučuje se **isključivanje `merge_slashes` direktive** za aplikacije koje su podložne ovim ranjivostima. Ovo osigurava da Nginx prosledi zahteve aplikaciji bez izmene strukture URL-a, čime se ne prikrivaju nikakvi osnovni problemi sa bezbednošću.
|
||
|
||
Za više informacija pogledajte [Danny Robinson i Rotem Bar](https://medium.com/appsflyer/nginx-may-be-protecting-your-applications-from-traversal-attacks-without-you-even-knowing-b08f882fd43d).
|
||
|
||
### **Maclicious Response Headers**
|
||
|
||
Kao što je prikazano u [**ovoj analizi**](https://mizu.re/post/cors-playground), postoje određena zaglavlja koja, ako su prisutna u odgovoru sa web servera, menjaju ponašanje Nginx proxy-a. Možete ih proveriti [**u dokumentaciji**](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/):
|
||
|
||
- `X-Accel-Redirect`: Ukazuje Nginxu da interno preusmeri zahtev na određenu lokaciju.
|
||
- `X-Accel-Buffering`: Kontroliše da li Nginx treba da baferuje odgovor ili ne.
|
||
- `X-Accel-Charset`: Postavlja karakter set za odgovor kada se koristi X-Accel-Redirect.
|
||
- `X-Accel-Expires`: Postavlja vreme isteka za odgovor kada se koristi X-Accel-Redirect.
|
||
- `X-Accel-Limit-Rate`: Ograničava brzinu prenosa za odgovore kada se koristi X-Accel-Redirect.
|
||
|
||
Na primer, zaglavlje **`X-Accel-Redirect`** će izazvati interno **preusmeravanje** u Nginxu. Tako da imati Nginx konfiguraciju sa nečim poput **`root /`** i odgovorom sa web servera sa **`X-Accel-Redirect: .env`** će nagnati Nginx da pošalje sadržaj **`/.env`** (Path Traversal).
|
||
|
||
### **Podrazumevana vrednost u Map direktivi**
|
||
|
||
U **Nginx konfiguraciji**, `map` direktiva često igra ulogu u **kontroli autorizacije**. Uobičajena greška je neodređivanje **podrazumevane** vrednosti, što može dovesti do neovlašćenog pristupa. Na primer:
|
||
```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";
|
||
}
|
||
}
|
||
```
|
||
Bez `default`, **maliciozni korisnik** može zaobići sigurnost pristupajući **neodređenom URI** unutar `/map-poc`. [Nginx priručnik](https://nginx.org/en/docs/http/ngx_http_map_module.html) savetuje postavljanje **podrazumevane vrednosti** kako bi se izbegli takvi problemi.
|
||
|
||
### **DNS Spoofing Ranljivost**
|
||
|
||
DNS spoofing protiv Nginx-a je izvodljiv pod određenim uslovima. Ako napadač zna koji **DNS server** koristi Nginx i može presresti njegove DNS upite, može falsifikovati DNS zapise. Ova metoda, međutim, nije efikasna ako je Nginx konfigurisan da koristi **localhost (127.0.0.1)** za DNS rezoluciju. Nginx omogućava specificiranje DNS servera na sledeći način:
|
||
```yaml
|
||
resolver 8.8.8.8;
|
||
```
|
||
### **`proxy_pass` i `internal` Direktive**
|
||
|
||
Direktiva **`proxy_pass`** se koristi za preusmeravanje zahteva na druge servere, bilo interno ili eksterno. Direktiva **`internal`** osigurava da su određene lokacije dostupne samo unutar Nginx-a. Iako ove direktive same po sebi nisu ranjivosti, njihova konfiguracija zahteva pažljivo ispitivanje kako bi se sprečili sigurnosni propusti.
|
||
|
||
## proxy_set_header Upgrade & Connection
|
||
|
||
Ako je nginx server konfigurisan da prosledi Upgrade i Connection zaglavlja, može se izvršiti [**h2c Smuggling napad**](../../pentesting-web/h2c-smuggling.md) kako bi se pristupilo zaštićenim/internim krajnjim tačkama.
|
||
|
||
> [!CAUTION]
|
||
> Ova ranjivost bi omogućila napadaču da **uspostavi direktnu vezu sa `proxy_pass` krajnjom tačkom** (`http://backend:9999` u ovom slučaju) čiji sadržaj neće biti proveravan od strane nginx-a.
|
||
|
||
Primer ranjive konfiguracije za krađu `/flag` sa [ovde](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]
|
||
> Imajte na umu da čak i ako je `proxy_pass` usmeren na određeni **put** kao što je `http://backend:9999/socket.io`, veza će biti uspostavljena sa `http://backend:9999`, tako da možete **kontaktirati bilo koji drugi put unutar tog internog krajnjeg tačke. Tako da nije važno ako je put specificiran u URL-u proxy_pass.**
|
||
|
||
## Pokušajte sami
|
||
|
||
Detectify je kreirao GitHub repozitorijum gde možete koristiti Docker da postavite svoj vlastiti ranjivi Nginx test server sa nekim od pogrešnih konfiguracija o kojima se govori u ovom članku i pokušate da ih pronađete sami!
|
||
|
||
[https://github.com/detectify/vulnerable-nginx](https://github.com/detectify/vulnerable-nginx)
|
||
|
||
## Alati za statičku analizu
|
||
|
||
### [GIXY](https://github.com/yandex/gixy)
|
||
|
||
Gixy je alat za analizu Nginx konfiguracije. Glavni cilj Gixy je sprečavanje sigurnosnih pogrešnih konfiguracija i automatizacija otkrivanja grešaka.
|
||
|
||
### [Nginxpwner](https://github.com/stark0de/nginxpwner)
|
||
|
||
Nginxpwner je jednostavan alat za traženje uobičajenih Nginx pogrešnih konfiguracija i ranjivosti.
|
||
|
||
## Reference
|
||
|
||
- [**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}}
|