mcpField
I
investigating-azure-incidents

investigating-azure-incidents

github.com/trilwuセキュリティ17747 回インストール12 週間前に更新
リポジトリ

investigating-azure-incidents について

Azure リソースと ID に関わるインシデントを調査するセキュリティスキルです。Azure Activity Log を Entra のサインイン記録やリソース診断ログと関連付け、データプレーンログがないことはデータ未アクセスの証明にならないと説明します。

主な機能

  1. 01ログソースと保持期間の確認
  2. 02Activity Log と Entra ID の関連付け
  3. 03KQL による AzureActivity の検索
  4. 04ロールと認証情報の変更の検出
  5. 05マネージド ID トークン悪用の調査
  6. 06封じ込め前の証拠保全

活用シーン

  1. 01不審な Azure デプロイの調査
  2. 02リソース外で使われたマネージド ID トークンの追跡
  3. 03Storage や Key Vault のデータ窃取可能性の評価

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/trilwu/secskills --skill investigating-azure-incidents

インストール後、Claude Code で/investigating-azure-incidentsを入力して読み込まれたか確認します。

詳細

Azure インシデントの調査

Azure では、コントロールプレーンのほぼすべての操作が Azure Resource Manager を通じて記録されるため、インシデントは Activity Log と リソース/データプレーンのログを使い、呼び出しを行った ID(ユーザー、 サービスプリンシパル、マネージド ID)を軸に再構成します。よくある落とし穴は、 ID の情報は Entra にあり、被害の情報はサブスクリプションにあることです。両方の プレーンをまたいで関連付ける必要があります。Activity Log はリソースに対して 何が行われたかを示しますが、Entra のサインインログは、誰がトークンを 所持し、どこからアクセスしたかを示すためです。

使用する場面

  • Azure リソースの侵害が疑われる場合 — サブスクリプション、リソースグループ、VM が誰かに制御されているかのように動作している
  • Azure Activity Log に異常なエントリがある場合 — 見慣れない呼び出し元、IP、リージョンからの書き込み、または列挙に見える AccessDenied の大量発生
  • Microsoft Defender for Cloud のアラート — 暗号通貨マイニング、異常なリソースのデプロイ、不審なサインイン、IMDS トークンの窃取
  • マネージド ID またはサービスプリンシパルの悪用 — アプリや VM 用に発行されたトークンが、本来現れるはずのない場所から使われている
  • 暗号通貨マイニング用 VM — 予期しない支出の急増、GPU/大規模 SKU、または運用していないリージョンへの新たなデプロイ
  • ストレージアカウントまたは Key Vault からの窃取 — キーの再生成、SAS トークンの発行、パブリックアクセス設定の変更、ディスクスナップショットの共有、シークレットのダンプ

使用しない場面

  • 侵害対象が Azure リソースではなく、Entra ID/M365 メールボックスである場合(ただし、両方の調査が必要になることはよくあります)— investigating-m365-entra を使用してください
  • インシデントが AWS で発生している場合 — investigating-aws-incidents を使用してください
  • インシデントが Google Cloud で発生している場合 — investigating-gcp-incidents を使用してください
  • 対応者ではなく、テナントに対する攻撃者である場合 — attacking-entra-id を使用してください
  • 調査対象が特に AKS/Kubernetes への侵入である場合 — attacking-eks-gke-aks を使用してください。クラスターを防御する場合は defending-kubernetes を使用してください
  • 一般的な IR プロセスとホストレベルの対応 — responding-to-incidents を使用してください

ログソースと保存場所

クエリを実行する前に、利用できるログを確認します。ログがないことも調査結果の一つであり、質問を省略する理由にはなりません。

