【PR】本記事には、書籍『Project Zero Trust』のアフィリエイトリンク(Amazon)を含みます。
本記事で触れる連載Vol.5の場面やディランの台詞の描写は、George Finney『Project Zero Trust』(Wiley、2022年)を手がかりに運営者が脚色したもので、本の原文の引用ではありません。
連載『Project Zero Trust』Vol.5(書籍の第7章「Zero Trust SOC」をもとにした当サイトの翻案)では、主人公ディランが「数億行のログの洪水」から脱却し、「本当に見るべき3つの指標」に絞り込む様子を描きました。
Vol.5の物語そのものは、【物語連載】Vol.5 運用編:見えないものは守れないで読めます。
- Identity Risk(アイデンティティのリスク)
- Privileged Access(特権IDの動き)
- Lateral Movement(内部での感染拡大)
「概念はわかった。でも、Azure(Microsoft Sentinel)でそれをどう書けばいいの?」
今回はそんな現場のエンジニアのために、Sentinelで試すためのKQL(Kusto Query Language)のクエリ例を用意しました。テーブルの列名や条件は、環境に合わせて調整が必要な場合があります。
なお、Microsoft Sentinel は2027年3月31日以降、Azure portal ではサポートされなくなり、Microsoft Defender ポータルでのみ使用できるようになる予定です(Microsoft Learn、Microsoft Sentinel のブックの解説)。
この記事は『Project Zero Trust』特集の一部です。全記事一覧はこちら↓
前提条件:ログの蛇口を開く

このクエリを実行するためには、以下のログがMicrosoft Sentinelに取り込まれている必要があります。
これらが「データコネクタ」設定でONになっていれば準備完了です。
1. Identity Risk:そのログイン、本人ですか?

ディランが最初に固めたのは「ID」です。ここでは「ブルートフォース(総当たり)」攻撃の兆候を捉えます。
「何度も失敗した後に、ようやく成功した」というパターンには、主な可能性として、正規ユーザーがパスワードを忘れただけの場合と、攻撃者が突破した場合が考えられます。
なお、多数のアカウントに少しずつパスワードを試す「パスワードスプレー」は、アカウントロックやパスワード誤りの閾値に届かない「Low and slow」型で行われることがあります(Microsoft Learn、パスワード スプレー調査のインシデント対応プレイブック)。1ユーザー×1IP×1アプリの失敗回数を数える次のクエリでは拾いにくいため、別の観点(1つのIPから失敗した宛先ユーザーの数など)での確認が必要です。
🛠 再現クエリ (KQL)
// 過去1時間に、同じユーザー・同じIP・同じアプリへのサインイン失敗が5回以上あり、
// その最後の失敗より後にサインインに成功したユーザー(ブルートフォース成功の疑い)
// ※ResultType が "0" 以外の失敗には、パスワード誤り以外(MFA要求など)も含まれる
let timeRange = 1h;
let failureThreshold = 5;
SigninLogs
| where TimeGenerated > ago(timeRange)
| where ResultType != "0" // 失敗(パスワード誤り以外も含む)
| summarize FailureCount = count(), LastFailure = max(TimeGenerated)
by UserPrincipalName, FailureIP = IPAddress, AppDisplayName
| where FailureCount >= failureThreshold
| join kind=inner (
SigninLogs
| where TimeGenerated > ago(timeRange)
| where ResultType == "0" // 成功のみ抽出
| project UserPrincipalName, SuccessTime = TimeGenerated, SuccessIP = IPAddress
) on UserPrincipalName
| where SuccessTime > LastFailure // 最後の失敗より後の成功だけに絞る
| project UserPrincipalName, AppDisplayName, FailureCount, FailureIP, LastFailure, SuccessIP, SuccessTime
| order by SuccessTime desc
解説:
このリストに載ったユーザーには、本人に確認を入れ、不正なサインインが疑われる場合は、パスワードの変更やユーザーのブロックを検討します(Microsoft Learn、パスワード スプレー調査のインシデント対応プレイブック)。1つの失敗のまとまりに複数の成功が結び付くと、同じユーザーの行が複数表示されます。
2. Privileged Access:王冠の鍵を守れ

