IRQL -- インシデント対応クエリ言語
セレクター、抽出子、エンリッチャーのビルディングブロックからIRQL関数パイプラインを作成します。IRQLは、生のKQLセキュリティテーブルを、意図が明らかで構成可能な関数でラップすることで、アナリスト(およびLLM)がスキーマ、クラスタの場所、結合キーを覚えなくてもハントを記述できるようにします。
アクティベーション条件
このスキルは、ユーザーが次のことを行った場合に使用します。
- IRQL、
Get_*、Extract_*、Enrich_*関数を明示的に言及した場合 - 「IRQLを使う」または「IRQLクエリを書く」と言った場合
- 既知のIRQLセレクターを使用した構成可能なハンティングパイプラインを要求した場合
ユーザーが明示的にIRQLを要求しない限り、一般的なセキュリティクエリ(例:「失敗したログインを検索」)ではアクティブにしないでください。そのようなクエリはazure-kustoにルーティングしてください。
自然言語からIRQLへの変換機能ではありません。 このスキルはIRQL関数パイプラインを作成し、既知のセレクターと単純なフィルターに直接マッピングできる基本的な自然言語要求を処理する場合があります。一般的なNL-to-KQLまたはNL-to-IRQL変換には、専用のクエリ生成スキル(別途利用可能)を使用してください。
IRQL関数の事前確認
パイプラインを生成する前に、ターゲットデータベースでIRQLが利用可能であることを確認します。
.show functions
| where Name startswith "Get_" or Name startswith "Extract_" or Name startswith "Enrich_"
| project Name
IRQL関数が見つからない場合は、ターゲットデータベースにIRQLがデプロイされていないことをユーザーに通知し、代わりに生のKQLクエリにはazure-kustoを使用することを提案します。IRQL関数は前提条件です -- このスキルはベースIRQLセレクターをデプロイしません。
IRQLとは
IRQLはKQL上に構築された関数ベースの言語です。以下を提供します。
- 統一スキーマ -- 異種のセキュリティテーブルを、基盤となるデータソースに関係なく一貫した列名に投影します。
- 構成可能性 -- 小さな関数を
| invokeで連鎖させて、簡単なステップから複雑なハントを構築します。 - 移植性 -- 同じIRQLパイプラインが異なるクラスタ/データベースで動作します。
Get_*プリミティブのみ再ポイントする必要があります。
IRQLは別の言語ではありません。呼び出すKQL関数です。有効なKQLは、IRQL関数と一緒に使用できます。
IRQLのデプロイ
IRQL関数は、保存されたKQL関数(.create-or-alter function)です。このスキルがパイプラインを生成する前に、ターゲットデータベースにデプロイされている必要があります。
公開サンプルクラスタ(関数は事前デプロイ済み):
- クラスタ:
https://kc7001.eastus.kusto.windows.net - データベース:
ValdyTimes、JoJosHospital
IRQLを新しいクラスタ/データベースに移植するには、ソーステーブルを統一スキーマ(以下の列名)に投影するGet_*セレクターを作成し、抽出子とエンリッチャーをデプロイします。入力スキーマが一致していれば、抽出子とエンリッチャーは変更せずに動作します。
関数カタログ
1. セレクター -- Get_*
ソーステーブルの投影された、スキーマ統一ビューを返します。デフォルトでは最小限の形式を使用し、追加の列が必要な場合は_Allを使用します。
| 関数 | 列 |
|---|---|
Get_Event_Authentication | EnvTime, Hostname, ClientIp, Username, Result |
Get_Event_Authentication_All | + Description, UserAgent, PasswordHash |
Get_Email | EnvTime, EmailSender, EmailRecipient, Subject, Url |
Get_Email_All | + ReplyTo, Verdict |
Get_Employees | Name, ClientIp, Email, Username, Hostname, Role |
Get_Employees_All | + HireDate, UserAgent, Domain |
Get_Event_FileCreation | EnvTime, Hostname, Filename, Path |
Get_Event_FileCreation_All | + Username, Sha256, ProcessName |
Get_Event_NetworkInbound | EnvTime, ClientIp, Url |
Get_Event_NetworkInbound_All | + Method, UserAgent, StatusCode |
Get_Event_NetworkOutbound | EnvTime, ClientIp, Url |
Get_Event_NetworkOutbound_All | + Method, UserAgent |
Get_Dns_All | EnvTime, Domain, ClientIp |
Get_Event_Process | EnvTime, ProcessCommandLine, ProcessName, Hostname, Username |
Get_Event_Process_All | + ParentProcessName, ParentProcessHash, ProcessHash |
Get_SecurityAlerts_All | EnvTime, AlertType, Severity, Description, Indicators |
Get_Network_Connection_All | EnvTime, SourceIp, SourcePort, DestinationIp, DestinationPort, Protocol, Bytes |
2. 抽出子 -- Extract_*
既存の列から新しい列を導出します。セレクターの後に呼び出します。
| 関数 | 入力列 | 追加される列 |
|---|---|---|
Extract_Email_Sender_Domain(T) | EmailSender | Domain |
Extract_Employee_Firstname(T) | Name | Firstname |
Extract_Event_Network_Domain(T) | Url | DomainName |
3. エンリッチャー -- Enrich_*
関連テーブルからコンテキストを付加する左外部結合ヘルパー。
| 関数 | キー列 | エンリッチ対象 |
|---|---|---|
Enrich_Event_Authentication_Username(T) | Username | ユーザーの認証イベント |
Enrich_Ip_Employee(T) | ClientIp | IPからの従業員情報 |
Enrich_Username_Employee(T) | Username | ユーザー名からの従業員情報 |
Enrich_Ip_Domain(T) | ClientIp | IPに解決されたDNSドメイン |
Enrich_Ip_Event_NetworkOutbound(T) | ClientIp | IPからの送信ネットワーク |
Enrich_Ip_Network_Connection(T) | ClientIp | IPからのネットワークフロー |
4. 外部エンリッチメント
| 関数 | ソース | 要件 |
|---|---|---|
Enrich_Sha256_VirusTotal(T) | VirusTotalファイルレポート | APIキー + コールアウトポリシー |
Get_CISA_KEV() / Enrich_CISA_KEV(T) | CISA KEVカタログ | コールアウトポリシー |
構成ルール
セレクター -> 抽出 -> フィルター -> エンリッチ -> 集計/射影
- セレクターから開始:
Get_Event_Authentication、Get_Emailなど。 - 導出フィールドを抽出:
| invoke Extract_Email_Sender_Domain() - シグナルにフィルター:
| where Result == "Failed Login" - コンテキストでエンリッチ:
| invoke Enrich_Username_Employee() - 回答を集計/射影
常にパイプ(|)でステップを接続します。抽出子とエンリッチャーは| invoke FunctionName()を使用します。
クエリ生成ガイドライン
- 追加の列が必要な場合を除き最小限のセレクターを使用 -> 必要に応じて
_All - 抽出子をエンリッチャーの前に連鎖させる(抽出子はエンリッチャーがキーとする可能性のある列を追加します)
whereフィルターは可能な限り早い段階に配置- 集計には
summarize、最終的な列選択にはprojectを使用 order by+takeで出力を制限して終了
例
追加のプロンプトと詳細な例については、references/EXAMPLES.mdを参照してください。
ブルートフォース検出
Get_Event_Authentication
| where Result == "Failed Login"
| summarize FailedCount = count() by Username
| where FailedCount > 19
| invoke Enrich_Username_Employee()
| project Username, Name, Role, Email, FailedCount
| order by FailedCount desc
受信者の役職に基づくフィッシングトリアージ
Get_Email
| invoke Extract_Email_Sender_Domain()
| project EnvTime, EmailSender, Domain, Username = EmailRecipient, Subject, Url
| invoke Enrich_Username_Employee()
| extend Seniority = case(
Role has_any ("CEO", "Chief", "Director", "VP", "President"), 3,
Role has_any ("Manager", "Lead", "Senior"), 2,
1)
| summarize
TotalEmails = count(),
SeniorityScore = sum(Seniority),
Recipients = make_set(Name, 50),
DistinctRecipients = dcount(Username)
by Domain
| where DistinctRecipients >= 2
| order by SeniorityScore desc
| take 20
侵害指標からのポストエクスプロイテーションピボット
let victims =
Get_Event_FileCreation_All
| where Filename has "<INDICATOR>"
| distinct Hostname;
Get_Event_Process
| where Hostname in (victims)
| where ProcessCommandLine has_any ("rundll32", "regsvr32", "powershell", "systeminfo")
| project EnvTime, Hostname, Username, ProcessName, ProcessCommandLine
| order by EnvTime asc
ID情報でエンリッチした不審な送信トラフィック
Get_Event_NetworkOutbound
| invoke Extract_Event_Network_Domain()
| where DomainName has_any ("<SUSPICIOUS_DOMAIN_1>", "<SUSPICIOUS_DOMAIN_2>")
| invoke Enrich_Ip_Employee()
| project EnvTime, Name, Role, DomainName, Url, ClientIp
| order by EnvTime desc
外部IP認証の異常
Get_Event_Authentication_All
| where not(ClientIp startswith "10.") and not(ClientIp startswith "192.168.")
| summarize
Attempts = count(),
Failures = countif(Result == "Failed Login"),
Users = make_set(Username)
by ClientIp
| order by Failures desc
| take 20
使用されるMCPツール
| ツール | 目的 |
|---|---|
kusto_query | Kustoデータベースに対してIRQLパイプラインを実行 |
kusto_table_schema_get | 利用可能なテーブルと列を発見 |
kusto_cluster_list | 利用可能なADXクラスタを一覧表示 |
kusto_database_list | クラスタ内のデータベースを一覧表示 |
Kusto Explorerでクエリを開く(Windowsのみ)
オプションの便利機能です。 デフォルトのワークフローは、チャットに完全なKQLを出力し、ユーザーが手動でKusto ExplorerまたはVS Code Kusto拡張機能にコピーできるようにすることです。自動起動はオプトインのみです。
常にチャット応答で完全なKQLクエリを出力し、ステップ1(接続)とステップ2(クエリ)を明確にラベル付けします。
// ステップ1: クラスタに接続(既に接続済みの場合はスキップ)
// 例: KC7トレーニングクラスタに接続するにはコメントを解除
// #connect cluster('kc7001.eastus.kusto.windows.net').database('ValdyTimes')
// または独自のクラスタに置き換え:
// #connect cluster('<YOUR_CLUSTER>').database('<YOUR_DATABASE>')
// ステップ2: 以下のクエリを実行
<KQL_QUERY>
ユーザーがKusto Explorerに保存または開くように要求した場合は、references/KUSTO_EXPLORER_LAUNCH.mdの手順に従います。主要なルール:
- ファイルを書き込んだり実行可能ファイルを起動する前に
ask_userを使用して確認します - ファイルの内容をチャットに表示して、ユーザーが開く前に確認できるようにします
- シェル補間やヒアドキュメントは使用しないでください -- ファイルは
Set-Content/Add-Contentで書き込みます - クエリをブラウザのURLにエンコードしないでください
- macOS/Linuxでは、
.kqlファイルを保存し、VS Code Kusto拡張機能またはADX Web Explorerを提案します - IRQLデータからのグラフ可視化については、
azure-kusto-graphおよびazure-kusto-irql-graphを参照してください