LFI2RCE via Nginx temp files
Tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Configuração vulnerável
Example from bierbaumer.net mostrou que mesmo o seguinte comando de uma linha é suficiente quando o PHP é executado atrás de um proxy reverso nginx que grava os corpos das requisições no disco:
<?php
$action = $_GET['action'] ?? 'read';
$path = $_GET['file'] ?? 'index.php';
$action === 'read' ? readfile($path) : include $path;
O lado do nginx normalmente mantém caminhos temporários padrão, como /var/lib/nginx/body e /var/lib/nginx/fastcgi. Quando o corpo da requisição ou a resposta upstream é maior que o buffer em memória (≈8 KB por padrão), o nginx grava os dados em um arquivo temporário de forma transparente, mantém o descritor de arquivo aberto e apenas remove o nome do arquivo (unlink). Qualquer include do PHP que siga links simbólicos (como /proc/<pid>/fd/<fd>) ainda pode executar o conteúdo removido, permitindo RCE via LFI.
Por que os arquivos temporários do nginx são abusáveis
- Corpos de requisição que excedem o limiar do buffer são gravados em
client_body_temp_path(padrão para/tmp/nginx/client-bodyou/var/lib/nginx/body). - O nome do arquivo é aleatório, mas o descritor de arquivo permanece acessível em
/proc/<nginx_pid>/fd/<fd>. Enquanto o corpo da requisição não terminar (ou você mantiver a stream TCP pendente), o nginx mantém o descritor aberto mesmo que a entrada de caminho tenha sido removida. - O
include/requiredo PHP resolve esses links simbólicos/proc/.../fd/..., então um atacante com LFI pode pular pelo procfs para executar o arquivo temporário em buffer mesmo depois que o nginx o exclui.
Fluxo clássico de exploração (recapitulação)
- Enumerar PIDs dos workers. Buscar
/proc/<pid>/cmdlinevia LFI até encontrar strings comonginx: worker process. O número de workers raramente excede a contagem de CPUs, então você só precisa escanear a faixa inferior de PIDs. - Forçar o nginx a criar o arquivo temporário. Envie corpos POST/PUT muito grandes (ou respostas proxied) de modo que o nginx derrame para
/var/lib/nginx/body/XXXXXXXX. Garanta que o backend nunca leia o corpo inteiro — por exemplo, mantenha a thread de upload em keep-alive para que o nginx mantenha o descritor aberto. - Mapear descritores para arquivos. Com a lista de PIDs, gere cadeias de travessia como
/proc/<pidA>/cwd/proc/<pidB>/root/proc/<pidC>/fd/<fd>para contornar qualquer normalizaçãorealpath()antes que o PHP resolva o alvo final/proc/<victim_pid>/fd/<interesting_fd>. Forçar via brute-force descritores de arquivo entre 10–45 normalmente é suficiente porque o nginx reusa essa faixa para arquivos temporários de corpo. - Incluir para execução. Quando você encontrar o descritor que ainda aponta para o corpo em buffer, um único
includeourequireexecuta seu payload — mesmo que o nome original do arquivo já tenha sido removido (unlink). Se você só precisa ler o arquivo, usereadfile()para exfiltrar o conteúdo temporário em vez de executá-lo.
Variações modernas (2024–2025)
Ingress controllers e service meshes agora rotineiramente expõem instâncias de nginx com superfície de ataque adicional. CVE-2025-1974 (“IngressNightmare”) é um bom exemplo de como o truque clássico de arquivos temporários evoluiu:
- Atacantes injetam um shared object malicioso como corpo da requisição. Como o corpo é >8 KB, o nginx o bufferiza para
/tmp/nginx/client-body/cfg-<random>. Ao mentir intencionalmente no cabeçalhoContent-Length(por exemplo, alegando 1 MB e nunca enviando o último chunk), o arquivo temporário permanece preso por ~60 segundos. - O código de template vulnerável do ingress-nginx permitia injetar diretivas no config gerado do nginx. Combinar isso com o arquivo temporário persistente tornou possível brute-forcear links
/proc/<pid>/fd/<fd>até que o atacante descobrisse o shared object em buffer. - Injetar
ssl_engine /proc/<pid>/fd/<fd>;forçou o nginx a carregar o.soem buffer. Construtores dentro do shared object resultaram em RCE imediato dentro do pod do ingress controller, que por sua vez expôs segredos do Kubernetes.
Um snippet de reconhecimento reduzido para esse estilo de ataque se parece com:
Scanner rápido de procfs
```python #!/usr/bin/env python3 import osdef 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>
Execute isso a partir de qualquer primitiva (command injection, template injection, etc.) que você já possua. Alimente os caminhos descobertos `/proc/<pid>/fd/<fd>` de volta no parâmetro LFI para incluir o payload armazenado no buffer.
## Practical tips
* When nginx disables buffering (`proxy_request_buffering off`, `client_body_buffer_size` tuned high, or `proxy_max_temp_file_size 0`), the technique becomes much harder—so always enumerate config files and response headers to check whether buffering is still enabled.
* Hanging uploads are noisy but effective. Use multiple processes to flood workers so that at least one temp file stays around long enough for your LFI brute force to catch it.
* In Kubernetes or other orchestrators, privilege boundaries may look different, but the principle is the same: find a way to drop bytes into nginx buffers, then walk `/proc` from anywhere you can issue file system reads.
## Labs
- [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/)
## References
- [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]
> Aprenda e pratique Hacking AWS:<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;">\
> Aprenda e pratique Hacking GCP: <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;">
> Aprenda e pratique Hacking Azure: <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>Supporte o HackTricks</summary>
>
> - Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
> - **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
>
> </details>


