Subdomain Takeover: Identifying Providers

Recently, I have come across an interesting list of domain suffixes used by cloud providers which are vulnerable to subdomain takeover. Although the list is pretty accurate, it is still a raw list that needs to be further processed. In this post, I will explain how to process this list correctly and how to identify new vulnerable cloud services using simple methods.

Architecture

Firstly, let's recap and begin by explaining how the usual cloud provider becomes vulnerable to subdomain takeover. When people create cloud resources, they want them to be accessible through their domain. After registering, for instance, a new Heroku app, the engine will give you subdomain in form APP_NAME.herokudns.com. Heroku recognizes that customers want such applications to be exposed through their domain (e.g. herokuapp.example.com) so they provide a way to set custom domain to their cloud resource.

Due to the technical simplicity, such architecture is often achieved through the use of virtual hosting. You can see the basic idea on the following diagram:

The reason why virtual hosting is preferred is that providers like Heroku don't want to dedicate the whole instance to one application. This also means having dedicated IP address (A record) for each application on *.herokudns.com. It is easier for them to hide the content behind a couple of load balancers and let them decide what content to return based on HTTP Host header. You can confirm this by resolving two different *.herokudns.com domains and comparing the returned A records. They will be the same.

After the HTTP request arrives to load balancer, it determines what content to return based on HTTP Host header assignment:

Custom domains provide a little problem in this architecture. We need to provide the name of custom domain beforehand, so the load balancer knows to which domain it corresponds to when the request arrives. This is the whole problem of subdomain takeover: Having CNAME set to cloud provider domain, but not setting this custom domain in your cloud provider portal.

Some cloud services that use virtual hosting setup:

Amazon S3

Heroku

Shopify

Readme.io

...

On the other hand, there are still some cloud providers that don't rely on virtual hosting but simply creates a dedicated instance (and thus IP address) for each cloud resource. We don't rely on Host header, and the target instance thus accepts any HTTP Host header provided. In other terms, this means that we don't need to specify our custom domain beforehand. Any domain with correct CNAME record will work. The prominent cloud provider in this category is Microsoft Azure.

Verification

Based on this explanation, we can divide the cloud providers into two categories:

As we know from the previous post, subdomain takeover monitoring is a continuous process. We should aim for creating the automation that provides a high success rate in finding potential takeovers. My approach is to create so-called signatures that technically explain each vulnerable cloud service, like so:

Formats — List that describes various formats of domains that the cloud provider uses. These domains are then used in CNAME records.

Responses — What strings are we looking for in HTTP responses of vulnerable domain.

(Optional)Response Codes — What HTTP response codes are we looking for in vulnerable domain.

These signatures are then used by a scanner that takes a list of domain names for verification and checks their HTTP responses against this signature list (this process was explained in the previous post). Indeed, Ghost is not the only vulnerable cloud provider out there. The next section describes how to identify whether the provider is vulnerable and how to write such signatures correctly.

Virtual hosting oriented

This is the majority of cloud providers out there. A common theme across these providers is the fact that they tend to respond with a predefined error page for HTTP Host header they don't recognize. Imagine this: You request a Heroku application via some *.herokudns.com, but you set the HTTP Host header to a value that is not set in Heroku portal. As I explained before, Heroku has no way of knowing to which application does this domain name relate to, unless explicitly specified in Heroku app settings. So how does Heroku respond to such request?

Now that we know the motivation behind these error messages let's look on how to create a signature. I always like to have fresh FDNS dataset handy during this task. If I want to check whether some provider is vulnerable, this is my usual workflow:

Identify what domains they use. This can be simply checked using Google or creating the cloud resource on your own. Usually query like <cloud provider name> custom domain will do the job. For Heroku, it is *.herokudns.com and sometimes *.herokuapp.com. Documentation can be found here. The Format part of the signature is now done.

Grep some CNAMEs of such domain from FDNS: zcat fdns.gz | grep cname | grep herokudns.com. You need at least three domains.

Do DNS (A) resolution for these three domains. If the A records match, you have confirmed virtual hosting setup.

Now it is time to identify what the error page looks like. This can be simply done by creating an HTTP request and forging Host header to something non-existing, like so: http GET http://<something>.herokudns.com Host:totallynonexistingdomainhere.com.

From the response, identify some unique strings that are used as error messages. Responses part of the signature is now done.

Now it's time to finish the signature with Name which is trivial.

With that, you are pretty much done. What I also like to do is to register the free account in the cloud provider I am testing and go through the whole workflow of setting the custom domain name. In some cases, the cloud provider is doing domain verification (e.g., Squarespace) so the takeover is not possible whatsoever. In other cases, they require you to have exact CNAME set in your DNS records which are not always possible.

This virtual hosting setup and technique are actually what Domain Fronting is all about.

Non-virtual hosting oriented

This category is pretty simple to check. When following the workflow described above, point #3 is what decides between VHO and NVHO. If you see that the A records of this domain don't match, there is a high chance that the provider is not using virtual hosting. Fortunately, checking these instances is very simple, all you need to do is check, whether the provider generated domain responds with NXDOMAIN or not. There is no need to write full signatures for NVHO providers; they should be check separately.

Microsoft Azure is the best example of NVHO provider. They use several domains for their services: