Lateral movement between AWS accounts - Abusing trust relationships

2019.02.04

RSS feed

Best practice on AWS is to create multiple accounts instead of the entire company working out of a single large account. This helps reduce the blast radius of incidents, among other benefits. Trust relationships are then established between the different accounts in order to grant access to IAM roles, S3 buckets, networks, and more. These trust relationships can diminish the isolation goals of having the separate accounts. This post describes this concept further, how an attacker can find and abuse these trusts, and how defenders can identify and analyze these trusts.

AWS account trust relationships

It is very difficult, and often impossible, to both allow certain common use cases on AWS and isolate parts of an account to only those use cases. In order to isolate projects, AWS recommends using multiple accounts. This not only helps isolate things in the event of a compromise, but also helps make billling easier to understand, avoid certain account limits, and more.

AWS recommends a multi-account strategy, and they have a service AWS Control Tower (a managed version of their previously released AWS Landing Zone), that not only is supposed to help companies setup new AWS accounts easily, but just by itself requires 4 AWS accounts. There are a number of companies that have already surpassed 100 AWS accounts or are planning to. I personally have almost a dozen accounts in order to isolate my main account that hosts my website from the hacking challenge flaws.cloud, two accounts for flaws2.cloud, test accounts, and accounts I use for training I give.

Most accounts at companies are going to have trust relationships between each other, and between external third-party vendors. A common trust relationship is to have CloudTrail logs from multiple accounts configured to be delivered to a single S3 bucket in a “Security” account. That Security account has a resource policy on the S3 bucket that is granting some level of trust to all of the other accounts. Another common strategy is to have an “Identity” account that employees log into and then assume into IAM roles into other accounts. All of the other accounts then have an IAM role with trust relationships back to the Identity account. This simple example is shown in the following diagram, and note that as the number of accounts and types of relationships increases, this situation becomes even more complex.

Trust relationships between accounts

The types of trust relationships possible include:

  • IAM role trust relationships that allow one account to assume a role into the other account. For more info see the AWS docs Tutorial: Delegate Access Across AWS Accounts Using IAM Roles.
  • Resource policies: These look like IAM policies, but are applied to resources, and grant access to S3 buckets, glacier vaults, KMS keys, SQS, SNS, and other services. For more info see the AWS docs AWS Services That Work with IAM for information about which services work with Resource Polices.
  • S3 ACLs: S3 also supports an older trust relationship that is possible with ACL’s and canonical IDs. For more info see the AWS docs Access Control List (ACL) Overview
  • Network trusts: This could be in the form of VPC peering, Direct Connect back to datacenters, Security Groups allowing access to certain public IP ranges in another account, and more. In any of these cases, you may have a situation where trusted network resources have no authentication, or weaker authentication.
  • Resource Access Manager: This new service announced at re:Invent 2018 is meant to allow accounts to share resources. Currently the only interesting resources for this discussion that can be shared are VPCs and Transit Gateways, which results in a similar situation as the network trusts mentioned above.

How an attacker can abuse these trusts

Let’s say an attacker compromises an employee laptop, finds the file ~/.aws/credentials, and uses the access key and secret key they find there to configure their own AWS CLI. They run aws sts get-caller-identity and get back:

{
    "Account": "111111111111",
    "UserId": "AIDA00EFXQQ53AZ3IY11U",
    "Arn": "arn:aws:iam::111111111111:user/alice"
}

They then run aws iam get-account-authorization-details and look up the user alice in the data that is returned and find this user has the AdministratorAccess policy attached! This policy allows the Action * on the Resource *, which means the user can do anything!

The attacker looks around though and the account isn’t very interesting. They look for S3 buckets and they look in every region for interesting resources. There just isn’t anything interesting there. If the attacker isn’t familiar with the concepts abusing trust relationships between accounts, they might stop there, but our attacker knows what they are doing.

The attacker then looks at ~/.aws/config on the laptop they compromised and finds:

