Nginx ์ž„์‹œ ํŒŒ์ผ์„ ํ†ตํ•œ LFI2RCE

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

์ทจ์•ฝํ•œ ๊ตฌ์„ฑ

Example from bierbaumer.net ๋Š” PHP๊ฐ€ nginx ์—ญ๋ฐฉํ–ฅ ํ”„๋ก์‹œ ๋’ค์—์„œ ์‹คํ–‰๋˜์–ด ์š”์ฒญ ๋ณธ๋ฌธ์„ ๋””์Šคํฌ์— ๋ฒ„ํผ๋งํ•  ๋•Œ ๋‹ค์Œ ํ•œ ์ค„์งœ๋ฆฌ ๋ช…๋ น์–ด(one-liner)์กฐ์ฐจ๋„ ์ถฉ๋ถ„ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค:

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

nginx ์ชฝ์€ ์ผ๋ฐ˜์ ์œผ๋กœ /var/lib/nginx/body ๋ฐ /var/lib/nginx/fastcgi ๊ฐ™์€ ๊ธฐ๋ณธ ์ž„์‹œ ๊ฒฝ๋กœ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ ๋ณธ๋ฌธ์ด๋‚˜ upstream ์‘๋‹ต์ด ๋ฉ”๋ชจ๋ฆฌ ๋ฒ„ํผ(๊ธฐ๋ณธ โ‰ˆ8โ€ฏKB)๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด nginx๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํˆฌ๋ช…ํ•˜๊ฒŒ ์ž„์‹œ ํŒŒ์ผ์— ์“ฐ๊ณ  ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์—ด์–ด ๋‘” ์ฑ„ ํŒŒ์ผ ์ด๋ฆ„๋งŒ unlink ํ•ฉ๋‹ˆ๋‹ค. /proc/<pid>/fd/<fd> ๊ฐ™์€ ์‹ฌ๋ณผ๋ฆญ ๋งํฌ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋Š” PHP include๋Š” unlink ๋œ ๋‚ด์šฉ๋„ ์—ฌ์ „ํžˆ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ LFI๋ฅผ ํ†ตํ•ด RCE๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์™œ nginx ์ž„์‹œ ํŒŒ์ผ์ด ์•…์šฉ๋  ์ˆ˜ ์žˆ๋Š”๊ฐ€

  • ๋ฒ„ํผ ์ž„๊ณ„๊ฐ’์„ ์ดˆ๊ณผํ•˜๋Š” ์š”์ฒญ ๋ณธ๋ฌธ์€ client_body_temp_path๋กœ ํ”Œ๋Ÿฌ์‹œ๋˜๋ฉฐ(๊ธฐ๋ณธ๊ฐ’์€ /tmp/nginx/client-body ๋˜๋Š” /var/lib/nginx/body)
  • ํŒŒ์ผ ์ด๋ฆ„์€ ๋žœ๋คํ•˜์ง€๋งŒ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋Š” /proc/<nginx_pid>/fd/<fd> ์•„๋ž˜์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค. ์š”์ฒญ ๋ณธ๋ฌธ์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ TCP ์ŠคํŠธ๋ฆผ์„ ๊ฑธ์–ด๋‘” ์ƒํƒœ๋ฉด nginx๋Š” ๊ฒฝ๋กœ ์—”ํŠธ๋ฆฌ๊ฐ€ unlink ๋˜์—ˆ๋”๋ผ๋„ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์—ด์–ด ๋‘ก๋‹ˆ๋‹ค.
  • PHP์˜ include/require๋Š” ํ•ด๋‹น /proc/.../fd/... ์‹ฌ๋ณผ๋ฆญ ๋งํฌ๋ฅผ ํ•ด์„ํ•˜๋ฏ€๋กœ LFI๋ฅผ ๊ฐ€์ง„ ๊ณต๊ฒฉ์ž๋Š” procfs๋ฅผ ํ†ตํ•ด nginx๊ฐ€ ์‚ญ์ œํ•œ ํ›„์—๋„ ๋ฒ„ํผ๋œ ์ž„์‹œ ํŒŒ์ผ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์‹ ์ต์Šคํ”Œ๋กœ์ž‡ ์›Œํฌํ”Œ๋กœ์šฐ (์š”์•ฝ)

  1. ์›Œ์ปค PID ์—ด๊ฑฐ. LFI๋กœ /proc/<pid>/cmdline์„ ๊ฐ€์ ธ์™€ nginx: worker process ๊ฐ™์€ ๋ฌธ์ž์—ด์„ ์ฐพ์Šต๋‹ˆ๋‹ค. ์›Œ์ปค ์ˆ˜๋Š” ๋ณดํ†ต CPU ์ฝ”์–ด ์ˆ˜๋ฅผ ๋„˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‚ฎ์€ PID ์˜์—ญ๋งŒ ์Šค์บ”ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  2. nginx๊ฐ€ ์ž„์‹œ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ฒŒ ๊ฐ•์ œ. ๋งค์šฐ ํฐ POST/PUT ๋ณธ๋ฌธ(๋˜๋Š” ํ”„๋ก์‹œ๋œ ์‘๋‹ต)์„ ๋ณด๋‚ด nginx๊ฐ€ /var/lib/nginx/body/XXXXXXXX๋กœ ์Šคํ•„ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ๊ฐ€ ์ „์ฒด ๋ณธ๋ฌธ์„ ์ ˆ๋Œ€ ์ฝ์ง€ ์•Š๋„๋กโ€”์˜ˆ: ์—…๋กœ๋“œ ์Šค๋ ˆ๋“œ๋ฅผ keep-alive ์ƒํƒœ๋กœ ์œ ์ง€ํ•ด nginx๊ฐ€ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์—ด์–ด๋‘๊ฒŒ ํ•˜์„ธ์š”.
  3. ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ํŒŒ์ผ์— ๋งคํ•‘. PID ๋ชฉ๋ก์œผ๋กœ /proc/<pidA>/cwd/proc/<pidB>/root/proc/<pidC>/fd/<fd> ๊ฐ™์€ ํŠธ๋ž˜๋ฒ„์„ค ์ฒด์ธ์„ ์ƒ์„ฑํ•ด PHP๊ฐ€ ์ตœ์ข… /proc/<victim_pid>/fd/<interesting_fd> ํƒ€๊นƒ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์ „์— realpath() ์ •๊ทœํ™”๋ฅผ ์šฐํšŒํ•˜์„ธ์š”. nginx๊ฐ€ ๋ฐ”๋”” ์ž„์‹œ ํŒŒ์ผ์— ๋Œ€ํ•ด ๋Œ€๊ฐœ ๊ทธ ๋ฒ”์œ„๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ 10โ€“45๋ฅผ ๋ธŒ๋ฃจํŠธํฌ์Šคํ•˜๋ฉด ๋ณดํ†ต ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.
  4. ์‹คํ–‰์„ ์œ„ํ•œ include. ๋ฒ„ํผ๋œ ๋ฐ”๋””๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์ฐพ์œผ๋ฉด ๋‹จ ํ•˜๋‚˜์˜ include ๋˜๋Š” require ํ˜ธ์ถœ๋กœ ํŽ˜์ด๋กœ๋“œ๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค โ€” ์›๋ณธ ํŒŒ์ผ๋ช…์€ ์ด๋ฏธ unlink ๋˜์–ด ์žˆ์–ด๋„์š”. ๋‹จ์ˆœํžˆ ํŒŒ์ผ ์ฝ๊ธฐ๋งŒ ํ•„์š”ํ•˜๋‹ค๋ฉด ์‹คํ–‰ ๋Œ€์‹  readfile()๋กœ ์ž„์‹œ ๋‚ด์šฉ์„ ์œ ์ถœํ•˜์„ธ์š”.

