What Is HTTP Request Smuggling?
The term HTTP request smuggling (HRS) refers to techniques that interfere with the way in which a website processes sequences of HTTP requests.
Request smuggling vulnerabilities are considered critical because they allow threat actors to bypass security controls. The actor then gain unauthorized access to sensitive information and directly compromise other users.
The majority of today’s web applications use chains of HTTP servers between the application logic and users. Users send requests to a “front-end server”, which is also commonly referred to as reverse proxy or load balancer. This server forwards user requests to one or multiple backend servers, which execute application logic.
An HRS attack becomes possible when the front end and back end servers disagree on details of the HTTP protocol. The HTTP specification allows two methods of signaling the end of the HTTP request:
- Using the
- Using the
Threat actors may use both headers in a single request, hiding a second request in the body of the first request. This is how the second request is “smuggled”.
Here are several types of attack enabled by HRS:
- Session hijacking
- Web cache poisoning
- Bypassing a web application firewall (WAF)
- Cross-site scripting (XSS)
In this article:
- How Does an HTTP Smuggling Request Attack Work?
- Which HTTP Features Make HTTP Request Smuggling Possible?
- Types of HTTP Smuggling
- Advanced HTTP Request Smuggling Attacks
- HTTP Request Smuggling Prevention
How Does an HTTP Smuggling Request Attack Work?
During HRS attacks, actors exploit two HTTP headers:
- Content-Length Header – defines the size of the request body in bytes.
- Transfer-Encoding Header – sends the request body in chunks that are separated by newline. Typically, the chunk ends with 0.
Here are the conditions that must be met for the attack to work:
- The front-end server forwards multiple requests to a back-end server, using the same network connection.
- The back-end is in disagreement with the front-end regarding where the message ends.
- The ambiguous message sent by the attacker is interpreted by the back-end server as two individual HTTP requests.
- The second request is designed to perform a malicious action, which cannot be accomplished by the first request.
As you can see in the above image, the top request, sent to the front-end server, is interpreted as 2 different requests by the back-end server.
Which HTTP Features Make HTTP Request Smuggling Possible?
In the past, when HTTP/0.9 was the current version,. smuggling was not possible. The only way to send 3 queries was by opening 3 TCP/IP connections to the server at the same time and each time asking for the targeted document.
In HTTP/1.1, the current version of the HTTP protocol, there are several new features that allow bad behavior:
- Keep Alive mode
- Pipelined queries
- Chunked queries and responses
Let’s see how these features can be exploited, with a load balancer between the end-user and back-end server.
Keep Alive Mode
With this feature, we can open one TCP/IP connection and send more than one request over it. The goal of this is to retrieve all the assets coming with an HTML page faster, by reusing the TCP/IP connection opened for the document, avoiding the slow TCP/IP connection opening. Using keep-alive between HTTP servers and proxies (in the middleware or between the middleware and the backend) is less common.
The other big thing in HTTP/1.1 is pipelining. Pipelining means sending several queries before having the responses of these requests.
The communication between middleware and the back-end server is not using pipelining, but it does use keep-alive, and there lies a problem of HTTP Request Smuggling.
Sometimes the communication between these two does not use Keep Alive and that is the first step in defending against HRS attacks. Eventually, the server is never expected to respond to all requests in a pipeline. You can get the first response with a Connection: close header, cutting the Keep Alive connection right after the response like shown down below.
Chunk transfer is another way of sending messages over the HTTP protocol. Instead of sending a full size of Content Length, messages can be transferred by small chunks, each one announcing a size.
A special last chunk, empty chunk, marks the end of the message. The important thing with chunks is that it is another way of manipulating the size of the message. Chunks can be used on HTTP responses (usually) but also on queries.
Types of HTTP Smuggling Attacks
There are three main ways to exploit HRS vulnerabilities:
- CL-TE: the front-end server uses the Content-Length header and the back-end server uses the Transfer-Encoding header.
- TE-CL: the front-end server uses the Transfer-Encoding header and the back-end server uses the Content-Length header.
- TE-TE: the front-end and back-end servers both support the Transfer-Encoding header, but one of the servers can be induced not to process it by obfuscating the header in some way.
In this case, the front-end server uses the Content-Length header and the back-end server uses the Transfer-Encoding header. We can perform a simple HTTP request smuggling attack as follows:
POST / HTTP/1.1
The front-end server processes the Content-Length header and determines that this request is 13 bytes long, up to the end of SMUGGLED. This request is forwarded on to the back-end server.
The back-end server processes the Transfer-Encoding header and treats the message body as using chunked encoding. It processes the first chunk, which is stated to be zero-length, and so is treated as terminating the request. The following bytes, SMUGGLED, are left unprocessed, and the back-end server will treat these as being the start of the next request in the sequence.
Here, the front-end server uses the Transfer-Encoding header and the back-end server uses the Content-Length header. We can perform a simple HTTP request smuggling attack as follows:
POST / HTTP/1.1
The front-end server processes the Transfer-Encoding header and treats the message body as using chunked encoding. It processes the first chunk, which is stated to be 8 bytes long, up to the start of the line following SMUGGLED. It processes the second chunk, which is stated to be zero-length, and so is treated as terminating the request. This request is forwarded to the back-end server.
The back-end server processes the Content-Length header and determines that the request body is 3 bytes long, up to the start of the line following 8. The following bytes, starting with SMUGGLED, are left unprocessed, and the back-end server will treat these as being the start of the next request in the sequence.
TE-TE Behavior: Obfuscating the TE Header
Here, the front-end and back-end servers both support the Transfer-Encoding header, but one of the servers can be induced not to process it by obfuscating the header in some way.
There are potentially endless ways to obfuscate the Transfer-Encoding header. For example:
Transfer-Encoding : chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding : chunked
X: X[\n]Transfer-Encoding: chunked
Each of these techniques involves a subtle departure from the HTTP specification. Real-world code that implements a protocol specification rarely adheres to it with absolute precision, and it is common for different implementations to tolerate different variations from the specification.
To uncover a TE-TE vulnerability, it is necessary to find some variation of the Transfer-Encoding header such that only one of the front-end or back-end servers processes it, while the other server ignores it.
Depending whether it is the front-end or the back-end server that can be induced not to process the obfuscated Transfer-Encoding header, the remainder of the attack will take the same form as for the CL-TE or TE-CL vulnerabilities already described.
Advanced HTTP Request Smuggling Attacks
Let’s review a few more advanced HRS attacks that exploit additional features of the HTTP/1.1 protocol.
Bypassing Security Filters
The first type of attack is bypassing security filters on a forbidden query labelled “Smuggle”.
In this type of attack, the Smuggle query is forbidden, but the first query is hiding it query from the middleware filters. Eventually, the Smuggle query is executed on the target behind the filters by the end server.
Replacement of Regular Response
The second type of attack is if the middleware is a cache server. The goal of the attack is cache poisoning, where the faked response is stored on the wrong cache entry. On a successful attack by First request, anyone requesting anything from the server would get Smuggle response. A successful attack will deface the responses for everybody, not only for the attacker. This attack could lead to Deny of Service for the servers.
The trick was to inject a partial query in the stream and wait for the regular user query, coming in the same backend connection and added to the partial request. It means the proxy is able to add some data in [+] to a TCP/IP connection with the backend that was unfinished in [-]. But the proxy does not know that two queries were sent. For the proxy, there was only one query and the response is already received.
This was a complex scheme, but for example, the Second request could contain a valid session that Smuggle did not have (cookies, HTTP Authentication). Also, this valid session was needed for Smuggle query to succeed. Credentials used in Second query are stolen (hijacked) for a Smuggle query.
Damages of such issues are very high (you can make a user perform unwanted POST actions, using his own credentials and rights).
HTTP Request Smuggling Prevention
There are several ways you can prevent an HTTP request smuggling attack.
Prioritizing TE over CL
To prevent TE:CL and CL:TE attacks, make sure that the transfer encoding header is prioritized over content length, whenever there is a request containing both content length and a transfer encoding chunked header.
Disallowing Requests with Both TE and CL and Double CL Headers
To prevent CL:CL, as well as TE:CL and CL:TE attacks, use this more effective alternative to prioritizing TE over CL. Any request that contains both headers will get a response of HTTP 400. HTTP requests containing multiple CL headers with varying length values can also be remediated with a response of HTTP 400. Alternatively, any duplicated field-value can be replaced with a single valid CL field.
Disallowing Malformed TE Headers and Correctly Processing Multiple TE Values
TE:TE smuggling attacks can occur when both the frontend and backend prioritize the TE header. Attackers can insert two TE headers, with one header being processed by the frontend and ignored by the backend and the other doing the opposite. To prevent TE:TE attacks and ensures that multiple TE values are processed correctly, ensure that the following header variation types are rejected:
- Headers with no space before the value, “chunked”
- Headers with extra spaces
- Headers beginning with trailing characters
- Headers providing a value “chunk” instead of “chunked” (the server normalizes this as chunked encoding)
- Headers with multiple spaces before the value, “chunked”
- Headers with quoted values (whether single or double quotations)
- Headers with CRLF characters before the value, “chunked”
- Values with invalid characters
Protecting Against HTTP Request Smuggling with Bright Security
Bright can automatically crawl your applications while they are running in production to test for HTTP Request Smuggling vulnerabilities in your front end and back end servers.
Engineering and security teams can trust Bright’s results, with automatic validation of every finding carried out, and no false positives. Bright generates developer-friendly remediation advice that can help you fix the issue quickly and easily.