[default]

[profile security]
source_profile=default
role_arn=arn:aws:iam::222222222222:role/admin

The attacker can now access two accounts, the original 111111111111 and the new 222222222222, in order to look around further. In order for alice to assume this other role, the 222222222222 account might have a trust policy on the admin role that looks like:

# Trust policy
{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Principal": {
        "AWS": "arn:aws:iam::111111111111:user/alice"
    }
  }
}

The attacker can then review the IAM privileges in the two accounts, and they might come across another user in the account with an IAM policy like:

# IAM policy
{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "arn:aws:iam::333333333333:role/admin"
    }
}

The attacker can then user their admin privileges to become that other user and then assume the role into the third account.

The IAM policies might also specify resources in other accounts that a user can access, such as an S3 bucket. You can search the output of aws iam get-account-authorization-details with the regular expression :\d{12}: in order to search for 12-digt AWS accounts in ARNs. By filtering out the current AWS account, you can find other accounts and their associated resources you might be able to access.

The resources in the account the attacker has compromised might also have trust policies that indicate the resources are being shared with other accounts. Sometimes this can be interesting, such as an S3 bucket containing bash scripts or CloudFormation templates that other accounts use, or a shared AMI that is used to boot up EC2s in other accounts. These concepts are described by the Thinkst team in this 2017 Black Hat talk Fighting the Previous War aka Attacking and Defending in the Era of the Cloud.

How an attacker can use CloudTrail logs to their favor

If an IAM user simply has the AdministratorAccess policy or similar on themselves, they might not have any special policy added to them that further describes what roles in other accounts they can access, because they already have privileges to do so. This might make life harder for the attacker, but our attacker is smart. They know they can look in the CloudTrail logs to see what roles users in these accounts have accessed.

But what if CloudTrail isn’t on, or has been sending logs to an S3 bucket you can’t read from? Well, the attacker could use CloudTrail Event History which gives you access to 90 days of CloudTrail logs in the UI or via the CLI. In our case, the attacker could run:

aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRole

This will tell you role assumptions that have happened in this account. Similar queries can be used to look for other accesses of resources in other accounts.

How defenders can identify and analyze these trusts

Defenders (and attackers) can use CloudMapper’s wot (web of trust) command to identify trust relationships of their accounts. See more details here. Given one or more accounts, this command will find what accounts they trust to access them. This is the opposite direction of trust that attackers are normally interested in.

As a defender, you want to ensure your assumptions hold true, being mindful of privilege escalation and lateral movement. You want to ensure that the accounts you think are isolated from each other actually are. Are two accounts actually outside the blast radius of each other if one account is compromised? You might think alice is the only user that can access a Security account through a role assumption from the main account, but if a user bob is an admin user in the Identity account, then he can take-over the alice user and access that role too. I like to use a crown icon, as shown in the following image, to indicate when a user or role is an admin.

bob takes over alice user to assume into role

I’ve seen a situation where there was a sensitive AWS account that was only supposed to be accessed from one other account. This was true, but that other account granted trust to three other accounts to allow users in those accounts to become admin in it. The result was there were actually 4 other AWS accounts that could access this account! There was the one direct path, and then 3 indirect paths.

Indirect account access

You also need to worry about cycles. Imagine a user that might not be able to escalate their privileges in the current account, but they could assume a role into another account, and then might be able to assume a role back into the original account with higher privileges!

Privilege escalation using multiple accounts

Account trust relationships are often made to allow anyone in the other account to access the resource in the destination account. This can result in a user or role that is relatively unprivileged in one account, being highly privileged in another account. This is sometimes the goal, but should be understood when it happens. For example, I often recommend using an Identity account as has been mentioned in this post, but all the users in that account, except a few select admins, should not have any privileges other than to assume roles in other accounts.

I hope this post has helped explain the dangers and considerations you should have when setting up and evaluating trust relationships between accounts.