LFI2RCE preko Nginx privremenih fajlova

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Ranjiva konfiguracija

Example from bierbaumer.net je pokazao da je čak i sledeći jednolinijski primer dovoljan kada PHP radi iza nginx reverse proxy-ja koji baferuje tela zahteva na disk:

<?php
$action = $_GET['action'] ?? 'read';
$path   = $_GET['file'] ?? 'index.php';
$action === 'read' ? readfile($path) : include $path;

The nginx side typically keeps default temp paths such as /var/lib/nginx/body and /var/lib/nginx/fastcgi. When a request body or upstream response is larger than the in-memory buffer (≈8 KB by default), nginx transparently writes the data to a temp file, keeps the file descriptor open, and only unlinks the file name. Any PHP include that follows symbolic links (like /proc/<pid>/fd/<fd>) can still execute the unlinked contents, giving you RCE through LFI.

Zašto su nginx privremene datoteke zloupotrebljive

  • Tela zahteva koja premašuju prag bafera se preusmeravaju u client_body_temp_path (podrazumevano /tmp/nginx/client-body ili /var/lib/nginx/body).
  • Ime datoteke je nasumično, ali file descriptor ostaje dostupan preko /proc/<nginx_pid>/fd/<fd>. Dokle god telo zahteva nije završeno (ili držite TCP stream otvorenim), nginx drži descriptor otvoren iako je putanja uklonjena.
  • PHP-ov include/require rešava te /proc/.../fd/... symlinkove, pa napadač sa LFI može kroz procfs izvršiti baferovanu privremenu datoteku i posle brisanja od strane nginx-a.

Klasični tok eksploatacije (pregled)

  1. Enumeriši worker PIDs. Dohvati /proc/<pid>/cmdline preko LFI dok ne nađeš stringove poput nginx: worker process. Broj worker-a retko prelazi broj CPU jezgara, pa trebaš skenirati samo niži PID opseg.
  2. Prinuđi nginx da kreira privremenu datoteku. Pošalji veoma velike POST/PUT body-je (ili proxied response-e) tako da nginx prebaci sadržaj u /var/lib/nginx/body/XXXXXXXX. Pobrini se da backend nikada ne pročita ceo body — npr. zadrži upload thread otvoren (keep-alive) kako bi nginx držao descriptor otvoren.
  3. Mapiraj descriptor-e na fajlove. Sa listom PID-ova generiši traversal lance kao /proc/<pidA>/cwd/proc/<pidB>/root/proc/<pidC>/fd/<fd> da zaobiđeš bilo kakvu realpath() normalizaciju pre nego što PHP razreši konačnu metu /proc/<victim_pid>/fd/<interesting_fd>. Bruteforsovanje file descriptor-a u opsegu 10–45 obično je dovoljno jer nginx ponovo koristi taj raspon za body temp fajlove.
  4. Include za izvršenje. Kada pogodite descriptor koji i dalje pokazuje na baferovano telo, jedan poziv include ili require pokreće tvoj payload — iako je originalno ime datoteke već unlinked. Ako ti treba samo čitanje fajla, prebaci se na readfile() da eksfiltriraš privremeni sadržaj umesto da ga izvršavaš.

Modernije varijante (2024–2025)

Ingress controllers i service mesh sada rutinski izlažu nginx instance sa dodatnim površinama za napad. CVE-2025-1974 (“IngressNightmare”) je dobar primer kako se klasični trik sa temp fajlovima razvija:

  • Napadači ubacuju maliciozni shared object kao telo zahteva. Pošto je telo >8 KB, nginx ga baferuje u /tmp/nginx/client-body/cfg-<random>. Namernim lažiranjem Content-Length header-a (npr. navodeći 1 MB i nikada ne šaljući poslednji deo) temp fajl ostaje pinned otprilike ~60 sekundi.
  • Ranljivi ingress-nginx template kod je dozvoljavao injektovanje direktiva u generisanu nginx konfiguraciju. Kombinacija toga sa zadržanom temp datotekom omogućila je bruteforce /proc/<pid>/fd/<fd> linkova dok napadač nije otkrio baferovani shared object.
  • Injektovanje ssl_engine /proc/<pid>/fd/<fd>; primoralo je nginx da učita baferovanu .so. Konstruktor-i unutar shared object-a su odmah dali RCE unutar ingress controller poda, što je zauzvrat otkrilo Kubernetes secrets.

