HTTP Request Smuggling Explained
Jul, 24th 2023
HTTP Request Smuggling (HRS) is a type of attack that is gaining more and more attention in recent years. Its rise is fueled by the high prevalence of Cloud-based applications and services.
In this article, we’ll learn the basics of this attack. We’ll see how it works, how to exploit its various forms, and how to protect against it.
Introduction to HTTP Request Smuggling
Before I go ahead and explain what HTTP Request Smuggling is, we should first start with a brief reminder of how the web works and how web pages are loaded in the web browser.
The Web Page Loading Process
So, here is how the process goes:
- A user types in a web browser the HTTP address to a web page.
- The web browser sends an HTTP request to a webserver asking for the requested web page.
- The webserver replies with an HTTP response containing the requested page.
- Finally, the web browser displays the received content to the user.
This process is simple, and it has been the way the web operated for decades.
Well, it was,… for the most part. Actually, this traditional process is becoming less and less common in recent years.
Rather than having direct communication between the client and the webserver, the majority of modern web applications present their content to the user through a chain of HTTP servers.
In addition to the web server that hosts the requested web page, the HTTP communication may also pass through a reverse proxy, a load balancer, a web application firewall, or a caching server. Each of these servers interprets the HTTP header of the requests before forwarding them.
Here is a more realistic representation of how the process works.
- A user types in a web browser the HTTP address to a web page.
- The web browser sends an HTTP request to the front-end web server asking for the requested web page.
- After processing the request, the front-end web server forwards it to the back-end server
- The webserver replies with an HTTP response containing the requested page.
- Finally, the web browser displays the received content to the user.
In this case, the front-end web server sends many requests to the back-end server. So, how does the back-end server knows where one HTTP request ends and another one begins?
Thankfully, the HTTP protocol specification has defined two ways for marking the end of an HTTP request.
Determining the end of HTTP requests
Content-Length
The Content-Length Header contains the length in bytes of the message body.
GET / HTTP/1.1
HOST: target-website.com
Content-Length: 18
Malicious request
The content length in the above example is 18, which is the number of bytes (characters) contained in the body of the request (17 characters in Malicious request
and one character for the new line).
Transfer-Encoding
When the request contains the Transfer-encoding header with a value of chunked, this means that the body of the request contains one or more chunks of data. Each chunk starts with a hexadecimal value that specifies its length and ends with a newline. The webserver understands that it has reached the end of the message body once it encounters a chunk containing the value of zero.
GET / HTTP/1.1
HOST: target-website.com
Transfer-Encoding: chunked
12
Malicious request
0
The above HTTP request contains one chunk marked by the hexadecimal value of 12 (17 when converted to decimal), which is the length in bytes of Malicious request
. The request then ends when the webserver reaches a chunk of zero. After this, the webserver will start processing the following request.
By having two ways to handle HTTP requests, a big problem arises: What if the two servers do not use the same technique for delimiting HTTP requests?
In this case, the front-end server may forward a request that contains another, hidden, request to the back-end server. You can see how problematic this could be. Well, this is what we call HTTP Request Smuggling.
A malicious request may reach the backend web server without being processed by the frontend server.
Types of HTTP Request Smuggling Attacks
Now that we have seen how HTTP Request Smuggling attacks work, let’s start exploring the different forms of the attack.
CL.TE
When the front-end server uses Content-Length and the back-end server uses Transfer-Encoding, an attacker can send the following payload to smuggle the malicious request to the back-end server:
GET / HTTP/1.1
HOST: target-website.com
Transfer-Encoding: chunked
Content-Length: 21
0
Malicious request
The front-end will treat the above message as a single request and passes it to the following server. However, when the back-end server receives this request, it will handle it as two different requests separated by the line that contains 0.
TE.CL
When the front-end server uses Transfer-Encoding and the back-end server uses Content-Length, this time, an attacker can send the following payload to smuggle the malicious request to the back-end server:
GET / HTTP/1.1
HOST: target-website.com
Transfer-Encoding: chunked
Content-Length: 4
12
Malicious request
0
In this situation, the front-end server processes the request based on the Transfer-Encoding Header. And so, it will forward the entire request to the back-end server.
When the back-end server receives the request, it sees that the content-length is 4 bytes, and so it will stop processing the request at the beginning of the line containing Malicious request
. The web server will then consider what comes next as a new request.
TE.TE
When both servers use Transfer-Encoding, they can differ in the way they interpret the header.
For instance, the following requests can be handled differently depending on the presence of space and tab characters:
Transfer-Encoding: chunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding[Tab]:chunked
The options are endless here, but you can see now how the vulnerability can still be present even if the two servers agree on the Transfer-Encoding as a way to separate requests.
Preventing HTTP Request Smuggling Attacks
You can prevent HTTP request smuggling by following certain good practices.
- Use HTTP/2 protocol for communications between front-end and back-end servers.
- The Back-end server should reject all ambiguous requests.
- When possible, use the same web server solution for both the front-end and back-end servers (Apache, Nginx, IIS…). Of course, this won’t always be possible as front-end servers are often hardware appliances that do not offer options for customization.
- Use a Web Application Firewall (WAF) that provides a protection against HTTP Request Smuggling attacks.
Comments
No comments