A widespread vulnerability is allowing attackers to steal credentials, route victims to malicious URLs, and preventing users from using the targeted websites. The attack tricks the back-end server into splicing the content of an attacker’s malicious request into the content of the victim’s request. This allows attackers to control part of a normal user’s requests. Several companies, including PayPal and Akamai, have paid tens of thousands of dollars in bug bounties to white hat hackers who identified this vulnerability in their systems.
For the vulnerability to be present, the front-end and back-end servers need to use different methods to determine where the HTTP requests they receive end. One method is to use the request body length given by a Content-Length (CL.) header. The other is to use the header Transfer-Encoding: chunked (TE.), which looks for chunked data in the request body and numbers that indicate how much data is left in the request. If the servers do not agree on where the request ends, an attacker can trick the server into reading some of their malicious request as part of a victim’s request.
The PortSwigger articles and Burp Suite tool use the terms CL. TE. and TE. CL. to distinguish between the two types of desynchronization. If a front-end server uses CL. while the back-end server uses TE., the servers may be susceptible to the CL. TE. version of desynchronization. Similarly, if the front-end server uses TE. and the back-end server uses CL., the servers may be susceptible to the TE. CL. version of desynchronization.
This attack is known as HTTP Desync and was detailed in an article by James Kettle of PortSwigger in August. It is part of the class of attacks known as HTTP request smuggling attacks. These attacks exploit the processes that web application back-end servers use to handle multiple requests from one or more users. We recommend reading James’ articles (article 1, article2) on this subject for more nuances of this attack.
This tutorial demonstrates how to test if front-end and back-end servers can be desynchronized and how to get a proof of concept exploit of the vulnerability. Developing a proof of concept is important as not all front-end and back-end servers that can be desynchronized are exploitable. This tutorial uses Burp Suite Professional to test for the desynchronization and to verify the vulnerability.
Identifying Server Desynchronization
We use the PortSwigger lab to generate our sample vulnerable endpoint. Since the URLs for the lab sessions expire frequently, the URL in the tutorial will change across some screenshots. This can be ignored.
- HTTP Request Smuggler by James Kettle (currently v.1.04). This is available through the BApp store in the “Extender” tab of Burp Suite Professional.
- Flow by Marcin Woloszyn (currently v.1.24), also accessible through the BApp Store. This extension shows the individual requests made by the request smuggler but is not required for testing.
- The Burp Importer extension created by Smeege available on Github. The .py file from this project must be added through the “Extensions” sub tab under the “Extender” tab. This is useful for importing many URLs into scope at once. We include it here for testers that may need to test many URLs, but it is not required for testing.
- Go to the “Extender” tab and click on the “Extensions” sub tab. Load “HTTP Request Smuggler”, “Flow”, and “Burp Importer” by clicking the checkbox in the “Loaded” column.
- Click on the “Burp Importer” tab. Add the vulnerable URL(s) you want to test to the URL List section. This should be the full URL, including the HTTP or HTTPS protocol. If multiple URLs need to be tested, add them here as well.
- Click the “RUN” button in the “Burp Importer” extension. This will add the URL(s) to scope.
- Click on “Target” and the sub tab “Site map”. If the URL does not appear in the site map, click on the filter and set it to show all items.
- Right click on the URL and select “Launch Smuggle probe”.
- In the Attack Config window that appears, set the timeout to 3 (seconds).
- Click OK and navigate to the “Flow” extension tab to see the requests the probe is sending. They are listed as originating from the “Extender” tool. Notice that the probe sends a variety of requests that are slightly different.
- To see all requests being sent by the probe, including those that have not been completed or have timed out, click the checkbox to the right of the filter and select “Include incomplete requests”.
- Click on the “Dashboard” tab to see what the probe has found. Check if any HTTP request smuggling issues have been flagged. If no HTTP Request Smuggling issues are flagged, wait for requests to stop appearing in Flow, which indicates that the probe has finished running, and re-check the Issue activity list. If none appear, the front-end and back-end servers are not susceptible to being desynchronized. Consequently, they are not vulnerable to request smuggling using HTTP desynchronization, which requires desynchronization to be possible
- To manually verify a finding, click on one of the issues and click on the “Request 2” tab. Notice that the content length header is set to the value 11. Send “Request 2” to the Repeater by right clicking on the text field with the request content and clicking “Send to Repeater”.
- Open the “Repeater” options and uncheck the “Update Content-Length” option. If this option is checked, “Repeater” will update the Content-Length header with what it should be for a non-malicious request. We do not want content length to be updated when testing for this vulnerability.
- Click on the “Repeater” tab and click “Send” to resend the request. Burp Suite should receive a response within a second or two.
- Edit the content length to be 5 instead of 11. Resend the request. If the request takes several seconds to receive a response or does not receive one at all, it usually can be concluded that the front-end has been desynchronized from the back-end. In some cases, a server will drop the request as a protection against this attack, so this cannot conclusively show desynchronization on all server configurations.
Confirming the Vulnerability – Content-Length Transfer Encoding (CL.TE) Version
In order to confirm that the endpoint is vulnerable, it is necessary to see a request spliced into another one. On servers that give each user a unique and separately handled connection, it is not possible to smuggle a request because the attacker’s requests are not read in the same connection as the user’s. Thus, there is no chance of poisoning the requests that the server is processing. However, when the request streams from multiple clients are combined, an HTTP Desync Request Smuggling Attack may be possible.
Burp Suite has options to generate a Proof of Concept attack that can be used to confirm the vulnerability. These are prefixed by “poc:” and can be seen in the step 6 screenshot. We recommend the using these in addition to the method described below.
- Turbo Intruder by James Kettle and PortSwigger Web Security (currently v.1.0.16). This is available through the BApp store in the “Extender” tab of Burp Suite Professional.
- Go to the “Extender” tab and click on the “Extensions” sub tab. Load “Turbo Intruder” by clicking the checkbox in the “Loaded” column.
- In order to determine what type of HTTP response will return from an HTTP request that is impacted by HTTP Desync, it is helpful to modify an existing request to see if appending a character to the beginning will yield a different HTTP response code or body. For example, we can check if prepending a “G” to the request causes a different response from the back-end than making the request without the “G”. Attempt this in “Repeater” with the request sent during step 10 of the Identifying Back-end to Front-end Desynchronization section.
- Check if there is a different response from the request with the “G” and the one without. The PortSwigger labs example yields both a different HTTP status code and response body as shown below.
Now that we know a “G” at the beginning results in a different response, we can attempt to get a “G” at the front of a request and look for the 403 Forbidden HTTP response caused by the request beginning with “GPOST” instead of the 400 Bad Request HTTP response.
- Navigate to the “Request 3” tab for any of the HTTP Request Smuggling issues flagged. Right click on the text field and select “Smuggle attack (CL.TE)” from the menu.
Turbo Intruder shows a script that can be edited to tune the attack. Edit the prefix to be “G” or whatever characters were found to change the request when prepended to it. When testing a service with a high volume of traffic, we recommend adding additional concurrent connections. It may also be desirable to edit the loop that enqueues more requests that mimic what the victim of this attack would be sending to the server.
- Look for a 403, or the response that indicates the request is prepended with a “G”.
Notice the “Unrecognized method GPOST” string. This confirms that the servers are vulnerable to request smuggling.
Use HTTP/2 to facilitate back-end communication
HTTP/2 uses a framed structure that removes ambiguity regarding where HTTP packets end. With HTTP/2, it is no longer necessary to include either a Content-Length header or Transfer-Encoding header; in fact, HTTP/2 explicitly forbids the use of chunked transfer encoding.
Ensure all web servers run the same web server software and configuration
Since HTTP request smuggling is tied to a discrepancy in the HTTP protocol between the front-end and back-end servers, ensuring that all web servers share the same software and configuration inherently resolves this issue.
Do not reuse back-end connections
HTTP request smuggling relies on the multiplexing of multiple back-end connections. Smuggled packets are processed by the back-end server in conjunction with legitimate packets to trigger unwanted behavior. If each request is sent over a separate connection, smuggled malicious requests would no longer be effective.
For further reading on remediations, I recommend referring to the Defence section of James Kettle’s article.