HTTP Request Smuggling occurs when an attacker exploits inconsistencies in how different web servers handle multiple HTTP requests sent in a single packet. This can lead to various types of attacks, including:
- Session Hijacking: Hijacking other users’ sessions by manipulating the way sessions are managed.
- Cache Poisoning: Poisoning the web cache to serve malicious content to users.
- Cross-Site Scripting (XSS): Injecting malicious scripts to be executed by users’ browsers.
- Bypassing Security Controls: Circumventing security mechanisms such as web application firewalls (WAFs).
HTTP Request Smuggling typically exploits the difference in interpretation of Content-Length and Transfer-Encoding headers between two servers. By carefully crafting HTTP requests, attackers can trick one server into processing a request differently than another server, leading to unintended behaviors.
Example Scenario
- Client to Proxy: The attacker sends an HTTP request to a proxy server (we may call it front-end server) with both
Content-Length
andTransfer-Encoding: chunked
headers. - Proxy to Backend Server: The proxy might interpret the request using one of the headers (e.g., Content-Length), while the backend server interprets it using the other header (e.g., Transfer-Encoding).
- Smuggled Request: This discrepancy can cause part of the request to be treated as a new, independent request by the backend server, thus “smuggling” the malicious request.
The way to detect this type of vulnerability is by craft HTTP requests with overlapping or conflicting headers and observe how they are processed by the web application.
Example Payload
Here is an example of a crafted HTTP request to demonstrate HTTP Request Smuggling:
POST / HTTP/1.1
Host: example.com
Content-Length: 13
Transfer-Encoding: chunked
0
POST /malicious HTTP/1.1
Host: example.com
Content-Length: 5
hello
In this example, if the proxy interprets the request as having a Content-Length of 13, but the backend server interprets it as chunked, the second POST
request (/malicious
) may be processed as an independent request.
Example Payload 2
Here is a more detailed look at the HTTP smuggling request:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 4
1
A
X
Headers Conflict
- Transfer-Encoding: chunked: Indicates that the body of the request will be sent in chunks.
- Content-Length: 4: Specifies that the total length of the body is 4 bytes.
Breakdown of the Request Body
The body of the request looks like this:
1
A
X
Understanding Chunked Transfer Encoding
In chunked transfer encoding, the body is sent in a series of chunks. Each chunk begins with its size in hexadecimal, followed by the data, and ends with a carriage return and line feed (\r\n
). The message ends with a chunk of size 0
.
Front-End Server Behavior
The front-end server processes the Content-Length
header, meaning it expects the body to be exactly 4 bytes long. Hereβs how it processes the body:
- 1 (1 byte): Indicates the size of the first chunk.
- A (1 byte): The actual data of the first chunk.
- \n (1 byte): The newline character indicating the end of the chunk.
- X (1 byte): Extra data.
Thus, the front-end server reads 4 bytes: 1
, A
, \n
, and X
. It forwards these 4 bytes to the back-end server.
Back-End Server Behavior
The back-end server processes the Transfer-Encoding: chunked
header. It expects the body to be in chunks. Hereβs how it interprets the received body:
- 1 (1 byte): Indicates a chunk of 1 byte.
- A (1 byte): The actual data of the chunk.
- \n (1 byte): End of the chunk.
At this point, the back-end server expects either more chunks or the terminating chunk (0\r\n
). However, because it received only the 4 bytes forwarded by the front-end server, it doesn’t receive the termination signal for the chunks.
Properly Terminated Chunked Message
A properly terminated chunked message looks like this:
1\r\n // Chunk size (1 byte)
A\r\n // Chunk data
0\r\n // End of chunks (chunk size 0)
\r\n // End of message
Resulting Behavior
Due to the conflict between the Content-Length
and Transfer-Encoding: chunked
headers, the following occurs:
- Front-End Server: Reads and forwards exactly 4 bytes (
1A\nX
) as perContent-Length: 4
. - Back-End Server: Interprets the chunks but finds the message incomplete because it does not end with a
0\r\n
chunk, causing it to wait for more data.
This mismatch causes the back-end server to wait indefinitely for the proper termination sequence, leading to an observable delay.