HTTP Request Smuggling
HTTP request smuggling and HTTP/2 tunnelling: bypassing front-end restrictions.
1. What is the problem?#
Many websites have an admin panel (e.g., /admin) that they want to protect from general users.
They often enforce this restriction in the frontend proxy, without changing anything in the backend server.
Example:
- Frontend proxy ACL (Access Control List):
- Allow:
/hello - Deny:
/admin
- Allow:
If you try to visit:
https://MACHINE_IP:8100/adminYou will receive an "access denied" message from the proxy.
2. The Goal of the Attack#
The objective is to bypass the frontend restriction and access /admin on the backend server without the proxy blocking the request.
This is done by smuggling a forbidden request inside a permitted one.
This technique is known as HTTP/2 Request Tunneling.
3. How Does It Work?#
When a client uses HTTP/2, the frontend proxy receives the request and converts it to HTTP/1.1 to communicate with the backend server.
- The proxy checks the path in the HTTP/2 request.
- If the path is allowed (like
/hello), it forwards the request. - The proxy does not inspect or validate the request body in detail.
Key idea:
We can hide an extra HTTP/1.1 request (for /admin) inside the body of an allowed HTTP/2 request (for /hello).
The backend server, when parsing the downgraded HTTP/1.1 request, will see two separate requests:
- The allowed
/hellorequest. - The hidden
/adminrequest.
4. Example Attack Flow#
4.1 Frontend View#
HTTP/2 Request Sent by Attacker:
POST /hello HTTP/2
Host: MACHINE_IP:8100
Content-Length: 0
GET /admin HTTP/1.1
Host: MACHINE_IP:8100- The proxy examines the path
/helloand allows it. - It ignores the body during path-based filtering.
4.2 Backend View#
The proxy converts the HTTP/2 request to HTTP/1.1.
The backend server sees:
POST /hello HTTP/1.1
Content-Length: 0
GET /admin HTTP/1.1
Host: MACHINE_IP:8100- The first request (/hello) is processed normally.
- The second request (/admin) is processed as a separate, valid HTTP/1.1 request.
Result:
The attacker accesses /admin even though it is blocked in the proxy ACL.
5. Why Use POST?#
Using POST instead of GET is recommended because:
- Proxies may cache GET requests, returning a cached response instead of forwarding to the backend.
- POST requests are not cached and are always forwarded.
This ensures that the smuggled request reaches the backend server.
6. Requirement of Sending Twice#
The smuggled request is unfinished (incomplete) on purpose.
The backend will keep the connection open, waiting for the remaining data.
To fully trigger the second request (/admin):
- The attacker (or another user) must send a second request.
- This second request completes the smuggled request on the backend connection.
7. Using Burp Suite#
Steps:#
- Capture a normal request to
/helloin Burp. - Send it to the Repeater.
- Modify the request body to include the smuggled request:
GET /admin HTTP/1.1
Host: MACHINE_IP:8100- Set
Content-Lengthheader to0. - Disable "Update Content-Length" in Repeater to prevent Burp from recalculating it automatically.
- Ensure the request is sent as HTTP/2 (check in Repeater).
- Send the modified request.
Important:
Once you add binary data (like CRLF) in a header, Burp will enter "kettled mode."
You must edit the request using the Inspector tab.
8. Example Burp Request Template#
POST /hello HTTP/2
Host: MACHINE_IP:8100
User-Agent: Mozilla/5.0
Foo: GET /admin HTTP/1.1\r\nHost: MACHINE_IP:8100- The proxy sees the path
/helloand allows it. - The backend parses the second request to
/admin.
9. Summary#
- The frontend proxy only checks the initial path in the HTTP/2 request.
- By hiding (tunneling) an extra request inside the allowed request, you bypass the proxy's restrictions.
- This attack relies on HTTP/2 to HTTP/1.1 downgrading and the proxy's failure to sanitize the body of requests.
- This method can also bypass Web Application Firewalls (WAFs) that rely on path-based blocking.
CL.TE lab (PortSwigger)#
Lab 1: Confirming a CL.TE Vulnerability via Differential Responses#
Key Steps
-
Update the Content-Length
- In Repeater, adjust the
Content-Lengthvalue to match the payload.
sinon t9dr tbdllha nta ela hassab kolla chars wla espace b 1
- In Repeater, adjust the
-
Switch protocol from HTTP/2 to HTTP/1.1
- Ensure the front-end interprets the request as HTTP/1.1.
-
Show non-printable characters
- Enable “Show non-printables” in Burp Repeater (top right toolbar). This helps visualize line breaks (\r\n), spaces, and other hidden characters critical for request smuggling.
-
Change the method to POST
- Use
POSTto include bothContent-LengthandTransfer-Encodingheaders.
- Use
-
Send the smuggling payload
httpPOST / HTTP/1.1 Host: 0a7800d80350a85c8173da63003600c9.web-security-academy.net Content-Type: application/x-www-form-urlencoded Content-Length: 32 Transfer-Encoding: chunked 0 GET /404 HTTP/1.1 X-foo: X
Expected Output First Send → the request is processed normally. The smuggled request (GET /404) receives an HTTP 404 Not Found response.
Note This difference in responses (200 for the first request, 404 for the second) confirms the presence of a CL.TE HTTP Request Smuggling vulnerability. the header X-foo: X is just fake header bach l backend y accepter request wmaychkkch