์ตœ์‹  ๋ณ€ํ˜• (2024โ€“2025)

Ingress controllers์™€ service meshes๋Š” ์ด์ œ nginx ์ธ์Šคํ„ด์Šค๋ฅผ ์ถ”๊ฐ€์ ์ธ ๊ณต๊ฒฉ๋ฉด๊ณผ ํ•จ๊ป˜ ๋…ธ์ถœ์‹œํ‚ค๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. CVE-2025-1974 (โ€œIngressNightmareโ€)๋Š” ํด๋ž˜์‹ ์ž„์‹œํŒŒ์ผ ํŠธ๋ฆญ์ด ์–ด๋–ป๊ฒŒ ์ง„ํ™”ํ•˜๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ์ข‹์€ ์˜ˆ์ž…๋‹ˆ๋‹ค:

  • ๊ณต๊ฒฉ์ž๋Š” ์•…์„ฑ shared object๋ฅผ ์š”์ฒญ ๋ณธ๋ฌธ์œผ๋กœ ํ‘ธ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋ณธ๋ฌธ์ด >8โ€ฏKB์ด๊ธฐ ๋•Œ๋ฌธ์— nginx๋Š” ์ด๋ฅผ /tmp/nginx/client-body/cfg-<random>์— ๋ฒ„ํผํ•ฉ๋‹ˆ๋‹ค. Content-Length ํ—ค๋”์— ์˜๋„์ ์œผ๋กœ ๊ฑฐ์ง“์„ ์จ์„œ(์˜ˆ: 1โ€ฏMB๋กœ ์ฃผ์žฅํ•˜๊ณ  ๋งˆ์ง€๋ง‰ ์ฒญํฌ๋ฅผ ๋ณด๋‚ด์ง€ ์•Š์Œ) ์ž„์‹œ ํŒŒ์ผ์„ ์•ฝ ~60์ดˆ๊ฐ„ ๊ณ ์ •์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ทจ์•ฝํ•œ ingress-nginx ํ…œํ”Œ๋ฆฟ ์ฝ”๋“œ๋Š” ์ƒ์„ฑ๋œ nginx config์— ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ ๊ณผ ๋‚จ์•„ ์žˆ๋Š” ์ž„์‹œ ํŒŒ์ผ์„ ๊ฒฐํ•ฉํ•˜๋ฉด ๊ณต๊ฒฉ์ž๋Š” ๋ธŒ๋ฃจํŠธํฌ์Šค๋กœ /proc/<pid>/fd/<fd> ๋งํฌ๋ฅผ ์ฐพ์•„ ๋ฒ„ํผ๋œ shared object๋ฅผ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ssl_engine /proc/<pid>/fd/<fd>;๋ฅผ ์ฃผ์ž…ํ•˜๋ฉด nginx๊ฐ€ ๋ฒ„ํผ๋œ .so๋ฅผ ๋กœ๋“œํ•˜๋„๋ก ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. shared object ๋‚ด๋ถ€์˜ ์ƒ์„ฑ์ž๋“ค์€ ingress controller pod ๋‚ด๋ถ€์—์„œ ์ฆ‰๊ฐ์ ์ธ RCE๋ฅผ ๋ฐœ์ƒ์‹œ์ผฐ๊ณ , ์ด๋Š” Kubernetes ๋น„๋ฐ€์„ ๋…ธ์ถœ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

