Cognito User Pools
Basic Information
A user pool is a user directory in Amazon Cognito. With a user pool, your users can sign in to your web or mobile app through Amazon Cognito, or federate through a third-party identity provider (IdP). Whether your users sign in directly or through a third party, all members of the user pool have a directory profile that you can access through an SDK.
User pools provide:
Sign-up and sign-in services.
A built-in, customizable web UI to sign in users.
Social sign-in with Facebook, Google, Login with Amazon, and Sign in with Apple, and through SAML and OIDC identity providers from your user pool.
User directory management and user profiles.
Security features such as multi-factor authentication (MFA), checks for compromised credentials, account takeover protection, and phone and email verification.
Customized workflows and user migration through AWS Lambda triggers.
Source code of applications will usually also contain the user pool ID and the client application ID, (and some times the application secret?) which are needed for a user to login to a Cognito User Pool.
Potential attacks
Registration: By default a user can register himself, so he could create a user for himself.
User enumeration: The registration functionality can be used to find usernames that already exists. This information can be useful for the brute-force attack.
Login brute-force: In the Authentication section you have all the methods that a user have to login, you could try to brute-force them find valid credentials.
Tools for pentesting
Pacu, now includes the
cognito__enum
andcognito__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. For installation instructions see the main Pacu page.
Cognito Scanner is a CLI tool in python that implements different attacks on Cognito including unwanted account creation and account oracle. Check this link for more info.
CognitoAttributeEnum: This script allows to enumerate valid attributes for users.
Registration
User Pools allows by default to register new users.
If anyone can register
You might find an error indicating you that you need to provide more details of abut the user:
You can provide the needed details with a JSON such as:
You could use this functionality also to enumerate existing users. This is the error message when a user already exists with that name:
Note in the previous command how the custom attributes start with "custom:". Also know that when registering you cannot create for the user new custom attributes. You can only give value to default attributes (even if they aren't required) and custom attributes specified.
Or just to test if a client id exists. This is the error if the client-id doesn't exist:
If only admin can register users
You will find this error and you own't be able to register or enumerate users:
Verifying Registration
Cognito allows to verify a new user by verifying his email or phone number. Therefore, when creating a user usually you will be required at least the username and password and the email and/or telephone number. Just set one you control so you will receive the code to verify your newly created user account like this:
Even if looks like you can use the same email and phone number, when you need to verify the created user Cognito will complain about using the same info and won't let you verify the account.
Privilege Escalation / Updating Attributes
By default a user can modify the value of his attributes with something like:
Custom attribute privesc
You might find custom attributes being used (such as isAdmin
), as by default you can change the values of your own attributes you might be able to escalate privileges changing the value yourself!
Email/username modification privesc
You can use this to modify the email and phone number of a user, but then, even if the account remains as verified, those attributes are set in unverified status (you need to verify them again).
You won't be able to login with email or phone number until you verify them, but you will be able to login with the username.
Note that even if the email was modified and not verified it will appear in the ID Token inside the email
field and the filed email_verified
will be false, but if the app isn't checking that you might impersonate other users.
Moreover, note that you can put anything inside the name
field just modifying the name attribute. If an app is checking that field for some reason instead of the email
(or any other attribute) you might be able to impersonate other users.
Anyway, if for some reason you changed your email for example to a new one you can access you can confirm the email with the code you received in that email address:
Use phone_number
instead of email
to change/verify a new phone number.
The admin could also enable the option to login with a user preferred username. Note that you won't be able to change this value to any username or preferred_username already being used to impersonate a different user.
Recover/Change Password
It's possible to recover a password just knowing the username (or email or phone is accepted) and having access to it as a code will be sent there:
The response of the server is always going to be positive, like if the username existed. You cannot use this method to enumerate users
With the code you can change the password with:
To change the password you need to know the previous password:
Authentication
A user pool supports different ways to authenticate to it. If you have a username and password there are also different methods supported to login. Moreover, when a user is authenticated in the Pool 3 types of tokens are given: The ID Token, the Access token and the Refresh token.
ID Token: It contains claims about the identity of the authenticated user, such as
name
,email
, andphone_number
. The ID token can also be used to authenticate users to your resource servers or server applications. You must verify the signature of the ID token before you can trust any claims inside the ID token if you use it in external applications.The ID Token is the token that contains the attributes values of the user, even the custom ones.
Access Token: It contains claims about the authenticated user, a list of the user's groups, and a list of scopes. The purpose of the access token is to authorize API operations in the context of the user in the user pool. For example, you can use the access token to grant your user access to add, change, or delete user attributes.
Refresh Token: With refresh tokens you can get new ID Tokens and Access Tokens for the user until the refresh token is invalid. By default, the refresh token expires 30 days after your application user signs into your user pool. When you create an application for your user pool, you can set the application's refresh token expiration to any value between 60 minutes and 10 years.
ADMIN_NO_SRP_AUTH & ADMIN_USER_PASSWORD_AUTH
This is the server side authentication flow:
The server-side app calls the
AdminInitiateAuth
API operation (instead ofInitiateAuth
). This operation requires AWS credentials with permissions that includecognito-idp:AdminInitiateAuth
andcognito-idp:AdminRespondToAuthChallenge
. The operation returns the required authentication parameters.After the server-side app has the authentication parameters, it calls the
AdminRespondToAuthChallenge
API operation. TheAdminRespondToAuthChallenge
API operation only succeeds when you provide AWS credentials.
This method is NOT enabled by default.
To login you need to know:
user pool id
client id
username
password
client secret (only if the app is configured to use a secret)
In order to be able to login with this method that application must allow to login with ALLOW_ADMIN_USER_PASSWORD_AUTH
.
Moreover, to perform this action you need credentials with the permissions**cognito-idp:AdminInitiateAuth
**and cognito-idp:AdminRespondToAuthChallenge
USER_PASSWORD_AUTH
This method is another simple and traditional user & password authentication flow. It's recommended to migrate a traditional authentication method to Cognito and recommended to then disable it and use then ALLOW_USER_SRP_AUTH method instead (as that one never sends the password over the network). This method is NOT enabled by default.
The main difference with the previous auth method inside the code is that you don't need to know the user pool ID and that you don't need extra permissions in the Cognito User Pool.
To login you need to know:
client id
username
password
client secret (only if the app is configured to use a secret)
In order to be able to login with this method that application must allow to login with ALLOW_USER_PASSWORD_AUTH.
USER_SRP_AUTH
This is scenario is similar to the previous one but instead of of sending the password through the network to login a challenge authentication is performed (so no password navigating even encrypted through he net). This method is enabled by default.
To login you need to know:
user pool id
client id
username
password
client secret (only if the app is configured to use a secret)
REFRESH_TOKEN_AUTH & REFRESH_TOKEN
This method is always going to be valid (it cannot be disabled) but you need to have a valid refresh token.
CUSTOM_AUTH
In this case the authentication is going to be performed through the execution of a lambda function.
Extra Security
Advanced Security
By default it's disabled, but if enabled, Cognito could be able to find account takeovers. To minimise the probability you should login from a network inside the same city, using the same user agent (and IP is thats possible).
MFA Remember device
If the user logins from the same device, the MFA might be bypassed, therefore try to login from the same browser with the same metadata (IP?) to try to bypass the MFA protection.
User Pool Groups IAM Roles
It's possible to add users to User Pool groups that are related to one IAM roles. Moreover, users can be assigned to more than 1 group with different IAM roles attached.
Note that even if a group is inside a group with an IAM role attached, in order to be able to access IAM credentials of that group it's needed that the User Pool is trusted by an Identity Pool (and know the details of that Identity Pool).
Another requisite to get the IAM role indicated in the IdToken when a user is authenticated in the User Pool (aws cognito-idp initiate-auth...
) is that the Identity Provider Authentication provider needs indicate that the role must be selected from the token.
The roles a user have access to are inside the IdToken
, and a user can select which role he would like credentials for with the --custom-role-arn
from aws cognito-identity get-credentials-for-identity
.
However, if the default option is the one configured (use default role
), and you try to access a role from the IdToken, you will get error (that's why the previous configuration is needed):
Note that the role assigned to a User Pool Group needs to be accesible by the Identity Provider that trust the User Pool (as the IAM role session credentials are going to be obtained from it).
Last updated