ソーススコープ保持期間(デフォルト)記録される内容
Azure Activity Logサブスクリプションのコントロールプレーンエクスポートしない場合は 90 日ARM のすべての書き込み/アクション/削除:roleAssignments、runCommand、listKeys、デプロイ
リソース/診断ログリソースごとのデータプレーン有効化するまでなしBlob の読み取り、Key Vault の SecretGet、NSG フロー — 診断設定でワークスペースに送信した場合のみ
Log Analytics ワークスペースログの送信先ワークスペースの設定によるAzureActivity、AzureDiagnostics、StorageBlobLogs、AZKVAuditLogs テーブル
Entra サインイン/監査ログテナントの ID プレーン30 日(それ以上はエクスポート)SP/MI を認証したユーザー、アクセス元、CA/MFA のコンテキスト、資格情報の追加
Microsoft Sentinel取り込んだログの範囲テーブルごと上記すべてを対象とした相関分析、インシデント、ウォッチリスト

落とし穴: Activity Log はコントロールプレーンの記録です。Blob の読み取り、Key Vault シークレットの取得、Cosmos DB へのクエリなどのデータプレーン操作は、Activity Log にはまったく記録されません。インシデント発生前にそのリソースで診断設定が構成されていた場合にのみ記録されます。Activity Log に記録がないことは、データに手が加えられていない証拠にはなりません(「よくある合理化」も参照)。

ログの欠落を信用する前に、実際に何が記録されているかを確認します:az monitor diagnostic-settings subscription list(Activity Log は 90 日を超えてエクスポートされていますか?)および az monitor diagnostic-settings list --resource <id>(このストレージアカウント/Vault はデータプレーンログをどこかに送信していますか?)。

最初の1時間のトリアージ

3つの手順を順番に実施します。呼び出し元の ID を特定し、最近のアクティビティを取得してから、封じ込める前に証拠を保全します。

呼び出し元の ID を特定します。 Defender のアラート、課金の急増、不審なデプロイなどの報告を、Activity Log の caller / identity フィールドにある ID と照合します。このプリンシパル(UPN、またはサービスプリンシパル/マネージド ID のオブジェクト ID)が、以降の調査すべての起点になります。

# Everything a specific caller did across the subscription control plane
az monitor activity-log list --caller [email protected] \
  --start-time 2026-07-01T00:00:00Z -o json

# Who holds what right now -- role assignments are the escalation surface
az role assignment list --all --include-inherited \
  --query "[?roleDefinitionName=='Owner' || roleDefinitionName=='User Access Administrator']" -o table

Log Analytics ワークスペースがある場合は、KQL で最近のアクティビティを取得します。 最初の確認を終えた後は、CLI より高速で詳細な情報を得られます。

AzureActivity
| where TimeGenerated > ago(7d)
| where Caller == "[email protected]"
| project TimeGenerated, OperationNameValue, ActivityStatusValue,
    CallerIpAddress, ResourceProviderValue, ResourceId, CorrelationId
| order by TimeGenerated asc

保全してから封じ込めます。 操作の途中でロールの割り当てが取り消されたことに気付いた攻撃者は、まだ発見されていない永続化手段を使い切るおそれがあります。被害が現在進行中の場合を除き、まずディスクのスナップショットを作成し、関連するログをエクスポートして、永続化手段を洗い出してから、すべてを一斉に封じ込めます。ライブマイニングや進行中のデータ流出の場合は例外で、被害を止めることを優先し、そのためのトレードオフを受け入れます。

Activity Log の詳細調査(KQL)

AzureActivity テーブルは、コントロールプレーンの信頼できる記録です。次のフィールドを把握しておきましょう。

  • OperationNameValue -- ARM 操作です。例:Microsoft.Authorization/roleAssignments/write。これを基に調査します。
  • Caller -- 呼び出しを行った UPN またはオブジェクト ID です。
  • CallerIpAddress -- Azure 内からのみ呼び出すはずのマネージド ID に外部 IP が記録されている場合、IMDS の窃取を示す痕跡です(下記参照)。
  • ResourceProviderValue -- Microsoft.Compute、Microsoft.Storage、Microsoft.KeyVault、Microsoft.Authorization などです。
  • ActivityStatusValue -- Failure(多くの場合 AuthorizationFailed)が連続している場合は、盗まれたプリンシパルがアクセスできる範囲を攻撃者が調べていることを示します。
  • CorrelationId -- 1つの論理アクションに含まれるサブ操作を関連付けます。この ID を起点に調査することで、単一の不審なイベントを一連の動作全体へと展開できます。
