HTTP Request Smuggling is one of those vulnerabilities that sounds complicated, but the core idea is actually simple. Let’s Understand it in simplest way possible.
When your browser sends a request to a server there are generally two types of servers through which your request goes through -
Press enter or click to view image in full size
The Front end Server uses a single TCP Connection and sends many requests at once to save computation time and costs.
The Question arises here is when a request comes to the Front end server how does it know that the request has ended here and the next request has been started, actually this is identified by the server using either of the two types of headers mentioned below-
Suppose there is a request as Follows :-
Press enter or click to view image in full size
Here as you can see the Content-Length Header has value set to 13, you might wonder why it’s 13 and what are those \r\n actually these are non printable characters and \r\n is known as CRLF (Carraige return Line feed) it is used to represent a new line.
These are non printable characters but they are counted in Content-Length calculation and \r is 1 byte and \n is also 1 byte so \r\n together counted as 2 bytes.
Again now also if you count the full length of the body it should be 15 bytes right ?
Nopes, the first \r\n is used to seprate header and body and body starts behind it so the content length will be 13 only.
So the front end server will read the Content-Length and would know that after 13 bytes the request will be finished and next request will be started from there.
Now what if the server is using Transfer-Encoding to know where the request gets Terminated ?
Suppose there is a request as Follows :-
There is slight difference in how size calculation is done in Content-Length and in Transfer-Encoding: chunked :-
How Chunked Encoding Length Works :-
In HTTP/1.1 chunked encoding, each chunk consists of:
\r\n\r\n0 followed by \r\n to end the messageThe chunk size specifies only the length of the data content, excluding the \r\n line breaks.
So as you can see the chunk size in the request is 5 and in next line “Hello” which is of length 5 and in last line there is a
0to tell the server that the request has been terminated.
All GOOD, but where is the Vulnerability ?
The Vulnerability arises when one of the servers from the front end server and the back end server is using either of the one technique to check for request termination.
1. CL.TE (Frontend uses Content-Length, backend uses Transfer-Encoding)
2. TE.CL (Frontend uses Transfer-Encoding, backend uses Content-Length)
Join Medium for free to get updates from this writer.
3. TE.TE (Both use Transfer-Encoding, but one parses it differently)
But you might wonder how do attackers actually exploit this vulnerability ?
The answer is very simple they just add both the headers into the request and there is a desync created between the servers as both of them are relying on different headers.
Front-end trusts Content-Length& Back-end trusts Transfer-Encoding
What happens:
Content-Length: 13, so it thinks the body is "0\r\n\r\nSMUGGLED" (13 bytes) — the request ends there. It forwards everything as one request.Content-Length and instead trusts Transfer-Encoding: chunked. It sees the chunk 0, which means "end of chunked body" — so it treats the request as ending right there.SMUGGLED sitting unconsumed in the connection buffer. The back-end now treats SMUGGLED as the start of the next request on that same connection.If another legitimate user’s request comes in right after on that same reused connection, the back-end may accidentally glue the attacker’s leftover text onto the front of that innocent request — corrupting it, redirecting it, or letting the attacker read/manipulate parts of someone else’s traffic.
The attacker can also add a full new mallicious request at the place of
SMUGGLED
For example :-
What happens:
Content-Length so it thinks everything inside those 43 bytes belongs to ONE request so forwards all of it.Transfer-Encoding It sees 0 which means request finished.So the remaning data remains in the request Pipeline and now the server thinks Ohhhhh a new request has just arrived.
This ambiguity is what makes request smuggling possible.
Content-Length and Transfer-EncodingHTTP/2 does not use:
Content-Length to delimit framesTransfer-Encoding: chunkedInstead, HTTP/2 sends data in binary frames, and each frame has its own explicit length. There is no ambiguity about where one request ends.