はじめに
Security-JAWS DAYS Day2 でクラウド系CTFの入門によい、と紹介されていたので、やってみた。
ヒントが充実しているので、ほぼヒントそのままではありつつも、備忘録 + ブルーチーム的な視点で考えたことも含めて。
flAWS
Level 1
HTML見てみると「ここには何もないヨン」と書かれている。
is *buckets* of fun とか書いてあるのと、レスポンスヘッダやnslookupからS3の静的ウェブサイトホスティングっぽいとわかる。
$ curl --head http://flaws.cloud -s | grep Server:
Server: AmazonS3
$ nslookup flaws.cloud
$ nslookup 52.92.197.51
51.197.92.52.in-addr.arpa name = s3-website-us-west-2.amazonaws.com.
S3のウェブサイトホスティングはドメイン名とバケット名が一致するという仕様があるため、バケット名は flaws.cloud
だとわかる。 また、nslookupの結果からRegionは us-west-2
ということもわかる。
念のため、ウェブサイトホスティングのURL http://flaws.cloud.s3-website.us-west-2.amazonaws.com/
にアクセスしてみると、http://flaws.cloud
と同じコンテンツが表示される。
次に、 https://flaws.cloud.s3-us-west-2.amazonaws.com/
や http://flaws.cloud.s3.amazonaws.com/
などS3バケットのURLにブラウザでアクセスしてみると、バケット内のオブジェクトの一覧が確認可能となっている。また、aws cliでも同様に (認証情報なしで) リスト可能。
# --no-sign-request = 認証情報なしでのリクエスト
$ aws s3 ls s3://flaws.cloud/ --no-sign-request --region us-west-2
2017-03-14 12:00:38 2575 hint1.html
2017-03-03 13:05:17 1707 hint2.html
2017-03-03 13:05:11 1101 hint3.html
2020-05-23 03:16:45 3162 index.html
2018-07-11 01:47:16 15979 logo.png
2017-02-27 10:59:28 46 robots.txt
2017-02-27 10:59:30 1051 secret-dd02c7c.html
S3の静的サイトホスティングの用途的に、 s3:GetObject
は絶対必要だが、 s3:ListBucket
をつけたいユースケースはあまりないはずなので、必要なければ許可すべきではない。
こういったバケットに機密情報をいきなり置くことはあまりないはずではありつつ、実運用上怖いケースはいくつかありそう。
- 機密という程ではなくても、全オブジェクトの列挙はなるべくされたくないようなケース
- 誤操作や不注意で機密情報をアップロードしてしまった場合に、定期的にオブジェクトの一覧を外部からウォッチされており、アップロードした瞬間に即DLされる
- (総当たりでGetされたらどの道...というところはあるが、時間がかかるし辞書の精度にもよる。シンプルに列挙できてしまうのはよりハイリスク)
今では独自ドメイン+https化するためにCloudFront + ACMを挟むケースが多いはずなので、S3バケット側でCloudFrontのOAIからのみのアクセスに絞るように作るのが考えること減ってよいはず。
※ ちなみにListほげほげのアクション名とAPI名がややこしく、毎回どれがどれだっけとよくわからなくなりがち。。。
前述の通り s3:ListBucket と言うのは、オブジェクト一覧を閲覧する許可するためのものであり、バケット一覧の閲覧を許可したい場合は s3:ListAllMyBuckets という action がある。AWS、S3 をある程度使っている人であれば、この名前にモヤモヤしている人も多いと思う。
Level 2
Level 1 とほぼ同じだけど未認証の状態では通らない。ただし Any Authenticated User
なので適当な認証情報入れてコマンドたたけばListできてしまうやつ。
守る側としては、設計時にこういう視点を持っておくというのもありつつ、他の膨大なMisconfigurationも含めたすべてを全員が常に意識し続けるのはなかなか現実的でないので、CheckcovとかTrivyとかAWS Configとかのツールで常に検査するのがよい (TBD: 具体的に各ツールどのルールがこれに当てはまるというのを調べて補足で書く)
Level 3
Level 1,2 とほぼ同じだが、匿名で s3:ListBucket
s3:GetObject
可能なバケット内に .git/
が入ってしまっており、 aws s3 cp s3://<bucket-name>/ ./level3/ --recursive
とかで手元に持ってくる。
git log
にアクセスキー入っちゃってる
git log -p | grep access_key
そのIAM Userに s3:ListAllMyBuckets
がついている (多分) ので、全バケット名を知ることができる
Another interesting issue this level has exhibited, although not that worrisome, is that you can't restrict the ability to list only certain buckets in AWS,
❯ aws s3 ls
2017-02-13 06:31:07 2f4e53154c0a7fd086a04a12a452c2a4caed8da0.flaws.cloud
2017-05-30 01:34:53 config-bucket-975426262029
2017-02-13 05:03:24 flaws-logs
2017-02-05 12:40:07 flaws.cloud
2017-02-24 10:54:13 level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud
2017-02-27 03:15:44 level3-9afd3927f195e10225021a578e6f78df.flaws.cloud
2017-02-27 03:16:06 level4-1156739cfb264ced6de514971a4bef68.flaws.cloud
2017-02-27 04:44:51 level5-d2891f604d2061b6977c2481b0c8333e.flaws.cloud
2017-02-27 04:47:58 level6-cc4c404a8a8b876167f5e70a7d8c9880.flaws.cloud
2017-02-27 05:06:32 theend-797237e8ada164bf9f12cebf93b282cf.flaws.cloud
デプロイのやり方的に、リポジトリのルート以下全てエイヤッとコピーして .git/
とか .env
とかを含めてしまうとかは (S3に限らずDockerイメージとかでも) よくあるけど、避けたほうがよいという教訓がひとつ。 (無駄なファイル含めてサイズ肥大化するので、SDGs的な観点でもアレ)
あとはもうそろそろAWSのIAMアクセスキーは使うのやめていこう...というところはある。
とはいえやんごとなき事情で使わざるを得ない部分は残るだろうし、何らかの3rd party toolのアクセスキーとかは今後も存在し続けるはずなので、trufflehogなどで定期的なチェックはするとよい。
git-secrets でリモートプッシュする前に全部防ぐみたいなのは各開発者の開発環境に手を入れる必要があり、なかなか運用上厳しい(まわらない)部分がある。
ので、チョークポイントとしてGithubに上がった時点でもれなく検知 > 速やかに無効化していくようなデザインがよいとは思う。
trufflehogやgit-secretsなどのOSSを頑張って全リポジトリ検査できるようにgithub actionsとかで走らせてもよい、、、が、お金があればGitGuardianとかGithub Advanced SecurityのSecret Scanningとかを入れるのが管理は楽そう。
Level 4
It'll be useful to know that a snapshot was made of that EC2 shortly after nginx was setup on it.
❯ dig +short 4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud
ec2-35-165-182-7.us-west-2.compute.amazonaws.com.
35.165.182.7
Basic認証をnginxでかけているっぽい + EC2でホスティングしている + 設定後スナップショット取ったということが書いてあり、多分public snapshotになっちゃってるんじゃないかというあたりがつく。
ちょっと分かりづらいが先の設問で得たアクセスキーのユーザーの名前が backup
であることから推測して、このユーザーでsnapshotを取ったのだろうと推測する。
❯ aws sts get-caller-identity
{
"UserId": "AIDAJQ3H5DC3LEG2BKSLC",
"Account": "975426262029",
"Arn": "arn:aws:iam::975426262029:user/backup"
}
リージョン / AWSアカウント は全部共通というのをどこかで書いてあったので、このAWSアカウントのsnapshotをみる
❯ aws ec2 describe-snapshots --region us-west-2 --owner-id 975426262029
{
"Snapshots": [
{
"Description": "",
"Encrypted": false,
"OwnerId": "975426262029",
"Progress": "100%",
"SnapshotId": "snap-0b49342abd1bdcb89",
"StartTime": "2017-02-28T01:35:12+00:00",
"State": "completed",
"VolumeId": "vol-04f1c039bc13ea950",
"VolumeSize": 8,
"Tags": [
{
"Key": "Name",
"Value": "flaws backup 2017.02.27"
}
],
"StorageTier": "standard"
}
]
}
# "Group": "all" はPublic
❯ aws ec2 describe-snapshot-attribute --snapshot-id snap-0b49342abd1bdcb89 --attribute createVolumePermission --region us-west-2
{
"CreateVolumePermissions": [
{
"Group": "all"
}
],
"SnapshotId": "snap-0b49342abd1bdcb89"
}
snapshot-idがわかったので、適当なAWSアカウントで https://us-west-2.console.aws.amazon.com/ec2/home?region=us-west-2#Snapshots:visibility=public;v=3;snapshotId=snap-0b49342abd1bdcb89
を開いてみるとGUI上でもPublicになってることがわかる。
(TODO: GUIからAWSアカウントIDとかで特定しに行くのはいけるのか?後日もうすこし試す)
このスナップショットを適当に立てたEC2にマウントして中を漁る。
-
/etc/nginx/sites-available/default
にnginxの設定 -
/var/www/html/index.html
見に行くとそのまんまBasic認証抜けたあとのページ -
/home/ubuntu/setupNginx.sh
に htpasswd の設定コマンド履歴
などなどなどなど
流石にここまであからさまなケースは無いにしても、内部的にバックアップと本番サーバー/データベースに対するコントロールを同等にできているか?は常に考慮していく必要がありそう。
例えば、社内開発者によるec2/rdsへの接続を厳密に管理していても、ec2 copy-snapshot / rds copy-db-snapshotが広く付与されてしまっていたらこの問題のようにサーバ内の情報を色々持ち出せる。
Level 5
curl http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance/
で取った権限で aws s3 ls <level6のバケット>
。
- IMDSv1は無効化しておく
- 設定ミス等でのオープンプロキシ発生に注意する
- 入力値を受け取って何らかのリクエストを発生させる機能は注意 (仕様策定段階でなるべく避ける)
- インスタンスプロファイルで着けるIAM Roleの権限最小化しておく
- その他にもIMDSで取得できる情報には注意する(インスタンスのTagとか, User-Dataとか)
Level 6
For this final challenge, you're getting a user access key that has the SecurityAudit policy attached to it. See what else it can do and what else you might find in this AWS account.
SecurityAuditポリシーが付いてるのでいろいろ探索的にみることができそう。最短経路はヒントに記載されているが、以下の通り↓
- 着いてるIAMポリシーからAPI Gatewayまわりでなんかするっぽいなとわかる > API GatewayといったらLambdaだよなとあたりをつける > ... でなんやかんや辿ってURLにたどり着く。
ReadOnlyだからノーリスク、ではないというのは最低限理解しておいたほうがよい。Read系まで含めた最小権限付与を徹底する。
過去N日のCloudTrailみてゴニョゴニョするツールとかを使うと、システム用のRoleの場合はかっちり設定やりやすい。が、開発者用のRoleなどの場合は(動作が定型的ではない、明日にはこれまでに使ったこと無い権限を使うかもなので)なかなか難しく、生産性とも直結するので結構チャレンジングな部分になってくる。
あと個人的に Lambda + API Gatewayのスタックはあんまり土地勘がなかったのでどこかで勉強する。
感想
- ハンズオン的に社内でやってみるのも面白そう。
- こんど http://flaws2.cloud/ もやる。