Overview
In AWS, sts:AssumeRole is an action within AWS’s Security Token Service that allows existing IAM principals to access AWS resources to which they may not already have access. For example, Role A can assume Role B and then use Role B’s privileges to access AWS resources. Common use cases include assuming a role within the same AWS Account, gaining cross-account access to interact with workloads in different AWS Accounts, or providing centralized access to security or operations teams.
Multiple sts:AssumeRole calls can be linked to chain roles. For example, if Role A can assume Role B and Role B can assume Role C, someone with access to Role A could gain the permissions to Role C by role chaining sts:AssumeRole calls together. This is a privilege escalation path that malicious actors can abuse and that security teams frequently overlook.
In this blog post, we will be discussing one specific role chaining path that begins with an IAM User with MFA. While researching this privilege escalation path, Praetorian noted inconsistencies with documentation and permissions related to sts:GetSessionToken and Policy Simulator and reported those to AWS Security. Due to the inconsistencies with AWS documentation and Policy Simulator, it is possible for AWS customers to misconfigure security controls and overlook AWS IAM users with privilege escalation paths potentially gained via role chaining.
Timeline
- May 2022: Praetorian reported these issues to AWS Security.
- May 2022: AWS updated documentation to clarify sts:GetSessionToken.
- Planned: AWS is planning to update IAM Policy Simulator for both sts:GetSessionToken and sts:GetCallerIdentity.
Technical Walkthrough
AWS & Multi-Factor Authentication
AWS recommends configuring multi-factor authentication (MFA) to help protect AWS resources. In AWS, security teams can enable MFA for IAM Users or the AWS account root user.
Figure 1: MFA prompt within AWS.
Validating MFA on an IAM User
AWS IAM policies support multiple MFA conditions including the following:
- aws:MultiFactorAuthPresent for existence
- aws:MultiFactorAuthAge for duration
These MFA Conditions validate the presence of MFA on AWS API and CLI actions. The conditions apply to a couple places in this role chaining example:
- Directly on the IAM User’s permissions. An example IAM policy snippet is shown in Figure 2.
Figure 2: Source code requiring MFA on a user’s permissions.
- On a role’s trust policy, checked during the sts:AssumeRole call. For an example trust policy, see Figure 3.
Figure 3: A role’s trust policy requiring MFA.
Temporary Security Credentials vs Long-Term Credentials
Authenticating to AWS can result in temporary security credentials or long-term credentials. The type of credential used in AWS has an impact on MFA. AWS has designed MFA protection to only apply to temporary security credentials. Additionally, MFA-protected API access cannot be used either with AWS account root user credentials or U2F security keys.
With IAM Users, the IAM Access Key and Secret Access Key are long-term credentials and do not have the aws:MultiFactorAuthPresent condition key available. However, while using the AWS Management Console AWS generates temporary security credentials for an IAM User and thus the aws:MultiFactorAuthPresent condition key is available. However, when using the AWS CLI or API in conjunction with an IAM Access Key and Secret Access Key, the aws:MultiFactorAuthPresent condition key is not present in the request due to Access Keys and Secret Access Keys being long-term credentials. In that scenario the user must make another call to generate temporary credentials.
Acquiring Temporary Security Credentials for an IAM User
In AWS, there are two distinct methods for generating temporary security credentials.
- sts:GetSessionToken
Figure 4: Generating temporary security credentials via sts:GetSessionToken.
Note: stsGetSessionToken is similar to sts:GetCallerIdentity where the call cannot be controlled by IAM policies. This means that sts:GetSessionToken cannot be denied by an explicit deny and that an IAM user will always be able to call sts:GetSessionToken provided the call is properly formed.
- sts:AssumeRole
Figure 5: Generating temporary security credentials via sts:AssumeRole.
Thus, if MFA has been setup for the IAM User, then we can chain roles to an IAM User with MFA by one of the following two processes:
- Use the User’s Access Key and Secret Access Key.
- Call sts:AssumeRole into Role B with the corresponding MFA device and code.
- Use the credentials from the above command to sts:AssumeRole into Role C.
or
- Use the User’s Access Key and Secret Access Key.
- Call sts:GetSessionToken with the corresponding MFA device and code.
- Use the credentials from the above command to sts:AssumeRole into Role B.
- Use the credentials from the above command to sts:AssumeRole into Role C.
Inconsistencies
AWS Documentation
Praetorian noticed inconsistent documentation regarding the usage and permission model of sts:GetSessionToken across AWS documentation (as seen in Figure 6). This could lead to application teams misunderstanding and misconfiguring sts:GetSessionToken permissions. In one scenario, Praetorian observed a team unaware of the ability of a MFA-enabled IAM User to chain roles together via CLI and of how sts:GetSessionToken could not be denied via IAM Policy.
Figure 6: Former AWS reference material for sts:GetSessionToken, which AWS has since clarified following our discussions.
One example of clear documentation is the note regarding how IAM Policies interact with the sts:GetCallerIdentity, another sts call that cannot be controlled by IAM Policies (as seen in Figure 7).
Figure 7: AWS reference material for sts:GetCallerIdentity.
Praetorian worked with AWS to add a similar note to the sts:GetSessionToken documentation (as seen in Figure 8).
Figure 8: Current AWS reference material for sts:GetSessionToken, which AWS clarified following our discussions.
AWS Policy Simulator
Praetorian often uses the AWS Policy Simulator to test and validate IAM Permissions. While validating the usage of sts:GetSessionToken and sts:AssumeRole, Praetorian noticed that due to inconsistent documentation around sts:GetSessionToken and the way no attached IAM policy can explicitly deny it, the ability to chain an IAM User with MFA to multiple roles could be misunderstood and misconfigured.
Additionally, Praetorian noticed inconsistent results from the usage of IAM Policy Simulator for sts:GetSessionToken and sts:GetCallerIdentity. The IAM Policy Simulator results for both depend on the IAM policies passed to the simulator (see Figure 8), but they both should always return a permission allowed result. AWS is working on fixing IAM Policy Simulator for both sts:GetCallerIdentity and sts:GetSessionToken.
Figure 9: Incorrect permission result for sts:GetSessionToken and sts:GetCallerIdentity.
Conclusion
Praetorian and AWS both recommend pivoting away from IAM Users and long-term credentials in favor of IAM Roles and other short-term credentials. If an organization must use IAM Users, Praetorian recommends ensuring remediation of role chaining and other privilege escalation paths.
Note: Praetorian has reached out to AWS Security to report inconsistencies with documentation and behavior of sts:GetSessionToken. Praetorian would like to thank AWS Security for their prompt response, updates, and assistance.
Share via: