In this blog, Sunil Yadav, our lead trainer for “Advanced Web Hacking” training class, will discuss a case study of AWS account takeover via misconfigured AWS Cognito.
- The application under test only had a login page and no sign up feature exposed.
- AWS cognito misconfigured to allow sign up of new user
- Sign up and login to obtain AWS temporary token for authenticated Identities
- AWS token has access to Lambda functions which is leveraged to elevate access
Amazon Cognito manages user authentication and authorization (RBAC). User pools allow sign-in and sign up functionality. Identity pools (federated identities) allows authenticated and unauthenticated users to access AWS resources using temporary credentials
In short, the User Pool stores all users, and Identity Pool enables those users to access AWS services.
The Figure given below shows an AWS Cognito authentication and authorization flow. The user authenticates against a user pool, and after successful authentication, the user pool assigns 3 JWT tokens (ID, Access, and Refresh) to the user. The ID JWT is passed to the identity pool in order to receive temporary AWS credentials with roles assigned to the identity provider.
During a recent pentest, we stumbled upon a login page. It had no other authentication related functionality exposed such as forgot password or sign up page.
Amazon Cognito has authenticated and unauthenticated mode to generate AWS temporary credentials for users. Unauthenticated access rights can be obtained by anyone using a specific API call. So we tried to gain access to AWS credentials by using unauthenticated identities, but the access to unauthenticated identities was disabled.
An interesting case study in the area of exposing AWS services to unauthenticated identities is listed here: https://andresriancho.com/wp-content/uploads/2019/06/whitepaper-internet-scale-analysis-of-aws-cognito-security.pdf.
Moving forward, we focused on identifying the features available to us. We identified that the application exposed some functionalities unintentionally via AWS Cognito misconfiguration. Using the AppClientId, we created a user in Amazon Cognito user pool. The confirmation email was sent to the specified email along with the confirmation code.
We determined that the user account can be confirmed from the token received on the registered email by using the ConfirmSignUp API.
Now, when we logged into the application with the newly registered account, the app responded with an error, “user is not part of any groups". So, the app allowed access based on the group privileges granted within the application.
We realised that, the application essentially validated a newly created user and returned access tokens but did not allow the user to access any page as the user was not part of any groups that had access to the application.
Now that we had authenticated access and ID token. These values could be used to generate temporary AWS credentials for authenticated identities.
Now we can use AWS Command Line Interface(CLI) to interact with the AWS services:
Using the “aws sts get-caller-identity” command, it was identified that the token was working fine.
By leveraging our Cloud service enumeration scripts it was observed that the AWS token had full permissions for the AWS Lambda functions. This allowed us to explore the AWS Lambda configuration of the client. We began with viewing the list of Lambda functions:
aws lambda list-functions
We discovered that one of the Lambda function (RotateAccessKeys-CIS) had overly permissive IAM policies.
aws iam list-attached-role-policies --role-name IAM-CIS
We decided to modify the Lambda function code (RotateAccessKeys-CIS) such that it worked as required but additionally executed a command that allowed reading of AWS credentials from Environment variables.
Let’s see how we modified the said function.
We downloaded the Lambda function code from the code location as highlighted
aws lambda get-function --function-name RotateAccessKeys-CIS --query 'Code.Location'
The ‘lambda_handler’ function in the downloaded code was modified to print environment variables.
Further, we created a ZIP file that contained the modified code so that it now executed the modified Lambda function once the package was uploaded and invoked.
The Lambda function ‘RotateAccessKeys-CIS’ was now updated.
aws lambda update-function-code --function-name RotateAccessKeys-CIS --zip-file fileb:///root//lambda_function.zip
Once the Lambda function code was updated as intended, we invoked it using the below mentioned command. This command invoked the function and printed the Log on the screen that contained AWS temporary credentials.
aws lambda invoke --function-name RotateAccessKeys-CIS out --log-type Tail --query 'LogResult' --output text | base64 -d
We repeated the same steps and identified a set of temporary credentials which were highly permissive with full IAM Access.
Next, we configured our AWS CLI using the new AWS credentials to create a new user ‘nirahua’ and attached the AWS managed policy named AdministratorAccess to the user using the following commands.
aws iam create-user --user-name nirahua
aws iam create-login-profile --user-name nirahua --password s8iUzu******
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --user-name nirahua
And as you can see, we successfully logged in as an administrator via AWS console with the newly created user.
- Disable Signup on AWS Cognito if not required
- Never assign privileges beyond the minimum necessary while configuring the AWS Cognito for authenticated and unauthenticated identities.
- Use advanced security features for Amazon Cognito to protect application users from unauthorized access.