์ด ์Šคํƒ€์ผ ๊ณต๊ฒฉ์„ ์œ„ํ•œ ์ถ•์•ฝ๋œ ์ •์ฐฐ ์Šค๋‹ˆํŽซ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

๋น ๋ฅธ procfs ์Šค์บ๋„ˆ ```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>

Run it from any primitive (command injection, template injection, etc.) you already have. Feed the discovered `/proc/<pid>/fd/<fd>` paths back into your LFI parameter to include the buffered payload.

## ์‹ค์ „ ํŒ

* nginx๊ฐ€ ๋ฒ„ํผ๋ง์„ ๋น„ํ™œ์„ฑํ™”ํ•  ๋•Œ (`proxy_request_buffering off`, `client_body_buffer_size`๋ฅผ ํฌ๊ฒŒ ์กฐ์ •ํ–ˆ๊ฑฐ๋‚˜ `proxy_max_temp_file_size 0`), ์ด ๊ธฐ๋ฒ•์€ ํ›จ์”ฌ ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค โ€” ๋”ฐ๋ผ์„œ ์„ค์ • ํŒŒ์ผ๊ณผ ์‘๋‹ต ํ—ค๋”๋ฅผ ํ•ญ์ƒ ์—ด๊ฑฐํ•˜์—ฌ ๋ฒ„ํผ๋ง์ด ์—ฌ์ „ํžˆ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.
* Hanging uploads๋Š” ์‹œ๋„๋Ÿฝ์ง€๋งŒ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‚ฌ์šฉํ•ด ์›Œ์ปค๋ฅผ ๊ณผ๋ถ€ํ•˜์‹œ์ผœ ์ ์–ด๋„ ํ•˜๋‚˜์˜ ์ž„์‹œ ํŒŒ์ผ์ด LFI brute force๊ฐ€ ํฌ์ฐฉํ•  ์ˆ˜ ์žˆ์„ ๋งŒํผ ์˜ค๋ž˜ ๋‚จ์•„ ์žˆ๊ฒŒ ํ•˜์„ธ์š”.
* Kubernetes๋‚˜ ๋‹ค๋ฅธ orchestrator ํ™˜๊ฒฝ์—์„œ๋Š” ๊ถŒํ•œ ๊ฒฝ๊ณ„๊ฐ€ ๋‹ค๋ฅด๊ฒŒ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, primitive๋Š” ๊ฐ™์Šต๋‹ˆ๋‹ค: nginx ๋ฒ„ํผ์— ๋ฐ”์ดํŠธ๋ฅผ ๋„ฃ์„ ๋ฐฉ๋ฒ•์„ ์ฐพ๊ณ , ํŒŒ์ผ ์‹œ์Šคํ…œ ์ฝ๊ธฐ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์–ด๋А ๊ณณ์—์„œ๋“  `/proc`์„ ํƒ์ƒ‰ํ•˜์„ธ์š”.

## ์‹ค์Šต

- [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/)

## ์ฐธ๊ณ ์ž๋ฃŒ

- [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]
> 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;">\
> 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;">
> 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>HackTricks ์ง€์›ํ•˜๊ธฐ</summary>
>
> - [**๊ตฌ๋… ๊ณ„ํš**](https://github.com/sponsors/carlospolop) ํ™•์ธํ•˜๊ธฐ!
> - **๐Ÿ’ฌ [**๋””์Šค์ฝ”๋“œ ๊ทธ๋ฃน**](https://discord.gg/hRep4RUj7f) ๋˜๋Š” [**ํ…”๋ ˆ๊ทธ๋žจ ๊ทธ๋ฃน**](https://t.me/peass)์— ์ฐธ์—ฌํ•˜๊ฑฐ๋‚˜ **ํŠธ์œ„ํ„ฐ** ๐Ÿฆ [**@hacktricks_live**](https://twitter.com/hacktricks_live)**๋ฅผ ํŒ”๋กœ์šฐํ•˜์„ธ์š”.**
> - **[**HackTricks**](https://github.com/carlospolop/hacktricks) ๋ฐ [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) ๊นƒํ—ˆ๋ธŒ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— PR์„ ์ œ์ถœํ•˜์—ฌ ํ•ดํ‚น ํŠธ๋ฆญ์„ ๊ณต์œ ํ•˜์„ธ์š”.**
>
> </details>