About a year ago, during a review of our cloud infrastructure, my colleague Martin Birtel from our InfoSec department, discovered that a specific AWS managed policy can give hackers super powers.
The finding was related to the role SecretsManagerReadWrite which was attached to a Lambda responsible for credential management.
This is a great cocktail for an account takeover as you'll see below.
The SecretsManagerReadWrite managed policy includes surprising CloudFormation permissions:
{
"Version" : "2012-10-17",
"Statement" : [
{
"Sid" : "BasePermissions",
"Effect" : "Allow",
"Action" : [
"secretsmanager:*",
"cloudformation:CreateChangeSet",
"cloudformation:DescribeChangeSet",
"cloudformation:DescribeStackResource",
"cloudformation:DescribeStacks",
"cloudformation:ExecuteChangeSet"
],
"Resource" : "*"
}
]
}
It allows the principal (the Lambda execution role in our case) to create and execute CloudFormation change sets. This shouldn't be an issue as long as the Lambda role is not allowed to create all kinds of resources, right?
CloudFormation stacks with attached IAM roles
When you create a CloudFormation stack, you can attach an IAM service role that has permissions to create the defined resources. After stack creation, this service role remains attached and CloudFormation uses it for all future operations, including executing change sets.
If you have permissions to update CloudFormation stacks, you're already in the hacking game. This means that you can use the permissions attached at the stack creation (CloudFormation service role) to make calls to resources in a stack on your behalf.
AWS gives us a heads-up in the official documentation:
When you specify a service role, CloudFormation always uses that role for all operations that are performed on that stack. It is not possible to remove a service role attached to a stack after the stack is created. Other users that have permissions to perform operations on this stack are able to use this role, regardless of whether those users have the iam:PassRole permission or not. If the role includes permissions that the user shouldn't have, you can unintentionally escalate a user's permissions. Ensure that the role grants least privilege.
The escalation path
- You have a CloudFormation stack with a high privilege service role attached (let's assume Administrator).
- An attacker obtains credentials for a role with SecretsManagerReadWrite policy.
- The attacker discovers existing stack names (through enumeration or other means).
- The attacker creates a change set targeting the high-privilege stack.
- The attacker executes the change set using the stack's service role.
Your CloudFormation stack just created new resources generated by the change set, while your hacker didn't have the permissions to create them. It only had the SecretsManagerReadWrite role which allowed the creation and execution of change sets. Since the CloudFormation service role had Administrator permissions, the change sets could essentially do anything in the account.
Now let's get back to our cheerful Lambda: as it had this SecretsManagerReadWrite attached, it could call the CloudFormation API and create/execute change sets. This means it could inherit the permissions of any CloudFormation stack's service role in the account.
Heads-up: just because a policy is AWS managed, doesn't mean it follows the principle of least privilege for your specific use case.
PS. AWS Support confirmed this is by design.
Top comments (0)