// Enumeration storm -- authorization failures by operation
AzureActivity
| where TimeGenerated > ago(7d)
| where ActivityStatusValue == "Failure"
| summarize n = count() by Caller, OperationNameValue, CallerIpAddress
| order by n desc

// Expand one event's full correlated sequence
AzureActivity
| where CorrelationId == "<correlation-id>"
| project TimeGenerated, OperationNameValue, ActivityStatusValue, ResourceId
| order by TimeGenerated asc

攻撃者によく見られる操作の調査

タイムラインから、次の OperationNameValue パターンを検索します。Azure への侵入のほぼすべてに見られるパターンです。

  • ロール割り当てによる権限昇格 -- Microsoft.Authorization/roleAssignments/write によって Owner、Contributor、または User Access Administrator を付与する操作です(UAA はあらゆる権限を自らに付与できます)。無害そうな名前の背後に * アクションを隠した カスタムロールの作成(Microsoft.Authorization/roleDefinitions/write)にも注意してください。
  • サービスプリンシパルまたはアプリへの資格情報の追加 -- Activity Log ではなく Entra で実行されます。アプリ登録に新しいシークレットまたは証明書を追加すると、MFA に依存しない永続的なアクセスが可能になります。Entra の監査ログにある「Add service principal credentials」/「Update application - Certificates and secrets management」と関連付けて確認します。
  • マネージド ID トークンの悪用 -- 侵害された VM のシステム割り当て ID 用に発行されたトークンを使って ARM を呼び出します。予期しない CallerIpAddress からの呼び出しでは、マネージド ID のオブジェクト ID が Caller として記録されます。
  • VM でのコード実行 -- Microsoft.Compute/virtualMachines/runCommand/action と Custom Script Extension(Microsoft.Compute/virtualMachines/extensions/write で CustomScript をインストール)は、RDP/SSH を使わずに、攻撃者のコードを SYSTEM/root 権限で実行します。
  • コンピューティング/サーバーレスの永続化 -- Microsoft.Web/sites(App Service/Functions)、Automation の Runbooks、Logic Apps をスケジュール済みのバックドアとして使い、資格情報を再発行したり、ロールを再付与したりします。
  • リソース単位の RBAC バックドア -- サブスクリプション全体ではなく、特定のストレージアカウントやコンテナーに限定したロール割り当てです。全体レベルの確認では見落としやすい手口です。
AzureActivity
| where TimeGenerated > ago(14d)
| where OperationNameValue has_any (
    "roleAssignments/write", "roleDefinitions/write",
    "runCommand/action", "virtualMachines/extensions/write")
| project TimeGenerated, Caller, CallerIpAddress, OperationNameValue, ResourceId
| order by TimeGenerated asc

CLI で同じ操作を絞り込む場合は、次のようにします。 az monitor activity-log list --start-time <t> --query "[?contains(operationName.value,'roleAssignments/write')]"。

ID プレーンの相関分析

アクティビティログにはプリンシパル名は記録されますが、その背後にいる人間は記録されません。サービスプリンシパルまたはマネージド ID の オブジェクト ID を Entra に照合して、認証コンテキストを確認します。これがプレーンをまたぐ手順であり、通常は investigating-m365-entra を開くことになります。

// Where did this service principal / managed identity actually sign in from?
AADServicePrincipalSignInLogs
| where ServicePrincipalId == "<sp-or-mi-object-id>"
| where TimeGenerated > ago(30d)
| project TimeGenerated, AppId, ServicePrincipalName, IPAddress,
    ResourceDisplayName, ResultType
| order by TimeGenerated asc

// For an interactive user: sign-ins around the abusive Activity Log calls
SigninLogs
| where UserPrincipalName == "[email protected]"
| project TimeGenerated, IPAddress, Location, AppDisplayName,
    ConditionalAccessStatus, AuthenticationRequirement, ResultType

条件付きアクセスのステータスと、MFA が実際に満たされていたかを確認します。サービスプリンシパルは対話型 CA を完全に回避するため、攻撃者が SP/MI の認証情報に切り替えるのはまさにこのためです。