「ドメイン管理者(Domain Admins)」や「グローバル管理者(Global Administrator)」は、攻撃者が喉から手が出るほど欲しい特権です。
特権グループのメンバーの変更は、通常の運用ではそう多くなく、承認済みのものに限るべきです(PIM でロールを有効化する運用では、有効化の記録は日常的に残ります)。
🛠 再現クエリ (KQL)
Entra ID (Azure AD) の監査ログから、Microsoft Entra ID のすべての面を管理できる最上位の権限である「Global Administrator」へのメンバー追加を抽出します。
// "Global Administrator" ロールへのメンバー追加を抽出(過去24時間)
// ※正規の割り当ても表示されるため、承認済みの変更かを確かめる
// ※PIM 経由の割り当ても Identity 列が MS-PIM として記録されることがある。PIM 以外の割り当てだけを見たい場合は Identity 列で除外する(Microsoft の Sentinel 分析ルールと同じ考え方)
// ※modifiedProperties の項目名(Role.DisplayName)は Microsoft Learn のテーブル定義に記載がないため、
// 実際のログで確かめ、環境に合わせて調整が必要
AuditLogs
| where TimeGenerated > ago(24h)
| where OperationName == "Add member to role"
| where Result == "success"
| mv-expand Target = TargetResources
| mv-apply Prop = Target.modifiedProperties on (
where tostring(Prop.displayName) == "Role.DisplayName"
| extend RoleName = tostring(Prop.newValue) // ロール名抽出(添字の位置に頼らない)
)
// "Company Administrator" は記録される名称の候補として併記(実際のログで要確認)
| where RoleName contains "Global Administrator" or RoleName contains "Company Administrator"
| project TimeGenerated, Actor = Identity, ActorUPN = tostring(InitiatedBy.user.userPrincipalName),
AddedUser = tostring(Target.userPrincipalName), RoleName
解説:
このクエリは正規の割り当ても拾います。ヒットしたら、それが承認済みの変更かを必ず確かめてください。承認のない追加であれば、「誰かが勝手に神の権限を手に入れた」おそれがあります。ディランなら、この検知と同時に管理者のスマホへ電話をかけるでしょう。
3. Lateral Movement:横移動を許すな

「クライアントPC同士の直接通信」は、多くの環境で業務上は不要なため、監視の対象になります。
経理部のPCが、人事部のPCに接続しに行っている……それはマルウェアが感染拡大(ラテラルムーブメント)を狙っている兆候かもしれません。
🛠 再現クエリ (KQL)
Windowsイベントログ(4624: ログオン成功)から、クライアントPCへのネットワーク経由のログオンを探します。
// クライアントPCへのネットワーク経由のログオン(Logon Type 3 = Network)を抽出
// ※クライアントPCの見分け方(ここではホスト名の命名規則)は環境に合わせて調整が必要
// ※Kerberos のネットワークログオンでは WorkstationName が空のことがあるため、送信元IPも表示する
SecurityEvent
| where TimeGenerated > ago(1h)
| where EventID == 4624
| where LogonType == 3 // ネットワーク経由のログオン
| where AccountType == "User"
// 宛先をクライアントPCに絞る(例:ホスト名が "PC-" で始まる。自社の命名規則に合わせて変更)
| where Computer startswith "PC-"
// 命名規則で絞れない場合は、本来アクセスされるファイルサーバー等を宛先のホスト名で除外する
// | where Computer !in ("FileServer01.corp.local", "PrintServer.corp.local")
| project TimeGenerated, SourceWorkstation = WorkstationName, SourceIP = IpAddress, TargetComputer = Computer, Account
解説:
「PCからサーバー」への通信は通常の業務で発生します。「PCからPC」へのネットワークログオンには、ファイル共有や印刷などの正規の通信もありますが、管理用ツール以外で見つかったものは調べるべき兆候です。このクエリで想定外の接続が見つかったら、対象端末のネットワーク隔離(Isolation)を検討してください。
まとめ:可視化こそが「武器」だ

書籍『Project Zero Trust』の翻案として、運営者がこの記事のために書いたディランの台詞で締めくくります(本の原文の引用ではありません)。
「見えない敵とは戦えない。だから、まずは電気をつける(可視化する)んだ」
今回紹介した3つのクエリは、Sentinelの「ブック(Workbook)」でも使えます。ブックでクエリを使うには、データソースを「Logs」、リソースタイプを「Log Analytics」に設定し、ワークスペースを選びます(Microsoft Learn、Microsoft Sentinel のブックの解説)。各クエリは表を返すだけなので、グラフにする場合は表示形式の選択や時間ごとの集計などの調整が必要です。
SOCサービスを契約していなくても(費用がかからないという意味ではありませんが)、「今日、自社のネットワークで何が起きているか」を知る手がかりは得られます。
ぜひ、列名や条件を環境に合わせて調整したうえで、あなたのSentinelで実行してみてください。
もし「何も出ない(0件)」なら、それは平和な証拠……あるいは、まだログが取れていないだけかもしれません。
👉『Project Zero Trust』特集トップへ戻る
最終更新:2026年10月1日(公的資料・一次情報に基づき事実関係を修正)