Skraćeni reconnaissance snippet za ovu vrstu napada izgleda ovako:

Brzi procfs skener ```python #!/usr/bin/env python3 import os

def find_tempfds(pid_range=range(100, 4000), fd_range=range(10, 80)): for pid in pid_range: fd_dir = f“/proc/{pid}/fd“ if not os.path.isdir(fd_dir): continue for fd in fd_range: try: path = os.readlink(f“{fd_dir}/{fd}“) if “client-body” in path or “nginx” in path: yield pid, fd, path except OSError: continue

for pid, fd, path in find_tempfds(): print(f“use ?file=/proc/{pid}/fd/{fd} # {path}“)

</details>

Pokrenite ga iz bilo kog primitive (command injection, template injection, etc.) koji već imate. Vratite otkrivene `/proc/<pid>/fd/<fd>` putanje u vaš LFI parametar da uključite buffered payload.

## Praktični saveti

* Kada nginx isključi buffering (`proxy_request_buffering off`, `client_body_buffer_size` tuned high, or `proxy_max_temp_file_size 0`), tehnika postaje mnogo teža — zato uvek enumerišite konfiguracione fajlove i zaglavlja odgovora da proverite da li je buffering i dalje omogućen.
* Hanging uploads su bučni ali efikasni. Koristite više procesa da preplavite radnike tako da bar jedan temp fajl ostane dovoljno dugo da vaš LFI brute force može da ga uhvati.
* U Kubernetes ili drugim orkestratorima, granice privilegija mogu izgledati drugačije, ali the primitive je isti: pronađite način da ubacite bajtove u nginx buffere, pa onda pretražujte `/proc` sa bilo kog mesta odakle možete da čitate fajl sistem.

## Labovi

- [https://bierbaumer.net/security/php-lfi-with-nginx-assistance/php-lfi-with-nginx-assistance.tar.xz](https://bierbaumer.net/security/php-lfi-with-nginx-assistance/php-lfi-with-nginx-assistance.tar.xz)
- [https://2021.ctf.link/internal/challenge/ed0208cd-f91a-4260-912f-97733e8990fd/](https://2021.ctf.link/internal/challenge/ed0208cd-f91a-4260-912f-97733e8990fd/)
- [https://2021.ctf.link/internal/challenge/a67e2921-e09a-4bfa-8e7e-11c51ac5ee32/](https://2021.ctf.link/internal/challenge/a67e2921-e09a-4bfa-8e7e-11c51ac5ee32/)

## Reference

- [https://bierbaumer.net/security/php-lfi-with-nginx-assistance/](https://bierbaumer.net/security/php-lfi-with-nginx-assistance/)
- [https://www.opswat.com/blog/ingressnightmare-cve-2025-1974-remote-code-execution-vulnerability-remediation](https://www.opswat.com/blog/ingressnightmare-cve-2025-1974-remote-code-execution-vulnerability-remediation)

> [!TIP]
> Učite i vežbajte AWS Hacking:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> Učite i vežbajte GCP Hacking: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> Učite i vežbajte Azure Hacking: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>Podržite HackTricks</summary>
>
> - Proverite [**planove pretplate**](https://github.com/sponsors/carlospolop)!
> - **Pridružite se** 💬 [**Discord grupi**](https://discord.gg/hRep4RUj7f) ili [**telegram grupi**](https://t.me/peass) ili **pratite** nas na **Twitteru** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Podelite hakerske trikove slanjem PR-ova na** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repozitorijume.
>
> </details>