HTTP Request Smuggling - Desynchronisierung von HTTP-Proxies
HTTP Request Smuggling (CWE-444) ist ein Angriff der Desynchronisierungen zwischen Front-End (Reverse-Proxy, CDN) und Back-End-Server ausnutzt. Unterschiedliche Interpretationen von Content-Length und Transfer-Encoding: chunked erlauben es Angreifern, HTTP-Requests zu 'schmuggeln'. Varianten: CL.TE (Front-End nutzt Content-Length, Back-End Transfer-Encoding), TE.CL (umgekehrt), TE.TE (beide TE, unterschiedliche Behandlung). Resultat: andere User-Requests kapern, Authentifizierung bypassen, Cache-Poisoning.
HTTP Request Smuggling ist eine fortgeschrittene Angriffstechnik die 2019 durch James Kettle (PortSwigger) umfassend dokumentiert wurde. Das Kernprinzip: Wenn ein Load Balancer und ein Backend-Server dieselbe Anfrage unterschiedlich parsen, kann ein Angreifer einen zweiten Request in den TCP-Datenstrom “schmuggeln” - der dann vom Backend als eigenständige Anfrage eines anderen Nutzers verarbeitet wird.
Protokoll-Grundlagen
HTTP/1.1 Request-Längen-Bestimmung - zwei Methoden:
Content-Length (CL):
POST /search HTTP/1.1
Content-Length: 11
q=smuggling
→ Body ist exakt 11 Bytes lang
Transfer-Encoding: chunked (TE):
POST /search HTTP/1.1
Transfer-Encoding: chunked
b ← Chunk-Größe in Hex (11 dezimal)
q=smuggling
0 ← Terminierungs-Chunk (leer)
← Leerzeile nach dem letzten Chunk
RFC 7230: Wenn beide Header vorhanden → Content-Length IGNORIEREN!
→ Aber verschiedene Implementierungen handhaben dies UNTERSCHIEDLICH!
→ Das ist die Grundlage für HTTP Request Smuggling
Request-Pipeline in Mehrstufiger Architektur:
Browser → [Front-End: Load Balancer / CDN / WAF] → [Back-End: App-Server]
Problem:
→ Front-End sieht eine HTTP-Request-Grenze
→ Back-End sieht eine ANDERE HTTP-Request-Grenze
→ Differenz = "Smuggled Request"
Angriffstypen: CL.TE, TE.CL, TE.TE
1. CL.TE - Front-End: Content-Length, Back-End: Transfer-Encoding:
Angreifer sendet:
POST / HTTP/1.1
Host: victim.com
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED
Front-End (nutzt CL=13):
→ Sieht: "0\r\n\r\nSMUGGLED" als einen Request (13 Bytes)
→ Leitet komplett weiter
Back-End (nutzt TE):
→ Chunk: "0" = Ende des Requests → erster Request ist fertig!
→ "SMUGGLED" = Anfang des NÄCHSTEN Requests!
→ Nächster Nutzer-Request wird an "SMUGGLED" angehängt
---
2. TE.CL - Front-End: Transfer-Encoding, Back-End: Content-Length:
POST / HTTP/1.1
Content-Length: 3
Transfer-Encoding: chunked
8
SMUGGLED
0
Front-End (nutzt TE):
→ Chunk 1: "SMUGGLED" (8 Bytes)
→ Terminierungs-Chunk: "0"
→ Ein vollständiger Request
Back-End (nutzt CL=3):
→ Body = "8\r\n" (3 Bytes!)
→ Rest ("SMUGGLED\r\n0\r\n\r\n") = Anfang des nächsten Requests!
---
3. TE.TE - Beide: Transfer-Encoding, aber unterschiedliche Behandlung:
Transfer-Encoding: chunked
Transfer-Encoding: cow ← unbekannte Kodierung
→ Front-End erkennt "chunked" und verarbeitet TE
→ Back-End erkennt "cow" als unbekannt → fällt auf CL zurück!
→ Ergebnis: effektiv TE.CL-Szenario
Weitere Obfuscation-Varianten:
Transfer-Encoding: xchunked
Transfer-Encoding :\tchunked ← Tab vor Doppelpunkt
Transfer-Encoding: chunked
Transfer-encoding: chunked ← Kleinschreibung (RFC: Header case-insensitive!)
X: X[\n]Transfer-Encoding: chunked ← Header-Injection
---
4. HTTP/2 Downgrade Smuggling (H2.CL / H2.TE):
→ CDN/Front-End akzeptiert HTTP/2 vom Client
→ Aber: Backend unterstützt nur HTTP/1.1
→ CDN konvertiert HTTP/2 → HTTP/1.1 (Downgrade!)
Angreifer injiziert in HTTP/2 Request-Header:
:method: POST
:path: /
:authority: victim.com
content-length: 0
transfer-encoding: chunked
→ Front-End ignoriert TE in HTTP/2 (kein Chunked in H2!)
→ Backend erhält HTTP/1.1 mit BEIDEN Headern → Desynchronisierung!
Angriffsziele und Auswirkungen
Was ist mit Smuggling möglich?
1. HTTP-Request-Capturing (andere User-Requests stehlen):
Angreifer schmuggelt:
POST /comment HTTP/1.1
Host: victim.com
Content-Length: 400 ← Großer CL = wartet auf 400 Bytes!
action=store&body= ← Request-Body beginnt hier
→ Nächster Nutzer-Request wird angehängt (bis 400 Bytes voll!)
→ Angreifer liest aus: Cookie, Authorization-Header, POST-Body
→ Credentials + Session-Token des Opfers gestohlen!
2. Privilegien-Eskalation via Internal-Redirect:
Back-End hat /admin nur für 127.0.0.1 zugänglich:
Angreifer schmuggelt:
GET /admin HTTP/1.1
Host: localhost
→ Back-End sieht Request von "localhost" (Front-End forwarded es intern!)
→ Admin-Interface zugänglich!
3. WAF-Bypass:
WAF prüft: POST /api/admin HTTP/1.1 → BLOCKED!
Angreifer schmuggelt Admin-Request als Teil eines erlaubten Requests:
→ WAF sieht normalen Request
→ Back-End-Server verarbeitet den Admin-Endpunkt!
4. Cache-Poisoning via Smuggling:
Angreifer schmuggelt einen Request dessen Response gecacht wird:
GET /static/js/app.js HTTP/1.1
Gecachte Response enthält Angreifer-Payload!
→ Alle folgenden Cache-Requests liefern Angreifer-JS aus!
5. Response Queue Poisoning (HTTP/2):
→ Angreifer sendet so viele Requests dass Response-Queue desynchronisiert
→ Andere Nutzer erhalten falsche Responses
→ Session-Daten anderer Nutzer sichtbar!
Erkennung und Testing
Testing-Ansatz (nur für autorisierte Tests!):
Burp Suite - HTTP Request Smuggler Extension:
→ Burp App Store: HTTP Request Smuggler
→ Automated: Scan → Issues → HTTP Request Smuggling
→ Manual: Repeater mit non-default HTTP/1
Timing-basierte Erkennung (CL.TE):
Schritt 1 - Normal-Request (Baseline):
POST / HTTP/1.1
Content-Length: 4
Transfer-Encoding: chunked
12ab
HALLO
→ Normales Timeout?
Schritt 2 - Anomalie testen:
POST / HTTP/1.1
Content-Length: 6
Transfer-Encoding: chunked
0
X
→ Wenn Back-End TE nutzt: wartet auf 6-Byte-Body (CL)!
→ Response kommt VERZÖGERT → CL.TE bestätigt!
Differential Response Analysis:
→ Zwei identische Requests senden
→ Wenn zweiter Request andere Response gibt → "Vergifteter Puffer"!
→ Beweist: erster Request hat Daten in Back-End-Puffer hinterlassen
Wichtig:
→ Testing NUR auf eigenen/autorisierten Zielsystemen!
→ Smuggling kann andere Nutzer beeinflussen → Kollateralschäden möglich!
→ immer mit sehr kurzen/harmlosen Payloads beginnen (Schaden minimieren)
Schutzmaßnahmen
Defense-Strategien:
1. HTTP/2 Ende-zu-Ende nutzen (keine Downgrade-Konvertierung):
→ Front-End und Back-End beide HTTP/2 → kein Downgrade-Smuggling
→ HTTP/2 hat klares Frame-basiertes Protokoll (kein CL/TE-Konflikt!)
2. Front-End: Request-Normalisierung erzwingen:
HAProxy:
option http-server-close
option forwardfor
# Normalisiert CL/TE vor Weiterleitung
Nginx:
proxy_http_version 1.1; # HTTP/1.1 für Upstream
proxy_set_header Connection ""; # Verhindert Connection-Reuse
3. Ambiguous Requests ablehnen (beides vorhanden → Fehler):
→ Wenn SOWOHL Content-Length als AUCH Transfer-Encoding → 400 zurückgeben
→ RFC-konformes Verhalten: bei Konflikt Content-Length ignorieren (HTTP/1.1)
4. Back-End-Server-Konfiguration:
Apache: RejectOverlappingHeaders On (ab 2.4.55)
IIS: Direkt betroffen durch CL.TE → Update auf aktuelle Version!
Tomcat: rejectIllegalHeader=true in server.xml
5. Monitoring:
□ HTTP 400-Fehler häufen sich: möglicherweise Smuggling-Tests
□ Ungewöhnliche Chunked-Encoding-Requests an statische Endpunkte
□ Requests mit sowohl CL als auch TE loggen + alertieren
6. WAF-Regeln (als Ergänzung, kein Ersatz!):
→ Requests mit beiden Headern (CL + TE) ablehnen
→ Transfer-Encoding Obfuscation erkennen (Tab, Leerzeichen)
→ TE-Header mit unbekannten Werten blockieren