マネージド ID と SSRF による認証情報の窃取

AWS IMDS 窃取に相当する Azure の手口です。VM/App Service 上で SSRF または侵入の足がかりを得た攻撃者が、インスタンスメタデータサービスを読み取ってマネージド ID のトークンを取得し、別の場所で使用します。

http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/

兆候は明白です。マネージド ID による呼び出しが AzureActivity に記録されますが、その CallerIpAddress はリソース自身のアウトバウンド IP ではありません。トークンはそのリソース向けに発行されるため、無関係な IP または外部 IP からの呼び出しは、トークンがリソースの外に持ち出されたことを意味します。

AzureActivity
| where TimeGenerated > ago(7d)
| where Caller == "<managed-identity-object-id>"
| summarize ops = count() by CallerIpAddress, OperationNameValue
| order by ops desc     // flag IPs that are not the VM's egress

窃取された期間を、アウトバウンドの SSRF と再利用元を示す NSG フローログ(有効な場合)と照合します。App Service では、トークンエンドポイントに 169.254.169.254 ではなく、ヘッダーシークレットを伴う IDENTITY_ENDPOINT が使われます。リソース外での使用に関する考え方は同じです。

Defender for Cloud アラートのトリアージ

Defender for Cloud は調査の出発点であり、調査そのものではありません。各アラートが示す仮説を、アクティビティログと診断ログで確認します。

アラート(代表例)示唆
暗号通貨マイニング/Digital currency mining の挙動VM がマイニングプールと通信しています。デプロイ権限を持つプリンシパルが侵害されています。
異常なリソースのデプロイ/通常と異なる RunInstances 相当の操作攻撃者がコンピューティングリソースを起動しています。未使用のリージョンで行われることがよくあります。
不審なサインイン/Tor または既知の悪意ある IP からのアクセス盗まれたプリンシパルが攻撃者のインフラストラクチャから呼び出されました。
マネージド ID/メタデータ認証情報の流出上記の IMDS 窃取です。リソース外でのトークン使用を確認してください。
ストレージアカウント/Key Vault への異常な場所からのアクセス予期しない地域からのデータプレーンアクセスです。
az security alert list -o table
az security alert show --location <loc> -n <alert-name> -g <rg>

90 日間のアクティビティログ保持期間を過ぎたアラートにも、プリンシパルと IP アドレスは記録されています。生のイベントが保持期間切れで消えていても、それらを起点に調査してください。

データ窃取の検出

  • ストレージアカウントキーの再生成 — Microsoft.Storage/storageAccounts/listKeys/action と regenerateKey により、攻撃者は RBAC の適用外で使用でき、その後アクティビティログにも記録されないフルアクセスキーを取得します。
  • SAS トークンの発行 — listAccountSas/listServiceSas により、オブジェクトごとの制御プレーンの記録を残さない、期限付きのデータ流出用 URL が生成されます。
  • Blob の流出 — データプレーンの診断ログが有効な場合にのみ確認できます。StorageBlobLogs には呼び出し元ごとの GetBlob 件数が記録されます。
  • コンテナーのパブリックアクセス設定の変更 — コンテナーまたはアカウントで匿名アクセス/Blob のパブリックアクセスを許可する設定は、データ流出の準備を示します。
  • ディスクスナップショットのエクスポート/共有 — Microsoft.Compute/snapshots/write の後に /beginGetAccess/action を実行すると、ディスクイメージ全体をダウンロードするための SAS URL が発行されます。
  • Key Vault シークレットの一括取得 — Microsoft.KeyVault/vaults/read(VaultGet)で列挙し、続いてデータプレーンの SecretGet で読み取ります(ログが有効な場合に限り、AzureDiagnostics/AZKVAuditLogs に記録されます)。
// Control-plane data-theft indicators
AzureActivity
| where TimeGenerated > ago(14d)
| where OperationNameValue has_any (
    "storageAccounts/listKeys", "storageAccounts/regenerateKey",
    "listAccountSas", "listServiceSas",
    "snapshots/write", "snapshots/beginGetAccess")
| project TimeGenerated, Caller, CallerIpAddress, OperationNameValue, ResourceId

