Enumerating Cognito Clients Exposed to the Internet

By Shahnoor Kiani on 11th October 2023

 

In this post, I will describe the process carried out when looking for means of exploiting AWS Cognito at scale. It aims to be an example for those interested in researching how to exploit any cloud service, as the process has been written to be as general as possible. It begins with an overview of Cognito and the methodology used to approach the project. It follows with a description of the process of finding potential misconfigurations in the service, enumerating instances of the service and confirming misconfigurations. It concludes with takeaways from the project which may be of use for anyone interested in researching how to exploit cloud services at scale. 

Basics

Before describing the methodology of the project, some points need to be understood about the Cognito service. Deep knowledge of this specific service is not important, but it is important to understand the following:

  • It is an identity provider (IdP) that can be integrated with other identity providers as a means of adding single sign on (SSO) to your application. 
  • It also comes with other features such as the ability to add custom attributes to users who are registered in the IdP and to configure a role which can be assumed by users who authenticate with the IdP.

If you are interested, read more at https://cloudsec.wiki [1].

Methodology

This section details the methodology used to find means of attacking Cognito at scale. I identified three requirements to exploit this service:

  • Finding ways Cognito can be misconfigured by configuring a test instance. 
  • A means of enumerating active instances of this service on the internet. 
  • A means of identifying the misconfigurations within the found instances of the service

This property is not unique to Cognito; when attacking other services at scale which are cloud hosted, you may find a similar pattern.

Finding misconfigurations

This section describes the process of fulfilling the first requirement for the task, namely identifying means of misconfiguring Cognito.

A mix of local testing and researching other blog posts [2] allowed me to find several misconfigurations which had sufficient impact. I identified misconfigurations which can lead to account takeover vectors, access to the underlying AWS environment the service it’s hosted on and privilege escalation in the application which uses Cognito as an IdP. This was done through a combination of public bug bounty writeups and local testing of a Cognito instance I set up myself.

Enumerating instances of the service

This section details how instances of Cognito were enumerated. It was an opportunity to find a creative solution for the problem as there is little online on how to enumerate Cognito instances. It concludes with key takeaways on how to approach attacking other cloud services.

These are identified by a client id, which is equally as valuable as finding a Cognito instance to attack. Scraping the web looking for login pages powered by Cognito is easy since they are often a subdomain of *.amazoncognito.com; however, finding a Cognito domain does not necessarily give me its Cognito client id. I needed a way of linking these login pages to their respective client ids.

In order to do this, I considered the context in which these client ids appear when using the service normally. Developers typically send users a link to their login page via a backlink, which is a link to a webpage appearing from another website [3]. These backlinks need to contain the client id for the Cognito login page to work, and research into backlinks lead me to discover SEO websites. SEO websites are SaaS offerings that aim to offer advice to website owners to improve their search rankings for various search engines. One metric they use are backlinks, and most offer a tool to identify backlinks to your webpage.

The websites claimed to identify around 11 million backlinks to the *.amazoncognito.com domain, but most severely limited the number of results I could retrieve. Furthermore, a lot of the results were duplicated, but despite this the technique yielded 146 unique active instances of Cognito client ids I could test. When combined with katana [4] and waybackurls [5], I got a total of 959 unique client ids. This was a far cry from the 11 million I had, but it sufficed as a proof of concept. With better SEO tooling and a more comprehensive scan, I could have gotten more client ids from this technique. Furthermore, scanning Javascript files in websites is a popular method of enumerating instances which could have produced more client ids.

Confirming a misconfiguration in the service

This section outlines the process for finding a scalable method of determining if a particular instance was misconfigured. It begins by describing the process of confirming whether a client id is active, and then shows how I would confirm if the Cognito instance vulnerable.

What I needed was an *oracle*, something that would take a client id and tell me if the instance was active. From reading the AWS CLI documentation, I found the following AWS CLI command told me a lot of information about the client id:

aws cognito-idp initiate-auth --client-id <client ID> --auth-flow USER_PASSWORD_AUTH --auth-parameters USERNAME=random_user,PASSWORD=random_password

aws cognito-idp initiate-auth --client-id <client ID> --auth-flow USER_PASSWORD_AUTH --auth-parameters USERNAME=random_user,PASSWORD=random_password 

If the client was not active, it would respond with an error complaining about the client id:

An error occurred (ResourceNotFoundException) when calling the InitiateAuth operation: User pool client [CLIENT-ID] does not exist.

If the USER_PASSWORD_AUTH authorisation flow was disabled, it would produce an error claiming so. I was able to call this programmatically for each client ID I had scanned and found that there were 282 unique client ids working out of the 959 retrieved previously.

For each misconfiguration, a local Cognito instance was used to establish a process for scanning for them This involved creating both a misconfigured and securely configured instance of Cognito, and comparing the output of various AWS CLI calls to see what information I could get. However, when working on assets which you do not have explicit permission to test, it is important to first consider the risk when performing them. Scans can be categorised into the following:

Category
Description 

Passive

 

The scan does not involve interacting with the application directly, so it cannot be directly attributed to us. 

 

Active

 

The scan is similar to typical usage of the application from the perspective of the target.

 

Intrusive

 

The scan acts beyond typical usage of the application.

 

 

In this case, all of the scans ranged from active to intrusive. Unfortunately, the scans required to confirm the vulnerabilities were intrusive so I was not able to run them against internet wide assets. However, it was proven during local testing that the exploitation of these misconfigurations could lead to account takeovers or gaining a foothold into the AWS environment, which could have meant the exploitation of 282 public Cognito instances.

Takeaways

This section summarises the methodology behind the project. It also lists key takeaways from the project which can be applied when researching other means of exploiting cloud services.

Scanning for misconfigured cloud assets can be split into three steps. The first involves building a test instance to find means of misconfiguring it. Afterwards, a method for enumerating active instances of the asset needs to be determined. Finally, a means of confirming a given instance is misconfigured must be found. It is important to consider if these methods are passive, active or intrusive and to avoid performing intrusive actions on internet wide assets. 

The project gave me an insight into the benefits and challenges people face if they choose to research means of exploiting cloud services. The shared responsibility model means there is a trust boundary between cloud service engineers and AWS. This is because the engineers trust AWS to secure certain parts of their system, but understand they are responsible for securing other parts of it. However, under the PaaS model this boundary can be particularly blurry. It is reasonable for a developer to assume that if they create a page without a registration feature, that people cannot register new users. However, cloud services introduce a new challenge for developers as there is another attack surface to consider. If that same developer uses Cognito to create the login page, they may not realise that an attacker can use the AWS Cognito API to create a new user. As an attacker, understanding where this boundary lies, and which boundaries may be misplaced by developers is a key skill to exploiting cloud services.

Furthermore, due to the isomorphic nature of cloud, attackers can programmatically scan for these discrepancies at scale. This means research into how a cloud service can be misconfigured alongside means of enumerating that service can often lead to exploiting hundreds of instances in a single script, perhaps even more.

References

1. Kiani, S. (2023). Cognito. Retrieved from https://www.secwiki.cloud/aws/services/Cognito
2. Lauritz, H. (2021). Retrieved from https://security.lauritz-holtmann.de/advisories/flickr-account-takeover/
3. Backlink.com. (2023). Retrieved from https://backlinko.com/hub/seo/backlinks
4. Projectdiscovery. (n.d.). Retrieved from https://github.com/projectdiscovery/katana
5. Tomnomnom. (n.d.). Retrieved from https://github.com/tomnomnom/waybackurls