HTTP Request Smuggling Explained

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

The Web Page Loading Process

  1. A user types in a web browser the HTTP address to a web page.
  2. The web browser sends an HTTP request to a webserver asking for the requested web page.
  3. The webserver replies with an HTTP response containing the requested page.
  4. 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.

  1. A user types in a web browser the HTTP address to a web page.
  2. The web browser sends an HTTP request to the front-end web server asking for the requested web page.
  3. After processing the request, the front-end web server forwards it to the back-end server
  4. The webserver replies with an HTTP response containing the requested page.
  5. 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

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).

Method 2 : 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

CL.TE

GET / HTTP/1.1
HOST: target-website.com
Transfer-Encoding: chunked
Content-Length: 21
0Malicious 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

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

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

  • 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.

Originally published at https://patchthenet.com on December 31, 2021.

A cybersecurity enthusiast, and founder @ Patchthenet.com