// Key Vault data-plane reads -- only present if diagnostics were on beforehand
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.KEYVAULT"
| where OperationName in ("SecretGet", "KeyGet", "VaultGet")
| project TimeGenerated, CallerIPAddress, identity_claim_upn_s, OperationName, id_s

攻撃者が試みるアンチフォレンジック

有能な攻撃者は、こちらの視界を遮ろうとします。調査すべき重要な操作と、その対策は次のとおりです。

  • 診断設定の削除 — Microsoft.Insights/diagnosticSettings/delete により、データプレーンのログがワークスペースに送信されなくなります。
  • アクティビティログのエクスポートの削除/範囲縮小 — アクティビティログをワークスペースまたはストレージに送信する、サブスクリプションレベルの診断設定を削除します。
  • リソースの削除 — VM、スナップショット、ストレージアカウントを削除し、証拠とそのログを破壊します。

対策の基本は AWS の組織トレイルと同じです。侵害されたプリンシパルがアクセスできない、テナントレベルでエクスポートする、ロックされた一元的な保存先を用意します。たとえば、不変ストレージ(WORM/法的保全)への Blob エクスポートや、削除保護とリソースロックを設定した分離ワークスペースへの Sentinel 取り込みが挙げられます。エクスポートが不変であれば、攻撃者自身による diagnosticSettings/delete の呼び出しは、設定に反映される前にそこへ記録されるため、痕跡を消そうとした行為自体が証拠となり、記録の欠落を防げます。これがない場合は、記録できない期間を調査範囲の制約として記録してください。

AzureActivity
| where TimeGenerated > ago(14d)
| where OperationNameValue has_any (
    "diagnosticSettings/delete", "Microsoft.Insights/diagnosticSettings/write")
| project TimeGenerated, Caller, CallerIpAddress, OperationNameValue, ResourceId

証拠の保全

  • 対象となる VM のディスクに手を加える前にスナップショットを作成し、削除できないようスナップショットをロックします。

    az snapshot create -g <rg> -n IR-2026-042-osdisk \
      --source <os-disk-id> --tags case=IR-2026-042 legal-hold=true
    az lock create --name IR-2026-042-hold --lock-type CanNotDelete \
      --resource-group <rg> --resource-name IR-2026-042-osdisk \
      --resource-type Microsoft.Compute/snapshots
    
  • 90 日間の保持期間が過ぎる前に、関連するアクティビティログの期間をエクスポートします。CLI/KQL を実行し、JSON を保全用のロックされたストアに保存します。

  • 証拠となるアーティファクトにリソースロック/法的保全を適用します。インシデントが規制対応や訴訟に発展する可能性がある場合は、収集前に法務部門に相談してください。

封じ込め

スコープを特定した後、すべてを一度に実施してください。部分的な封じ込めは攻撃者に警戒されます。

  • 侵害されたプリンシパルを無効化するか、資格情報をローテーションします。 サービスプリンシパル/アプリの場合は、無効化して資格情報をローテーションします。

    az ad sp update --id <app-id> --set accountEnabled=false
    # remove attacker-added secrets/certs
    az ad app credential reset --id <app-id>
    

    ユーザーの場合は、Entra でアカウントを無効化してパスワードのリセットを強制し、その後、セッションを取り消します(以下を参照)。

  • 攻撃者が付与したロール割り当てを取り消します。

    az role assignment delete --assignee <object-id> \
      --role Owner --scope /subscriptions/<sub-id>
    
  • セッション/更新トークンを取り消し、既存のトークンを無効化します(Entra での操作です。Revoke-MgUserSignInSession/az ad user ...)。無効化するだけでは、発行済みのトークンが最長 1 時間有効なままになるためです。

  • VM は削除せず、NSG をすべてのアウトバウンド通信を拒否するルールに切り替えて隔離します。これにより、分析用にディスクとメモリを保全できます(az network nsg rule create ... --access Deny --direction Outbound --protocol '*')。

  • ストレージキーをローテーションし、SAS を再生成します。両方のキーを更新すると、有効なすべての SAS とアクセスキーを一度に無効化できます。

    az storage account keys renew --account-name <acct> -g <rg> --key primary
    az storage account keys renew --account-name <acct> -g <rg> --key secondary
    
  • 攻撃者による永続化手段を除去します。バックドアとなる Functions/App Service、Automation のランブック、カスタムロール、リソーススコープのロール割り当ては、記録を取ってから削除します。

