Upgrade to Pro — share decks privately, control downloads, hide ads and more …

攻撃 3 時間 vs 復旧 10 時間。アクセスキー流出の非対称性を体感するために CTF を...

Avatar for kazzpapa3 kazzpapa3
October 30, 2026

攻撃 3 時間 vs 復旧 10 時間。アクセスキー流出の非対称性を体感するために CTF を作った話

2026年10月31日に新潟の NINNO3 で開催された KomeKaigi 2026 でお話しした内容です。
クレデンシャル流出が多い昨今、対応していて攻撃者と防御側の対応時間の非対称性を知ってほしい!というモチベーションで作成した CTF(Capture the flag)ゲームを作成した時の話です。
AWS が提供する AI Agent である Kiro の CLI 版を利用して作成しましたが、犯行事例やログ生成などは Kiro が知っていたものも多く、やはり攻撃手法については広く知られているものも多いのだと再認識するとともに、アクセスキーを無くしたいと思っている本人自身を華麗にスルーしてしまった落とし穴についてお話ししました。
#KomeKaigi

Avatar for kazzpapa3

kazzpapa3

October 30, 2026

More Decks by kazzpapa3

Other Decks in Technology

Transcript

  1. KomeKaigi 2026 (October 31, 2026) 攻撃 3 時間 vs 復旧

    10 時間。 アクセスキー流出の非対称性を体感するために CTF を作った話 Speaker : @kazzpapa3(ICHINO Kazuaki)
  2. 本日のキーワード 用語 ざっくり言うと AWS アカウント AWS を使うための契約単位。サーバーやデータなどのリソースはすべてこの中に作られる 「クラウド上の自分専用の区画」 API プログラムから

    AWS を操作するための窓口。画面(コンソール)でのクリック操作も、裏 側ではすべて API 呼び出し クレデンシャル(認証情 報) AWS に「自分は誰か」を証明する情報の総称。パスワードやアクセスキーなど IAM(ユーザー / ロール / ポリシー) 「誰が・何をしてよいか」を管理する仕組み。ユーザーは ID、ロールは一時的に借りる権 限の役割、ポリシーは許可・禁止のルール アクセスキー プログラムから AWS を操作するための ID とシークレットの組(API キー相当)。有効期 限がなく、削除するまで使え続けるため、漏れると第三者に使われ続ける 一時認証情報 数分〜数時間で自動的に無効になる認証情報。漏れても被害の時間を限定でき、現在はこち らが推奨 CloudTrail 「いつ・誰が・どの API を実行したか」を記録し続けるサービス。いわば監視カメラの録 画で、被害調査はこのログを読み解くことになる CTF(Capture The Flag) セキュリティの知識や技術を競うゲーム形式の競技。問題の中に隠された答えの文字列(フ ラグ)を見つけて提出すると得点
  3. Biography { "Bio": { "Name": "ICHINO Kazuaki a.k.a. kazzpapa3", "Organization":

    "A certain AWS partner company", "Role": "Technical Support Engineer", "Favorite AWS Services": [ "AWS CLI", "AWS CloudTrail", "Kiro CLI" ], "Less Favorite People (as a Support Engineer)": [ "クレデンシャル情報を雑に扱う人" ], "Personal Interest": "初音ミク", "Socials": { "Twitter/X": "@kazzpapa3", "LinkedIn": "https://www.linkedin.com/in/kazzpapa3/" } } }
  4. AWS のパートナー企業でテクサポをやっています お客様 - 弊社 - Amazon Web Services(AWS)という関係性で AWS

    アカウントをお客様へ再販しています 契約関係上、お客様は AWS への直接的なパスを持たないので、弊社が 代わりにサポート窓口を設け、AWS になりかわって技術サポートを行 います お客様からの問い合わせに対して、「公式ドキュメントで仕様が公開さ れているか」「発生事象の再現性があるか」を確認し、AWS に聞くし かない、となった時点で AWS Support に問い合わせをしています @kazzpapa3 / #KomeKaigi 5 / 40
  5. 基本的に弊社を介することとなる 弊社(リセラー) お客様 AWS アカウント お問い合わせ AWS 上記の構図となるため、AWS から届く通知も弊社を通ることになる 不正な利用が疑われる事象が

    AWS からの E メールや AWS が起票する サポートケース(アウトバウンドケース)として届く そのため、私の所属部署での、問題発生の把握に繋がっている @kazzpapa3 / #KomeKaigi 6 / 40
  6. 作成経緯やモチベーション アクセスキーの流出の調査や封じ込めの支援などを通じて、犯行者の一 定の行動が見えてきていた もしかしたら Kiro など生成 AI では、攻撃者の多くが行う行動を、既 知の手法としてそれらを理解しているかも?と考えた 別界隈

    で CTFd という OSS があることを知ったので簡単に作れるか もしれない、という期待 Kiro CLI を利用して Vibe Coding 的に作ってみよう! そして、漏れたキーを使って 第三者によって行われた API 実行を客観 的に調査することの難しさ、めんどくささを体験してもらいたい! @kazzpapa3 / #KomeKaigi 8 / 40
  7. 開発初期に投入したプロンプト @kazzpapa3 / #KomeKaigi “ “CTFd を用いて、アクセスキー流出事例をテーマとした CTF ゲーム環 境を作りたい

    流出したキーの特定から封じ込め、犯行者に実行されたアクションの 特定を行うシナリオで CloudTrail のログを解析してフラグを検索ある いは結合し回答する形式にしたいです 9 / 40
  8. 出来上がったモックアップ Terraform で出来上がる AWS 環境を使った仕組みができた 合わせて作成されたセットアップスクリプトによって、CloudTrail の ログを模した json ファイル群を作成、S3

    バケットにアップロード し、CTF のフラグの検索用の元ソースとして利用する形となっていた 問題の作成もセットアップスクリプトで行うように定義されており、 ctfcli で CTFd 環境にチャレンジをインストールする形式も出来上がっ ており、ほぼ修正なしで利用できる状況だった @kazzpapa3 / #KomeKaigi 10 / 40
  9. 問題の作成も AI がやってくれた また、問題についても Kiro CLI が作成してくれており、このゲームを 用いたコミュニティイベントを実施した際のバージョンでも 7 割ほどは

    Kiro CLI が作成した問題を採用した 作成された問題は、実際の事象発生中に見かける攻撃手法であったこと から採用した このことからも 生成 AI も理解している、広く知られた攻撃手法 な のだと再認識した 最初の Kiro CLI へのプロンプト実行から 3 時間程度で実際に遊べる状 況まで仕上がっており、一度所属企業内で遊んでみている @kazzpapa3 / #KomeKaigi 11 / 40
  10. その 1 - スケーラビリティを向上させたい EC2 インスタンス1台で CTFd を稼働させる構成となっており、デー タベースには CTFd

    既定の SQLite を使用することとなっていた 多人数でゲームを行う場合にボトルネックになる可能性があり、Kiro CLI に性能評価を求めてみると以下のような回答が得られた @kazzpapa3 / #KomeKaigi 14 / 40
  11. その 1 - Kiro の回答 “SQLite の特性 読み取りは複数同時に可能だが、書き込みはデータベース全体をロ ックする(WAL モードでも

    writer は1つ) CTFd はフラグ提出のたびに INSERT が走るので、同時提出が集中 @kazzpapa3 / #KomeKaigi “ するとロック待ちが発生する 15 / 40
  12. その 1 - Kiro の回答 “現実的な目安 体感 ~10人 問題なし 10〜30人

    ほぼ問題ないが、一斉提出時に稀に数百ms の遅延 30〜50人 スコアボード表示やフラグ提出で体感できる遅延が出始める 50人〜 外部 RDS を使うことを推奨する @kazzpapa3 / #KomeKaigi “ 参加者数 16 / 40
  13. その 1 - Kiro の回答 “ボトルネックになるポイント 1. フラグ提出: INSERT +

    正誤判定。一斉に提出が集中する競技開始 直後やヒント公開直後が最も負荷が高い 2. スコアボード: 全チームのスコアを集計する SELECT。参加者が増 えるとクエリが重くなり、かつ書き込みロックと競合する 3. CTFd 自体が Gunicorn (デフォルト1 worker): SQLite のロック @kazzpapa3 / #KomeKaigi “ 以前に、アプリケーションレベルの並列処理能力が限定的 17 / 40
  14. その 1 - Kiro の提案 Kiro に対して「スケールしやすくかつサーバレスでも環境をデプロイ できるようにしたい」と伝えたところ、「デプロイモード」として 「EC2 モード」と「Fargate

    モード」を作りましょう、と言ってくれ て、これもほぼ一発で動作するようにしてくれた デプロイモードの切り替えも Terraform の terraform.tfvars で ctfd_mode 変数に定義するだけの簡単設定にしてくれるなど、いい感 じにやってくれた @kazzpapa3 / #KomeKaigi 18 / 40
  15. その 2 - よりリアリティを出す スケーラビリティは向上しましたが、CloudTrail のログを S3 からダウ ンロードしてローカルで調査するとなると、 cat

    *.json | jq 祭り、 grep 祭りになってしまうなという気がした どうせなら AWS アカウント内でちゃんとログが出ている方が良いが、 私が思いつく方法も Kiro に聞いた結果も、結局実際の API 実行をする しかなさそうだった 結局、実際に攻撃して AWS API の履歴を CloudTrail に残して、 CloudTrail のログを確認するための API 操作をやることで解析できる 形とした @kazzpapa3 / #KomeKaigi 19 / 40
  16. 改良 1 , 2 により実現できるようになったこと 1. S3 バケットにある CloudTrail のログをダウンロードし、手元で解析を

    行う 2. AWS アカウントにコンソールログインして GUI で CloudTrail を調 査、解析を行う 3. AWS アカウントに AWS CLI 経由でアクセスし、CLI で CloudTrail の 調査、解析を行う 4. 上記のいずれの手法でも AI Agent に壁打ちしたり、自律的な調査を AI にやってもらうこともできるようになった @kazzpapa3 / #KomeKaigi 20 / 40
  17. その 3 - 参加者向けガイドドキュメントの自動生成 セキュリティ界隈の方だと CTF(Capture The Flag)というものにつ いての一定の理解はあるかもしれませんが、JAWS 界隈ではあまり見聞

    きしたことがなく、私も別界隈で初めて知った感じ そのため、「フラグ」というものがどのようなものかの解説と、ゲーム の中で何を問われているか、何を見つけて回答すればいいのか、などの 説明も必要だと感じた そのため、基本的に定型化しておき、CTFd のゲーム環境が構築される と同時に、参加者向けのドキュメントも自動生成させることを目指した @kazzpapa3 / #KomeKaigi 21 / 40
  18. ここまででできるようになったこと 1. Terraform Deploy Flow terraform.tfvars - ctfd_mode - s3

    - live - investigation_mode - ec2 - fargate Terraform ec2 terraform apply s3 EC2 モード s3 モード setup.sh ログ生成 + CTFd 登録 ctfd_mode? fargate live Fargate モード live モード investigation _mode? 2. CTFd Deploy Mode EC2 モード (少人数向け) Fargate モード (大規模: 50人〜) 攻撃再現環境 IAM User + S3 + Lambda VPC Docker (CTFd) EC2 参加者 IAM + 制限付き Policy OR ALB 参加者 IAM User + 制限付き Policy ECS Fargate Aurora Serverless v2 IAM CTFd x2 IAM NAT Gateway @kazzpapa3 / #KomeKaigi ElastiCache Redis 22 / 40
  19. ここまででできるようになったこと 3. Investigation Mode s3 モード (デフォルト) live モード (実践的)

    Python generate-logs.py ✔ 単一アカウントで可 ✔ 追加コストなし 記録 API 実行 S3 参加者 模擬 CloudTrail JSON ログ aws s3 cp + jq で解析 OR Lambda (攻撃実行) Route 53 CloudTrail 記録 us-west-2 / eu-west-1 Secrets Manager ✔ 実際の CloudTrail イベント ✔ 実務に近い体験 Organizations + SCP 必須 ⚠ 記録 RDS lookup 参加者 aws cloudtrail lookup-events 4. Participant Guide (MkDocs) participant-guide/ docs/*.md mkdocs build (Material theme) S3 参加者 イド内容 • はじめに • 調査方法 (S3/Live) • ステージ概要 • トラブルシューティング 参加者 静的サイト ホスティング @kazzpapa3 / #KomeKaigi 23 / 40
  20. ここまででできるようになったこと 1. terraform.tfvars で Deploy モードと Investigation モードを定義す る 2.

    Deploy モードの設定に応じて CTFd の実行環境が構築される 3. Investigation モードの設定に応じてログを生成 or 攻撃スクリプトが 実際の AWS API を実行 → それぞれに応じて設問と回答を生成 4. 参加者向けガイドドキュメントを自動作成 @kazzpapa3 / #KomeKaigi 24 / 40
  21. 第一波: アクセスキー流出 (Stage 1-5) # 1 2 3 4 5

    難易度 ★☆☆ ★★☆ ★★☆ ★★☆ ★★★ カテゴリ ヒント 発案者 Recon GuardDuty の findings を読む Kiro Investigation CloudTrail ログの分析 Kiro Investigation S3 操作の追跡 Kiro Containment AWS CLI で封じ込め実行 Kiro Persistence 複数リージョンの調査 Kiro @kazzpapa3 / #KomeKaigi 26 / 40
  22. 第二波: 横展開と深い侵害 (Stage 6-19) # 6 7 8 9 10

    11 12 13 14 15 16 17 18 19 難易度 ★★☆ ★★☆ ★★☆ ★★☆ ★★★ ★★★ ★★★ ★★☆ ★★★ ★★☆ ★★☆ ★★★ ★★☆ ★☆☆ カテゴリ ヒント 発案者 Investigation AssumeRole の痕跡 Kiro Investigation 複数リージョンの EC2 操作 Kiro Forensics CloudTrail 自体への攻撃 Kiro Network セキュリティグループの変更 Kiro Persistence SSM コマンドの内容 Kiro Investigation DNS レコードの変更 Kiro Persistence Lambda + EventBridge Kiro Investigation Secrets Manager へのアクセス Kiro Investigation RDS スナップショットの共有 Kiro Persistence インラインポリシー Kiro Persistence コンソールアクセスの追加 Kiro Persistence MFA デバイスの設定 Kiro Investigation S3 バケットポリシー Kiro Investigation 失敗した操作の痕跡 Kiro
  23. 第三波: 阻止できた大規模攻撃 (Stage 20-23) # 20 21 22 23 難易度

    ★★★ ★★☆ ★★★ ★★☆ カテゴリ ヒント 発案者 Persistence IAM ロールの信頼ポリシー書き換え 筆者 Investigation オプトインリージョンの有効化試行 筆者 Persistence ASG + ECS による自動復活クラスター 筆者 Investigation SageMaker ノートブック起動試行 筆者 このカテゴリは実際の攻撃(被害)から新たな手法を見出し、筆者にて 発案して実装した 実際に高額利用につながった事例であるため、攻撃の再現による費用発 生を抑えるため、SCP(Service Control Policy)で阻止できたことに して、事例の習熟につながるように設計した @kazzpapa3 / #KomeKaigi 28 / 40
  24. 最終問題 (Stage 24) # 24 難易度 ★★★ カテゴリ Forensics @kazzpapa3

    / #KomeKaigi ヒント 全体タイムラインの把握と整理 発案者 Kiro 29 / 40
  25. JAWS-UG 神戸支部でゲーム大会として開催 私が共同運営する JAWS-UG 神戸支部でハイブリッド型のイベントと して開催 37 名の方に参加いただけて、概ね完走していただくことができた AI Agent

    を駆使し最速で回答をされる方、縛りプレイとして AI を使わ ず自力かつ CLI で CloudTrail を調査された方、AI を相談相手として ヒントの使用を抑えた方、など、想定通り、多種多様な取り組みかたを していただけたようでした @kazzpapa3 / #KomeKaigi 31 / 40
  26. 再掲)改良 1 , 2 により実現できるようになったこと 1. S3 バケットにある CloudTrail のログをダウンロードし、手元で解析を

    行う 2. AWS アカウントにコンソールログインして GUI で CloudTrail を調 査、解析を行う 3. AWS アカウントに AWS CLI 経由でアクセスし、CLI で CloudTrail の 調査、解析を行う 4. 上記のいずれの手法でも AI Agent に壁打ちしたり、自律的な調査を AI にやってもらうこともできるようになった 2 を実現するのに IAM ユーザーを発行し、3 の実現のためにアクセス キーを配布する という実装になっていた 34 / 40
  27. フィードバックを踏まえた最新の構成 Cognito + EC2 フェデレーション発行サーバによる一時認証情報発行 AWS Cloud / Account (ap-northeast-1

    ほか) victim-env(被害環境・調査対象リソース) ctfd-fargate 専用 VPC (10.0.0.0/16) データイベント記録 customer-data-prod aws-ctf-cloudtrail aws-ctf-evidence aws-ctf-docs CloudTrail (顧客データ / 攻撃対象) (証跡ログ保管) (GuardDuty findings) (参加者ガイド/公開Web) aws-ctf-trail(マルチリージョン) Internet Gateway NAT Gateway + EIP ALB (HTTP:80) forward :8000 Public Subnet × 2 (AZ-a / AZ-c) ALB・NAT GW を配置 (map_public_ip=true) AssumeRole IAM User: dev-tanaka IAM Role: admin-role IAM Role: Lambda: ctf-verify-containment IAM Role: (被害者 / AdministratorAccess) (攻撃者が AssumeRole)system-health-check (Stage4 検証 / フラグ発行) verify-containment (backdoor Lambda 実行ロール) (verify Lambda 実行ロール) イメージ取得 Private Subnet × 2 (AZ-a / AZ-c) live モード限定リソース MySQL :3306 Redis :6379 Route 53 Hosted Zone Secrets Manager example-corp.com(Stage11) prod/database/credentials(Stage13) RDS: prod-database MySQL db.t3.micro(Stage14) ECS Cluster aws-ctf-ctfd ECS Service (Fargate) ctfd × 2 tasks (port 8000) Aurora Serverless v2 MySQL (ctfd DB) ElastiCache Redis cache.t4g.micro Security Groups: alb / ecs(8000) / db(3306) / redis(6379) CTFd 利用 SSM SendCommand ターゲット(Fargate モード時に main.tf が作 成) auth(cognito モード)— クレデンシャル配布基盤 IAM Role: ctfd-exec (TaskExecutionRole) CloudWatch Logs /ecs/aws-ctf-ctfd InitiateAuth EC2: aws-ctf-ctfd (t3.nano) IAM Role: ssm-target SSM Agent 有効 (SSMManagedInstanceCore) Cognito User Pool + ClientEC2: token-server (t3.micro) (参加者認証) Flask :8080 / default VPC ログイン/クレデンシャル取得 HTTP :8080 AssumeRole(一時認証情報発行) CTF 参加者(ブラウザ / CLI) IAM Role: token-server IAM Role: participant (AssumeRole + Cognito + SSM) (参加者用 / 時間制限付き権限) SG: token-server (HTTP:8080 公開) / InstanceProfile 35 / 40
  28. その後、何人かの AWS 関係者とも会話しましたが 割と普通に AI Agent が生成してくるスクリプトは、永続的なクレデン シャルに依存した実装をしてくることが多そう 「今は」ベストプラクティスではないものの、「過去に」多く採用され ていた実装方法なので、引きずられている可能性はあるかもしれない

    生成は AI でできるようになったものの、今のベストプラクティスを踏 まえているか?の目線は大事 そのため、ベストプラクティスが変遷していくことを理解し、今回のよ うな勉強会なども通じて、常にキャッチアップを怠らないようにしない といけない、と再認識しました @kazzpapa3 / #KomeKaigi 38 / 40