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

その Lambda、8分で 管理者権限まで奪われます

Avatar for k1nakayama k1nakayama
September 19, 2026

その Lambda、8分で 管理者権限まで奪われます

「インシデント対応の訓練、ドキュメントレビューで済ませていませんか」

サーバーレスは平常時、マネージドサービスに支えられて安定して動きます。だからこそ私たちは、自分のワークロードの「壊れ方」を練習する機会をほとんど持てません。CI/CDにスキャンは入れたが検出結果は放置されている、最小権限は掛け声で終わっている、攻撃を受けたとき何分で気づいて何を切れるのか分からない。

題材は、2026年2月にSysdigが公開した実在の脅威レポートです。公開S3バケットからの認証情報窃取、Lambdaへのコード注入による権限昇格(わずか8分)、19プリンシパルへの横展開、Bedrockの無許可利用。この観測済みキルチェーンを5段階に再構成し、自社GameDayとして再現しました。

そして本題です。同じ攻撃を受けても、キルチェーンがStep 3で止まるチームと、管理者権限まで抜かれるチームがありました。分けたのはIAMポリシーではありません。構成上のある一つの判断でした。それが何か、なぜ効くのかを当日お話しします。ご自身の環境で明日確認できるチェックポイントとして持ち帰ってください。

Avatar for k1nakayama

k1nakayama

September 19, 2026

More Decks by k1nakayama

Other Decks in Technology

