TL;DR, There used to be a bug in Internet Explorer allowing attackers to force victims to send requests with malformed Host headers. File Descriptor used it to steal GitHub OAuth tokens, and we used it to confuse Heroku and Fastly’s host routing to make them serve our content on their customers’ domains. Fastly and Heroku have since then patched the issue on their side.
Internet Explorer/Edge malformed Host-header
The Internet Explorer/Edge bug worked like this. Doing the following redirect (from a malicious link):
HTTP/1.1 307 Redirect Location: https://www.drupal.org%2f.to.to
Would result in Internet Explorer/Edge sending this request to www.drupal.org
:
GET /.to.toto/ HTTP/1.1 Host: www.drupal.org/.to.to
Heroku/Fastly
Now, both Heroku and Fastly had lax parsing of the Host
header. This meant that even though the /
-character was inside the header, they would still think the host was a subdomain of .to.to
. This made it possible to claim *.to.to
as your own domain on the services, point all subdomains of the .to.to
-domain to malicious content and then use the Internet Explorer/Edge bug to serve the malicious content on any domain bound to Heroku/Fastly.
PoC
The flow looked like this:
- You created a malicious redirect link and sent it to a victim.
- The redirect link would create the malformed Host header in Internet Explorer/Edge. The resolve would still be made to the original domain (in our case
www.drupal.org
) which was pointing to Fastly/Heroku. - Fastly/Heroku would parse the Host-header and resolve the wrong domain, in our case the wildcard
*.to.to
. - Fastly/Heroku would then return data from our domain, even though the domain resolved by the browser was still the owned by the customer of Fastly/Heroku.
To see this more clear, look at the following domain:
$ host www.drupal.org www.drupal.org is an alias for j.global-ssl.fastly.net.
It’s pointing to Fastly.
We then made the following test request using cURL:
curl -H 'Host: www.drupal.org/.to.to' https://www.drupal.org/
And got the following response:
<script>alert(document.domain)</script>
This is because we claimed *.to.to
in Fastly, serving our simple app providing this content as a proof of concept.
We now send the following link to the victim:
https://avlidienbrunn.se/redirect.php?redirect=https://www.drupal.org%252f.to.to
This would give us the following redirect response:
HTTP/1.1 307 Redirect Location: https://www.drupal.org%2f.to.to
Which would make Internet Explorer/Edge send the following Host
header:
Host: www.drupal.org/.to.to
Instead of invalidating this request, both services would actually handle this host header as a subdomain of *.to.to
, serving the content we controlled:
This meant that the combination of the lax host parsing and the Internet Explorer/Edge bug allowed us to us spoof content on all customers of these two services. We could serve any content we wanted or even make authenticated requests that would be allowed under the Same-Origin Policy (SOP) to hijack the current user.
Microsoft was previously informed twice about the Host header injection, they fixed it once, but regression made it come back again.
Affected
Basically all customers of both Heroku and Fastly that did not use any additional proxies in between were vulnerable. The only browsers that allowed us to do this were Internet Explorer and Edge. During the time, Safari had similar issues, but the origin was emptied, so the SOP restricted us from doing additional requests. Even though content extraction worked in Safari, the resolved page only had our content, which made the Safari bug pointless in this case.
Timeline
- June 16 – Reported to both Fastly and Heroku
- June 21 – Triaged by Fastly
- June 28 – Patch is deployed by Fastly
- June 30 – Triaged by Heroku
- July 7 – Additions to the patch added
- September X – Host header injection in Internet Explorer/Edge patched by Microsoft
- October 20 – Final patches added by Heroku