# HSTS Security Research

*I blurred domain names for "attack targets" in this blog post, however because of the very nature of how HSTS pre-loading works, most affected websites can be inferred pretty easily*

**Edit Note**: *Both attacks discussed below, while annoying are medium-low impact in my opinion but they are pretty widespread. I tried reporting one over a BB program and I'm pretty sure the triager just thought I was reporting a missing HSTS header. I can't really be bothered with arguing over severity so feel free to report this if you're fine explaining how this can  be higher impact than just a missing HSTS header.*\
\&#xNAN;*I also edited and reread this blog post a couple of time and wanted to clarify impact here: Forcing a victim domain to be removed from HSTS means they removed the "preload" directive and will end up being removed anyway at some point.*\
\&#xNAN;*Force adding a domain to the preload directive can 100% break non checked subdomains (especially internal domains not available on public DNS) or could break the domain if there is a regression. The impact here is a client-side DOS. Where clients can't access the domain on most modern browsers.*\
\&#xNAN;*Now let's get into it!*

I was reading [this post](https://portswigger.net/research/how-to-turn-security-research-into-profit?ref=warsangs-hobby-blog.ghost.io) from @albinowax on transforming security research into bounty and the paragraph about CORS got me super excited and inspired.

Specifically:

> If research is poorly explained or under-hyped, you can sometimes have major success simply by applying it. For example, [CORS Misconfigurations](https://ejj.io/misconfigured-cors/?ref=warsangs-hobby-blog.ghost.io) missed the infosec hype train, so upon reading it I tried the technique as-is and immediately found a bunch of vulnerabilities with very little effort, leading to deeper research and ultimately [Exploiting CORS Misconfigurations for Bitcoins and Bounties](https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties?ref=warsangs-hobby-blog.ghost.io).

That got me inspired to look for issues around overlooked HTTP headers. Specifically HSTS.

So I started digging on the Mozilla documentation around the [Strict-Transport-Security](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security?ref=warsangs-hobby-blog.ghost.io#preloading_strict_transport_security) header. The part about "preload" caught my eye. Specifically:

> Google maintains [an HSTS preload service](https://hstspreload.org/?ref=warsangs-hobby-blog.ghost.io). By following the guidelines and successfully submitting your domain, you can ensure that browsers will connect to your domain only via secure connections. While the service is hosted by Google, all browsers are using this preload list. However, it is not part of the HSTS specification and should not be treated as official.

I started poking around at [https://hstspreload.org/](https://hstspreload.org/?ref=warsangs-hobby-blog.ghost.io) ; it's actually open sourced on github and is a Google AppEngine hosted website. I started with a manual code review and didn't really find anything. Then tried runnig the code through semgrep but none of the findings seemed exploitable (after a lot of trial and error).\
I then tried to trigger a couple of SSRFs and again, the GAE endpoint does reach-out to arbitrary domains but nothing really exploitable there. I tried hitting internal GCP ips for meta-data etc. but to no avail.

Whoever wrote this site contributes to chromium and without a doubt has much more in-depth understanding of browser security than me so I wasn't really surprised to see that their website wasn't really exploitable.

Reading through the code, I noticed two Python scripts that seem to be run on launch through some form of automation -> [https://github.com/chromium/hstspreload.org/tree/8c863d498916802973bde3c55cebd466f5e215ca/scripts](https://github.com/chromium/hstspreload.org/tree/8c863d498916802973bde3c55cebd466f5e215ca/scripts?ref=warsangs-hobby-blog.ghost.io)

We can confirm the scripts are called at each deployment through the \[makefile]\([https://github.com/chromium/hstspreload.org/blob/master/Makefile#L21](https://github.com/chromium/hstspreload.org/blob/master/Makefile?ref=warsangs-hobby-blog.ghost.io#L21))

<div data-full-width="true"><figure><img src="https://warsangs-hobby-blog.ghost.io/content/images/2022/09/image-1.png" alt="" height="122" width="2000"><figcaption></figcaption></figure></div>

This got me two lists:

* Websites pending removal
* Websites submitted to the preload list

A little bit of info can be found about the preload list here:

From [https://support.openprovider.eu/hc/en-us/articles/360000350268-What-are-HSTS-and-the-HSTS-preload-list-](https://support.openprovider.eu/hc/en-us/articles/360000350268-What-are-HSTS-and-the-HSTS-preload-list-?ref=warsangs-hobby-blog.ghost.io)

> Not only domains can be added to the HSTS preload list, also complete top level domains (domain extensions). If a registry decides to add its extension(s) to the HSTS preload list, every domain registered under that TLD must be served over HTTPS. The first extensions using the HSTS preload list are .bank and .insurance - two extensions that have security as their unique selling point. Google Registry has also added .app and .dev to the HSTS preload list.

So two paths of attack opened up for me:

1. HSTS preload downgrade attack: I can add a domain to the removal list when they never asked to be removed.
2. HSTS Client-side Denial of Service: I can add a domain to the preload list without them asking for it -> If the subdomain clause is in their header, things can get really bad as most modern browsers will now try to force HTTPS on all of these subdomains. If the subdomain doesn't redirect to HTTPS, it now is unavailable in these browsers for ALL users

### Attack1: HSTS preload downgrade attack <a href="#attack1-hsts-preload-downgrade-attack" id="attack1-hsts-preload-downgrade-attack"></a>

For Attack1,  a couple of conditions are required. Mainly, the preload directive must be removed from the top domain's Strict-Transport-Security header. This condition can be verified using the GAE api path /api/v2/removable?domain=X

I wrote a quick Burp Turbo intruder script and started submitting domains.

The script for the HSTS preload downgrade attack is:\\

```
# Find more example scripts at https://github.com/PortSwigger/turbo-intruder/blob/master/resources/examples/default.py
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=8,
                           requestsPerConnection=100,
                           pipeline=False,
                           timeout=4,
                           maxRetriesPerRequest=3
                           )

    for word in open('C:\\Users\\Someone\\Desktop\\final.txt'):
        engine.queue(target.req, word.rstrip())


def handleResponse(req, interesting):
    if interesting:
        table.add(req)
```

Turbo Intruder output:

<div data-full-width="true"><figure><img src="https://warsangs-hobby-blog.ghost.io/content/images/2023/06/image-11.png" alt="" height="1288" width="2000"><figcaption></figcaption></figure></div>

This approach did not give me any successfull results for Attack1. Basically, all websites in there that were eligible for removal from HSTS were already in pending-removal status (also, they did not have a bug-bounty program). Removing preloadable from HSTS header will trigger your website being removed from the list at some point anyway so this is a pretty low finding imo.

### Attack2: HSTS Client-side Denial of Service <a href="#attack2-hsts-client-side-denial-of-service" id="attack2-hsts-client-side-denial-of-service"></a>

For the second attack, I just replaced the "removable" API endpoint with "preload" one in Burp intruder and ran all my BugBounty parent domains.

Quick bash foo to get the top domains from the Project disovery list [https://raw.githubusercontent.com/projectdiscovery/public-bugbounty-programs/master/chaos-bugbounty-list.json](https://raw.githubusercontent.com/projectdiscovery/public-bugbounty-programs/master/chaos-bugbounty-list.json?ref=warsangs-hobby-blog.ghost.io) :

```
 wget https://raw.githubusercontent.com/projectdiscovery/public-bugbounty-programs/master/chaos-bugbounty-list.json > hstsattack2.txt
 gron hstsattack2.txt | grep "domains" | cut -d'"' -f2 | grep -v '=' | sort -u > toplevelbbdomains.txt
```

And we now feed this to Intruder

Working victim for HSTS preload Denial of Service:

<div data-full-width="true"><figure><img src="https://warsangs-hobby-blog.ghost.io/content/images/2023/06/image-12.png" alt="" height="1257" width="2000"><figcaption></figcaption></figure></div>

[hstspreload/domain.go at ec3c2b47eaf181fb39e013afa2252586dbc1049f · chromium/hstspreload🔒🔍 A Go package to scan sites against requirements for Chromium-maintained HSTS preload list. - hstspreload/domain.go at ec3c2b47eaf181fb39e013afa2252586dbc1049f · chromium/hstspreloadchromium](https://github.com/chromium/hstspreload/blob/ec3c2b47eaf181fb39e013afa2252586dbc1049f/domain.go?ref=warsangs-hobby-blog.ghost.io#L110)

This only checks WWW domains and not that all **subdomains** are over HTTPS.

And now we can cause a client-side denial of service on all non HTTPS enabled sub-domain on all modern browsers. This also breaks some HTTP to HTTPS redirects if done through JS etc. This will be hard for the victim company to pinpoint and they'll have a hard time to troubleshoot the issue as their customers will be prevented from accessing the website while all their infrastructure will be working as intended. The mitigation/fix is to either disable the preload directive or the subdomain directive in the Strict-Transport-Security header or to disable the subdomain directive.

If you add a preload and subdomain directive when HTTPS isn't enabled everywhere, you as a site owner miss-configured the header. However, it seems like this could be an easy mistake to make which could have a devastating impact for any business. Even if your http domains 301 redirect to https, once HSTS preloading is enabled and your domain is added to the preload list, the redirect will not work.

Ultimately, I think the chromium team should probably enforce stronger domain ownership verification upon submission to this list as many high profile browsers depend on that list and millions of users could potentially be impacted at scale. Something like checking a TXT record entry at a DNS level similar to what Let'sEncrypt and CloudFront do.

Untill the above recommendation is implemented, there is still likely a lot of vulnerable bounty elligible domains out there. I only do bug bounty casually and have a very poor/small recon list. Moreover, there's another avenue of attack where an attacker that discovers a CDN Cache Poisoning attack where they can reflect an attacker controlled header could reflect the Strict-Transport-Security header with the preload and subdomains directives and have that cached. Once this entry is cached, they can register the domain to escalate the cache poisoning attack to an HSTS client-side DOS for the subdomains of this domain.

### Further thoughts <a href="#further-thoughts" id="further-thoughts"></a>

One extra idea that came to mind is that if you're able to perform DNS takeover on any domain in the list or not in the list, you should be able to trick the HSTS list tool into thinking you're ready to be added/removed to the preload list. Now you're redirecting victims to your website and when/if they take their dns back, they'll still need to fix serve the right HSTS headers before resuming proper functioning/operations. Removing a website from the HSTS preload list can take months according to the list page (as you're waiting for a new browser version to be shipped). I tried to find domains in a bugbounty scope that were affected by dns takeover to try and report+escalate impact but couldn't find any in my list.

Another thing I recently learnt is Windows ships with a dlll containing HSTS enabled domains; I don't know how this is updated but if it relies on the chromium list, this means you could impact clients at the OS level as well.

### &#x20;<a href="#appendix-report-blurb" id="appendix-report-blurb"></a>