Transcript

  1. ServerlessDays Tokyo 2026 | DAY1 Track C その Lambda 、

    8 分で 管理者権限まで奪われます 実際の攻撃を再現して見えた、サーバーレスの分かれ道 中山 桂一 株式会社キャラウェブ / クラウドパートナーグループ 2026.09.19 シニアソリューションアーキテクト 株式会社キャラウェブ | Cloud Partner X: @k1nakayama
  2. 話し手 AWS のサーバーレス推進と、 GitLab を使った AI 時代の DevSecOps が守備範囲です 中山

    桂一 株式会社キャラウェブ 今日持ち帰っていただきたいこと クラウドパートナーグループ シニアソリューションアーキテクト 同じ攻撃を受けても、キルチェーンが Step 3 で 止まるチームと、管理者権限まで抜かれるチーム がありました。 • AWS Community Builder ( Serverless ) • GitLab Champion • AWS と GitLab のインテグレーションが本 業 • X: @k1nakayama / blog.cloudpartner.jp 株式会社キャラウェブ | Cloud Partner 分けたのは IAM ポリシーではありません。構成 上の、ある一つの判断でした。 それが何で、なぜ効くのか。そして明日ご自身の 環境で確認できる形にして、お渡しします。 2
  3. Sysdig TRT の観測事例( 2026 年 2 月) 公開 S3 バケットから認証情報を拾われてから、管理者権限を握られるまで

    8 分でした 0:00 数分 8:00 初期アクセス 偵察 権限昇格 公開 S3 バケットに置かれた 認証情報を取得 Lambda ・ IAM ・ Secrets Manager を片端から列挙 Lambda 関数にコードを注入し 管理者権限を取得 この後、 19 の AWS プリンシパルが侵害され、 Secrets Manager ・ SSM ・ CloudTrail ログが抜かれ、 Bedrock が無 許可で呼ばれました。 しかも AI の痕跡つき セルビア語のコメントが残った LLM 生成コード。実在しない GitHub リポジトリへの参照。 株式会社キャラウェブ | Cloud Partner 4
  4. 8 分に、こちらの検知は間に合うか ログが届いて、ルールが鳴って、人が画面を開くまで。その合計を測ったことがあるでしょうか 合計 8 分 攻撃側 認証情報を取得 列挙 コード注入

    管理者権限 合計 ?? 分 防御側 CloudTrail に イベントが届く → 検知ルールが 評価される → 通知が 飛ぶ → 人が気づいて 画面を開く → 判断して 手を動かす 気づいた時には、もう終わっています。 株式会社キャラウェブ | Cloud Partner 5
  5. サーバーレスの死角 平常時があまりに静かなので、壊れ方を練習する機会がそもそもありません 落ちない、スケールする、パッチも当たる EC2 なら OS もミドルウェアも自分で面倒を見るので、否応なく壊れ方を覚えます。 Lambda では、その機会が来ませ ん。

    内部を初めて覗くのがインシデントの最中になる 実行ロールに何が付いているか、その関数がどこへ通信できるか。落ち着いて確認したことがないまま本番が動いています。 実行ロールは静的で、呼ばれていない間もそこにある 関数が動いていない時間も権限は存在し続けます。コードを差し替えられた瞬間、その権限はそのまま攻撃者のものになり ます。 株式会社キャラウェブ | Cloud Partner 7
  6. UpdateFunctionCode という正規の API ビルドもレビューもパイプラインも通さずにコードを差し替えられます。しかも、これは正規の API です いつものデプロイ 攻撃者のデプロイ git push

    → MR レビュー → CI のテストとスキャ キー 1 本 → aws lambda update-function- ン → デプロイ code → 完了 株式会社キャラウェブ | Cloud Partner 8
  7. 観測されたキルチェーン 6 段階の連鎖。 3 段階目・わずか 8 分で、もう管理者権限に届いています 1 初期アクセス 公開

    S3 バケットから 認証情報を取得 2 → 偵察 Lambda ・ IAM ・ Secrets Manager を列挙 3 → 権限昇格 Lambda にコード注入 → 管理者権限( 8 分) ↓ 4 横展開 5 19 の AWS プリンシパル を侵害 → データ収集 Secrets ・ SSM ・ CloudTrail を抽出 6 → リソース悪用 Bedrock を無許可で呼ぶ ( LLMjacking ) 出典 : Sysdig Threat Research Team 「 AI-assisted cloud intrusion achieves admin access in 8 minutes 」 (2026 年 2 月 ) 株式会社キャラウェブ | Cloud Partner 9
  8. Operation CloudPlate ( 2026 年 3 月・自社開催) 6 段階を、自分たちの構成で本当に成立するかを試せる 5

    ステップに組み直しました 架空のフードデリバリー企業の運用チームという設定。 2 チーム 5 名に、独立した AWS アカウントと GitLab リポジトリを配りました。 Step GM が撃つ攻撃 成立してしまう条件 = チームが潰せる点 1 公開バケットを探し、認証情報を拾う S3 の BlockPublicAccess が無効のまま 2 拾ったキーで ListBuckets / ListRoles を叩く キーが有効なまま(ローテーションされていない) 3 Lambda にバックドアコードを注入する 実行ロールに FullAccess 系が付いたまま 4 IAM ユーザー svc-backup-agent を作り、 SG を全 開放する Step 3 で得た権限が生きている 5 ECS タスク定義にマイニング用の環境変数を仕込む 同上 Step 3 が、 8 分で管理者権限に届いた場所です。ここを止められるかどうかで、この後の全部が変わります。 株式会社キャラウェブ | Cloud Partner 11
  9. 攻撃は連鎖でできている Step 2 で拾われた 1 本のキーが、そのあと全部の武器になります Step 2 コードに残っていた アクセスキー

    この 1 本 Step 3 Lambda にコードを注入し、管理者権限を作る Step 4 IAM ユーザーを作り、 SG を全世界に開ける Step 5 ECS タスク定義を書き換えて資源を持っていく 裏返すと、 Secret Detection が 1 本のキーを見つけて無効化するだけで、 Step 3 以降はまとめて空振りし ます。 株式会社キャラウェブ | Cloud Partner 12
  10. 採点と攻撃を自動化した GM が手を動かすのは「いつ撃つか」の判断だけ。採点も攻撃も自動で回しました 管理アカウント チームアカウント × 2 GameBoard ALB (

    Public Subnet ) FastAPI + React + DynamoDB WebSocket でスコアを即時配信 AssumeRole 監視デーモン 30 秒ごとに各チームの 4 エンドポイントを 叩き、応答すれば加点 ECS Fargate ( Private Subnet ) Aurora PostgreSQL ( Isolated Subnet ) GM ツール Python + boto3 の攻撃スクリプト ECR / Secrets Manager / S3 / Lambda インフラは CDK で書き、 cdk context の inject_failures フラグひとつで「壊れた版」と「正常版」を撃ち分けられるように しています。 株式会社キャラウェブ | Cloud Partner 13
  11. 攻撃スクリプトの構造 撃つ前に、そのチームの構成を読みます。読んだ結果で、撃つかどうかが変わります class AttackStepBase(ABC): def execute(self) -> AttackStepResult: # 1.

    撃つ前に、このチームの構成を読む pre_check = self.pre_check() # 2. 読んだ結果で分岐する # 防がれている → 失敗を演出して加点 # 防がれていない → 本当に撃つ result = self._execute_attack(pre_check) # 3. 何が起きたかをイベントログに流す self.report_to_gameboard(result) return result pre_check() 対象アカウントを boto3 で読む 防がれている 攻撃は失敗した体で演出し、 防御成功として加点する 防がれていない 本当に撃つ。減点と、 理由を書いたログが流れる チームが直していれば攻撃は成立しません。スコアも、そのとおりに動きます。 株式会社キャラウェブ | Cloud Partner 14
  12. pre_check が見ている 3 つ S3 の 4 項目、漏れたキーがまだ生きているか、ロールに何が付いたままか。この 3 つです

    cfg = s3.get_public_access_block(Bucket=b) is_blocked = all([cfg["BlockPublicAcls"], cfg["IgnorePublicAcls"], cfg["BlockPublicPolicy"], cfg["RestrictPublicBuckets"]]) S3 は 4 項目そろって初めてブロック # 漏れたキーで、実際に叩いてみる sts.get_caller_identity() # 通れば未対応、落ちればローテーション済み キーの生死は、叩いて確かめる policies = iam.list_attached_role_policies( RoleName=role)["AttachedPolicies"] has_full = any("FullAccess" in p["PolicyName"] for p in policies) ロールに FullAccess が残っているか 1 つでも false なら Step 1 が通ります リポジトリを見るのではなく、実際に AWS に通る かで判定します 残っていれば Step 3 のコード注入が成立します 書いたつもりと、効いている状態は別物です。だから、動いている環境そのものを読みにいきます。 株式会社キャラウェブ | Cloud Partner 15
  13. 訓練と検証の違い 撃つ相手の構成を見て、その環境で成立するかを判定します。だからこれは訓練ではなく、検証 になります 既製のシナリオ 自社で組んだ GameDay • 用意された問題を解く • 自分たちの構成が攻撃対象

    • 全員が同じ順路をたどる • 防御状態によって展開が変わる • 分かるのは「解けたかどうか」 • 分かるのは「その構成で成立するか」 • 自社の構成は一度も登場しない • 直した効果が、その場でスコアに出る 残るのは、この構成なら攻撃はここで止まる、という事実です。 株式会社キャラウェブ | Cloud Partner 16
  14. CI/CD のスキャン結果が、そのままスコアになる スキャンを有効にして直したチームは、そのぶん攻撃が空振りします スキャナ 何が出たか 直すと、どうなるか Secret Detection (Gitleaks) コードに残されたアクセスキー

    1 本 Step 2 以降が丸ごと空振りする IaC Scanning (KICS) CFn テンプレートから 23 件 ( S3 パブリック、 FullAccess ポリシー) Step 1 と Step 3 が成立しなくなる Container Scanning 古いベースイメージから 4,700 件超 コンテナ側の侵入口が減る スキャンジョブは、最初コメントアウトしてあります。 自分で外して、出てきた指摘を直す。そこまでやって初めて、攻撃を止められる側に回ります。 株式会社キャラウェブ | Cloud Partner 17
  15. 同じ攻撃を、両チームに撃った 片方は Step 3 で止まりました。もう片方は管理者権限まで抜かれました 2400 チーム A 終盤にコードへ残ったキーの存在に気づき、 無効化。

    Step 3 のコード注入はそこで失敗しました。 1800 1200 チーム B Phase 1 の復旧に時間を取られ、スキャン に手が届かず。 管理者ユーザーを作られ、 SG も全開放さ れました。 600 0 11:00 12:00 13:00 13:30 チーム A 14:00 14:30 チーム B 15:00 15:30 16:30 差は最終スコアより、どこで止まったか に出ました。 ※ 当日の環境とデータは削除済みのため、推移は再現したものです 株式会社キャラウェブ | Cloud Partner 18
  16. 同じコードで、結果が変わる 改ざんされた Lambda が IAM に到達できなければ、 Admin 作成はタイムアウトで落ち ます iam.create_user()

    を呼ぶだけの Lambda を 1 本置き、経路の設定だけを変えて実行しました。 コードも IAM ポリシーも同じです。変えたのは、出ていける先だけ。 株式会社キャラウェブ | Cloud Partner 21
  17. VPC に入れれば安全、ではない Lambda を VPC に入れても、 NAT があれば到達先は実質インターネット全部です Private Subnet

    + NAT Gateway Private Subnet + VPC Endpoint だけ Lambda ( VPC 内) Lambda ( VPC 内) NAT Gateway VPC Endpoint (貼ったサービスだけ) IAM / STS / 任意の外部サーバー = 出口の制限は、ほぼ無い S3 / Secrets Manager / ECR など = 到達先を紙に書き出せる IAM に到達できない Lambda は、乗っ取られても管理者ユーザーを作れません。 「 VPC に入れましょう」という話ではありません。どこへ出られるかを決める、という話です。 株式会社キャラウェブ | Cloud Partner 22
  18. 統制は「何が壊れても効くか」で分けられる 多層防御の層とは、厚さのことではありません。壊れる前提が違う、ということです 統制 成り立っている前提 その前提が崩れたとき IAM ポリシー 呼んでいるのが、正しい主体であること 実行ロールを奪われた瞬間、その権限は攻撃者 のものになる

    アプリ内の検証 コードが、書いたとおりであること コードを差し替えられたら、検証ごと消える ネットワーク経路 SCP / 改ざん不能なログ 実行主体が誰かに依存しない どちらが崩れても、そのまま効き続ける IAM は「誰が何をできるか」を制御します。「奪われたコードがどこへ行けるか」は制御していません。 株式会社キャラウェブ | Cloud Partner 23
  19. 最終目的も、経路で止まる Bedrock もエンドポイント経由に寄せれば、攻撃者がやりたかったこと自体が成立しません 1 S3 から認証情報 → IaC スキャンで塞げる 2

    キーで列挙 → Secret Detection で塞げる 3 Lambda にコード注入 → IAM へ到達できなければ失敗 4 19 プリンシパルへ横展開 → Step 3 が止まれば起きない 5 Secrets ・ログを抽出 → 持ち出し先へ到達できない 6 Bedrock を無許可で呼ぶ → エンドポイント経由なら呼べない 経路を絞ると、 3 番から下がまとめて成立しなくなります。 1 本ずつ潰していく話ではありません。 株式会社キャラウェブ | Cloud Partner 24
  20. とはいえ、全部には貼れない だから全部やりましょう、ではありません。認証情報を扱う関数から順に切ります コストの話 洗い出しの話 Interface Endpoint は AZ ごとに時間課金されます。 貼るには、その関数がどこへ通信するかを全部把握してい

    関数の数だけ貼る、という発想では現実的になりません。 る必要があります。これは設計の時にしかできません。 「 NAT を外したら、外部 API を叩いている既存の Lambda が動かなくなる」 そのとおりです。全部の関数を閉じる話ではありません。認証情報やシークレットを扱う関数から順に切る。そこ だけでも、キルチェーンは途中で切れます。 優先順位は、権限の強さではなく「奪われたとき、そこからどこへ行けるか」で決めます。 株式会社キャラウェブ | Cloud Partner 25
  21. 8 分は、これから縮む 人が間に合う領域が、その分だけ狭くなります。予防的な層の相対価値が上がっています 今回の 8 分には、まだ人の手が入っています。 列挙した結果を読んで、次に何を叩くか決める部分。ここが自動化されれば、 8 分はもっと短くなります。実在しない GitHub

    リポジトリを参照するようなミスも、同時に減っていきます。 検知して、人が対応する 「間に合う時間がある」という前提の上 に立っています。攻撃が速くなるほど、 この前提から外れていきます。 実行時に、自動で止める 人より速く反応できます。ただし、止める べき挙動を知っている必要があります。 そもそも成立させない 時間の勝負から降りられる唯一の層です。 攻撃が何倍速くなっても、結果は変わりま せん。 実行時に捕まえる話は、いま裏の Track B で檜垣さんが話されています。資料を後でぜひ。 株式会社キャラウェブ | Cloud Partner 26
  22. GameDay では AI を禁止した 禁止したかったからではありません。自分たちに何が残っているかを、先に測りたかったからで す 今回: AI なし 次回:

    AI あり 測ったのは、手が動くかどうか。ルートテーブルを開い 測るのは、速さではありません。 AI が出してきた対応 て、 SG を読んで、原因にたどり着けるか。ここが空洞 案を評価して、間違っているものを捨てられるか。そこ だと、 AI を渡しても判断ができません。 を見ます。 攻撃側が AI を使う以上、 防御側だけが人力なら、差は開いていく一方です。 株式会社キャラウェブ | Cloud Partner 27
  23. 明日、ご自身の環境で確認できること 手順書があるかではなく、実際にどうなっているかを見てください 1 その Lambda の実行環境から到達できる宛先を、列挙できますか。 NAT があるなら、答えは「インターネット 全部」です 2

    IaC スキャンの検出結果は、いま何件放置されていますか 3 UpdateFunctionCode / CreateUser / CreateAccessKey に検知はありますか。検知してから人に届くまで、 何分かかりますか 4 漏れたアクセスキーを無効化する作業を、誰が何分でできますか。一度、時間を計ってみてください 5 今日のキルチェーンが自社構成のどこで止まるか、机上で最後まで辿れますか 1 番だけでも、今日中に答えが出ます。 株式会社キャラウェブ | Cloud Partner 28