調査には Azure CLI と Log Analytics/Sentinel の KQL を使用します。攻撃者が実行する TTP と、各操作が残す痕跡を把握するには MicroBurst と ROADtools を、Azure での事案が M365 にまたがる場合は Microsoft の Unified Audit の相関分析を活用します。

棄却すべき誤った判断

  • 「アクティビティログに何も表示されないので、データには触れられていません。」 アクティビティログに記録されるのはコントロールプレーンのみです。BLOB の読み取り、シークレットの取得、DB クエリはデータプレーンの操作であり、事前に診断ログを有効にしていない限り確認できません。記録がないことは、データが持ち出されていない証拠にはなりません。
  • 「Defender for Cloud がアラートを出していないので、侵害はありません。」 Defender が対象とするのは一部の振る舞いであり、適切なプランとカバレッジが必要です。検出結果がないことは、侵害がない証拠にはなりません。アクティビティログのタイムラインが確かな情報源です。
  • 「ユーザーを無効化したので、アカウントは封じ込められています。」 発行済みのアクセストークンは最長 1 時間有効であり、攻撃者が作成したサービスプリンシパルの認証情報やロールの割り当ても、無効化後に残ります。セッションを取り消し、永続化の仕組みをすべて監査してください。
  • 「マネージド ID なので、Azure 内部からしか使用できません。」 それは設計上の想定であり、保証ではありません。SSRF/IMDS による窃取で、リソース外にトークンが持ち出されます。リソース外からの CallerIpAddress は、まさに調査すべき痕跡です。
  • 「サービスプリンシパルのロールは Contributor だけで、Owner ではありません。」 Contributor は VM で runCommand を実行し、ストレージキーを読み取り、SAS トークンを発行できます。ロールの割り当てに触れることなく、コードを実行してデータを窃取できます。そのロールが何にアクセスできるかを追跡し、思い込みで判断しないでください。
  • 「ただの暗号資産マイニングなので、優先度は低いです。」 マイニングが行われているなら、デプロイ権限を持つプリンシパルが侵害されています。同じアクセス権でデータを持ち出したり、roleAssignments/write を通じて権限を昇格したりできた可能性があります。マイニングは目に見える症状にすぎず、侵害の範囲そのものではありません。
  • 「ログの保持期間は 90 日なので、侵害は 90 日以内に始まったはずです。」 それはアクティビティログの既定の保持期間であり、攻撃者の活動期間ではなく、あなたの可視性の限界です。調査範囲の制約として記録し、より長く保持されているワークスペース/イミュータブルエクスポートを確認してください。

参考資料

  • investigating-m365-entra -- ID プレーンを扱う関連スキル。SP/MI と Entra のサインインおよび監査ログを関連付けるために開いてください
  • investigating-aws-incidents -- インシデントが AWS で発生した場合に使う、関連するクラウド IR スキル
  • attacking-entra-id -- 攻撃者側の視点。このテナント/サブスクリプションの TTP がどのように実行されるかを解説します
  • attacking-eks-gke-aks -- ピボット先が特に AKS/Kubernetes の場合に使用します
  • responding-to-incidents -- 一般的な IR プロセス、証拠の取り扱い、ホストレベルの対応
  • reporting-security-findings -- インシデントの説明と成果物の構成
  • Azure CLI (az) -- コントロールプレーンを操作し、アクティビティログを取得します
  • Log Analytics/Microsoft Sentinel の KQL -- AzureActivity、AzureDiagnostics、サインインテーブルをクエリします
  • Microsoft Defender for Cloud -- アラートの情報源および検出結果の種類に関するリファレンス
  • MicroBurst と ROADtools -- Azure/Entra の攻撃 TTP をエミュレートして理解し、それぞれがログに残す痕跡を確認します

コメント