こんにちは。Microsoft Sentinel を使用して脅威情報の調査・研究を行っている安藤です。
Microsoft Sentinel では KQL(Kusto Query Language)と呼ばれるクエリ言語を使用して検出ルールを設定することができますが、SOAR(Security Orchestration Automation and Response)での実装を考慮せずに検出ルールを作成した場合、予期しない結果を生むことがあります。
本記事では、SOAR を意識した Microsoft Sentinel ルールの記載方法についてご紹介します。
目次
Microsoft Sentinel とは
Microsoft Sentinel とはクラウドネイティブ SIEM(Security Information and Event Management)で、Microsoft 365 をはじめとした Microsoft 社サービスのセキュリティログ分析の他、外部からログを取り込み検出ルールに従った自動処理を実装することができます。
Microsoft Sentinel の検出ルールでは KQL と呼ばれるクエリ言語を使用します。以下に例を示します。
これは Microsoft Entra ID のサインインログの中から直近5分間に Microsoft Sentinel へ保管されたログを抽出するルールです。この後の説明のために例の中で使用している KQL クエリを説明します。
KQL クエリ例 | 意味/説明 |
---|---|
SigninLogs | Microsoft Entra ID のサインインログが保存されているテーブル。 |
where | Where 句と呼ばれる演算子でその後に続く条件に従って指定されたテーブル内のログをフィルタリングする。 |
TimeGenerated | Microsoft Entra ID のサインインログに含まれるタイムスタンプ。UTC で記録され、KQL クエリ上でも UTC で取り扱う必要がある点に注意。 |
ago(24h) または ago(5m) | 括弧内に含まれる文字列(timespan型)に従って KQL クエリ実行時点から前に遡った時刻を返す関数。 |
ingestion_time() | Microsoft Entra ID のサインインログが Microsoft Sentinel へ格納された時刻を表すタイムスタンプ。 |
where TimeGenerated >= ago(24h) | “TimeGenerated”というフィールドが”ago(24h)”が出力した時刻以降であるという条件。 |
where ingestion_time() >= ago(5m) | “ingestion_time()”が出力した時刻が”ago(5m)”が出力した時刻以降であるという条件。 |
例示したルールでは“TimeGenerated”と”ingestion_time()”という2つの条件を使用して、Microsoft Entra ID のサインインログをフィルタリングしています。何故2つの条件を使用しているかについては以下のブログで詳しく説明されています。
Handling ingestion delay in Azure Sentinel scheduled alert rules – Microsoft Community Hub
極端な例で説明すると、Microsoft Entra ID の障害によって、サインインログが実際のサインイン発生から約20時間遅延して Microsoft Sentinel に取り込まれたとします。その場合、“TimeGenerated”と“ingestion_time()”はそれぞれ以下のようになります。
KQL クエリ | 値 |
---|---|
TimeGenerated | サインインの発生時刻(時刻 X) |
ingestion_time() | サインインの発生時刻から20時間後(時刻 X+20) |
ここで Microsoft Sentinel の検出ルールが以下の場合はどのようになるでしょうか?
この場合、遅延したログは評価されません。この検出ルールが時刻 X 付近で実行されたとしてもその時点ではログが遅延しているため存在しません。また時刻 X+20付近で実行されたとしても“TimeGenerated”の値は20時間前となりますので、ルールでの評価時点から5分前までの条件によってフィルタリングされてしまい、存在しないことになってしまいます。こういった事態を防ぐためにログの格納時刻を表す“ingestion_time()”も使ってフィルタリングを行っています。
Microsoft Sentinel での SOAR(Azure Logic App)とは
Microsoft Sentinel では検出ルールを設定した後に行う処理を自動化する SOAR の機能を有しています。SOAR は“オートメーションルール”というものを使用して Azure Logic App のトリガーを呼び出す動作方式を採ります。
オートメーションルールの作成は手動でも行えますが、テンプレートを使用することも可能です。テンプレートを使用することで、対応する Azure Logic App が自動的に作成されます。
多くの場合、テンプレートで作成した Azure Logic App に対して検出したセキュリティイベントの情報を渡す場合、“エンティティ”と呼ばれる機能を使用します。これは検出ルールで設定できるもので、あらかじめ用意されたエンティティ変数に対してログテーブルの値を代入するようなイメージとなります。例えば以下は“IP”というカテゴリの“Address”というエンティティ変数の中に、Microsoft Entra ID のログに含まれる“IPAddress”という情報を入れる設定値となります。
このように設定することによって検出後のイベントにエンティティとして記録されることになります。
Azure Logic App からは、これらのエンティティを取得することができるビルトインアクション(=処理)が定義されており、簡単に取り扱うことができるようになっています。
しかし、テンプレートを使用せずに自組織にあわせて SOAR の実装を行う場合、エンティティを使用することで困るケースが出てきます。
例えば
- 検出ルールによって出力される件数が多く、エンティティが100件以上含まれる可能性がある
- あらかじめ用意されているエンティティカテゴリには存在しない情報種別を SOAR で処理したい
- 各要素だけでなく検出したログ全体をもって自動処理させたい
などです。2番目に関してはカスタムエンティティとしてビルトインカテゴリに含まれない任意のエンティティ変数を作成することもできますが、エンティティを使用しない場合は SOAR の中で“検出した内容そのもの”を取得したい状況が出てきます。
特定の IP アドレスだけが知りたいわけではなく、どの IP がどのアカウントに対して何件程度、何分間隔でアクセスしてきているのかを通知したい、などはエンティティだけでは対応しきれません。
ここで注意が必要なのは、Microsoft Sentinel ではルールによって検出されたイベントの内容を直接的に Azure Logic App へ連携する方法がエンティティを除くと存在しないということです。そのため、このような場合は Azure Logic App 上で検出ルールと同じ条件でログをフィルタリングする必要が出てきます。
幸いなことに Azure Logic App には Microsoft Sentinel の検出ルールを読み取り、KQL クエリを実行してログを出力させるビルトインアクションが用意されています。以下のように設定した場合、検出したルールで記述されている KQL クエリがそのまま Azure Logic App 上でも実行されて条件にヒットしたセキュリティイベントを抽出することができます。
実行することで以下のようにサインインログを取得することができます。
SOAR は必ずしもリアルタイム実行ではない
ここまでで Microsoft Sentinel と Azure Logic App を使用した SOAR の実装について記載してきましたが、これ以降の内容についてはここまでの知識が前提となります。不明な点についてはこれまでの内容をご確認いただきながら読み進めてください。
SOAR では自動的に処理させる方法もあれば半自動的に処理させる方法もあります。承認フローを処理途中に挟んだ場合、セキュリティイベントの検出から処理が完了するまでの時間差が生まれます。また、SOAR の実装不備などによって処理が失敗した場合、実装不備の修正後に再実行するケースもあります。
このようにセキュリティイベント発生から Azure Logic App によって KQL クエリを実行する時間が離れていると、ルールで検出したセキュリティイベントと Azure Logic App で処理するイベントが異なる場合があります。先ほどの KQL クエリで考えてみましょう。
Microsoft Entra ID のサインインログで不審なサインインを検出し、Azure Logic App によって半自動的な処理が実行されたとします。ここでいう半自動的な処理は、検出されたイベントに関連するユーザー(ユーザー A)に承認フローを回し、本人に覚えがなければユーザーアカウントを一時的に停止するものとします。
承認フローの中ではイベントに関連するユーザー宛に『いつ』『どこで』『何に対して』サインインをしたかを通知します。そのため、エンティティではなく Azure Logic App での KQL クエリで情報を取得することが望ましいです。
ではこの時、承認フローの途中で別のユーザー(ユーザー B)で不審なサインインが検出されたとします。
このユーザー B は不審なセキュリティイベントに覚えがあり、承認フローで不承認とすることで、アカウント停止を避けようとしています。しかし、実装によっては以下のような処理となる場合があります。
これは不審なセキュリティイベント①に紐づいて実行された SOAR が、本来イベントに紐づいていないユーザー B のイベントも対象としてしまうために起こります。では何故このようなことが起きたのでしょうか。
今回検出ルールの例として以下を例にあげました。
こちらの KQL クエリでは検出ルール実行時から過去5分間に発生したサインインログを対象とするものですが、実は検出ルール実行時点よりも後に格納されたサインインログも対象としています。
不審なセキュリティイベント①、②の検出時刻、つまり検出ルールの実行時刻と、承認フローにおいてユーザー A、B が応答した時刻を以下とします。
項目 | 値 |
---|---|
不審なセキュリティイベント①の検出ルール実行時刻 | 時刻 Y |
ユーザー A の承認フロー応答時刻 (不審なセキュリティイベント①から2時間後) |
時刻 Y+2 |
不審なセキュリティイベント②の検出ルール実行時刻 (不審なセキュリティイベント①から1時間後) |
時刻 Y+1 |
ユーザー B の承認フロー応答時刻 (不審なセキュリティイベント①から3時間後) |
時刻 Y+3 |
これらを図示すると以下のようになります。ユーザー A が覚えのないサインインであるとしてユーザーアカウントの一時的に停止することを承認したとします。承認後(時刻 Y+2)に KQL を実行して停止するユーザーアカウントの情報を取得する実装としていた場合、本来であれば以下の図中『5分間①』のイベントを対象にしたいところ、『5分間+α』のイベントも含まれて出力されます。
つまりユーザー A が承認することによって、不審なセキュリティイベント②も対象とも含まれてしまい、不承認とするはずだったユーザー B も同時にユーザーアカウントが停止してしまうことになります。
SOAR を意識したルールの記載方法
前章の事象を防ぐには、SOAR 内で使用する情報を検出直後に取得して承認時まで保持しておくか、あるいは KQL クエリを工夫する必要があります。
例示したケースでは『5分間①』の箇所のみを参照する必要がありました。この場合、KQL クエリのタイムスタンプに関連する条件式の下限だけでなく、上限を設定する必要があります。つまり、以下のように記述する必要があります。
SigninLogs
| where TimeGenerated >= ago(24h) and TimeGenerated < datetime(時刻Y)
| where ingestion_time() >= ago(5m) and ingestion_time() < datetime(時刻Y)
当然不審なセキュリティイベント②においては時刻 Y でなく時刻 Y+1とする必要があるため、これらは固定して設定することはできません。ここで上限として使用することができるのが“now()”という関数です。具体的には以下のような KQL クエリとなります。
SigninLogs
| where TimeGenerated >= ago(24h) and TimeGenerated < now()
| where ingestion_time() >= ago(5m) and ingestion_time() < now()
“now()”は文字通り“クエリ実行時点”を表す関数ですが、実は“クエリ実行時点”はルールによって検出される際、暗黙的に以下のクエリで変数として自動的に設定されています。以下は“クエリ実行時点”を2023年11月28日5時28分(UTC)(記事執筆時点)として設定している例です。
検出ルールが評価される際、このクエリが自動的に含まれて“クエリ実行時点”が定義されます。ではこのクエリが Azure Logic App に対して渡されるとどのような動きになるのでしょうか。図示すると以下のようになります。
このように時間が経過したとして Y+2時点で KQL クエリを実行したとしても、タイムスタンプの上限がルールで検出した時刻である“now()”によっておさえられているため、以下の『5分間①』のイベントのみを対象とすることができ、ユーザー B を巻き込むことはありません。
※勘の良い方はお気づきかと思いますが、実は“ago(5m)”も“クエリ実行時点”に基づいて計算されます。
まとめ
ここまでお読みいただきありがとうございます。本記事では SOAR を意識した Microsoft Sentinel ルールについてご紹介しました。今後も Microsoft Sentinel に関する記事を記載していきますので、良ければご覧ください。
また、当社では Microsoft Sentinel による自動監視と、セキュリティ専門アナリストによる有人調査を組み合わせたサービス「MSS for Microsoft Sentinel」をご提供していますので、ご興味のある方はぜひ下記からお問い合わせください。
関連ページ |