Elastic Securityで始める検知エンジニアリング — KQLでログを読んで最初のルールを作る(第2回)

BLOG

ログを読まずにルールは作れません。前回に続いて今回はDiscoverでイベントの中身を確認しながら、「ログイン失敗を検知する」最初のルールを正しい条件で作ります。ルール作成前にDiscoverで確認する習慣が、後々の誤検知を防ぐ最大のポイントです。

※本シリーズで使用するデータセットは、第1回の記事からダウンロードできます。


この記事を読むと何ができるか

  • event.outcome:"failure" に複数種類の失敗が混在していることを理解できる
  • event.action:"user-login" and event.outcome:"failure" でログイン失敗だけを正確に絞り込める
  • Failed Login Detection (Basic Rule) という名前の検知ルールが動いている状態になる
  • 過去データの確認に Rule preview と manual run を使い分けられる

Step 1:Discoverでイベントの中身を確認する

Discoverを開き、左上のData Viewが training-security-logs になっていることを確認します。時間範囲は「Last 2 years」に変更してください。

まず次のフィールドを列として追加します。フィールド名の横の「+」アイコンをクリックすると列に追加できます。

フィールド何を見るか
@timestampいつ起きたか
event.action何のイベントか
event.outcome成功か失敗か
user.name対象ユーザー
source.ip送信元IP
host.name対象ホスト


Step 2:ログイン失敗だけに絞り込む

まず次のKQLを実行します。

event.outcome:"failure"

18件ヒットします。ここで event.action 列に注目してください。event.outcome:"failure" は「失敗したイベント全般」を返します。ログイン失敗だけでなく、ポートスキャン時の接続失敗も含まれます。「Failed Login Detection」という名前のルールをこの条件で作ると、名前と実態がずれたルールになってしまいます。

event.action件数意味
connection-attempt6件ポートへの接続試行が失敗
user-login12件ログイン試行が失敗

次のKQLを実行します。

event.action:"user-login" and event.outcome:"failure"

12件に絞られます。connection-attempt の失敗が消え、純粋にログイン失敗だけが残っているはずです。

確認ポイント:

  • event.action がすべて user-login になっているか
  • event.outcome がすべて failure になっているか
  • connection-attempt のようなネットワーク失敗が混ざっていないか

混ざっていなければ、この条件がルールのKQLとして使えます。

event.category をルール条件に使う際の注意点 event.category はマルチバリューフィールドです。1件のイベントが ["iam", "authentication"] のように複数の値を持てる設計になっています。Elastic SecurityのCustom query ruleでこのフィールドをルール条件に使うと、「The event.category field cannot be used for…」というエラーが表示される場合があります。ルールのKQL条件では event.actionevent.outcome のようなシングルバリューフィールドを使い、event.category はDiscover での確認用として使うのが安全です。

※ Discoverでフィールドの統計量を確認できる。


Step 3:このサンプルデータに含まれる2つのシナリオ

絞り込んだ12件を時系列で見ると、2つの独立した攻撃シナリオが含まれています。この章では両方のシナリオを拾う「一般的なログイン失敗の監視ルール」を作ります。シナリオAの攻撃チェーンを詳しく追う調査は第3回で行います。

シナリオA:内部ネットワークからの侵害の可能性(source.ip: 192.168.1.100)

UTC 10:03台に、192.168.1.100 から PROD-SRV-01 に対して admin_rootadministrator へのログイン失敗が複数回続き、その直後に成功しています。

このような「短時間の連続失敗の後に成功する」挙動は、ブルートフォース攻撃による認証突破の可能性を示す典型的なパターンです。ただし、ユーザーの入力ミスによる正常なログインの可能性もあるため、追加の調査が必要です。

シナリオB:外部からのブルートフォース(source.ip: 45.33.21.11)

UTC 10:14〜10:17台に、外部IP 45.33.21.11 から PROD-SRV-01 に対して guest・admin・root・administrator など複数のユーザー名でログイン失敗が連続して発生しています。

これは、一般的なアカウント名を順に試す典型的なブルートフォース攻撃の挙動です。


Step 4:ルールタイプを選ぶ

Elastic Securityには複数のルールタイプがあります。

ルールタイプ何を見るか向いているケース
Custom query条件に一致する1件1件のイベント1件でも起きたら知らせたい
Threshold一致したイベントの件数5回以上失敗したら知らせたい
ES|QL集計・加工した結果合計転送量が閾値を超えたら
Event Correlationイベントの順序・パターンAのあとにBが起きたら

今回は「1件のログイン失敗が起きたら知らせたい」ので Custom query を選びます。Threshold は「何回失敗したか」を数えるためのものであり、1件ずつ検知したい今回の目的には向きません。Threshold の使い方は第5回で扱います。


Step 5:ルールを作る

SecurityRulesDetection rules (SIEM)Create new rule を開きます。

ルールタイプの選択画面で「Custom query」を選んで「Selected」にします。

Define rule の設定:

データソースとして「Data View」タブを選び、training-security-logs を指定します。Custom query 欄に次を入力します。

event.action:"user-login" and event.outcome:"failure"

保存前に必ずDiscoverで確認する ルールを保存する前に、同じKQLをDiscoverで実行して「期待したイベントだけが返ってくるか」を必ず確認してください。この確認を省くと、想定外のイベントを拾うルールや、何もヒットしないルールを本番環境に入れてしまうリスクがあります。

About rule の設定:

項目設定値
NameFailed Login Detection (Basic Rule)
Descriptiontraining-security-logs 内のログイン失敗イベントを検知する
SeverityLow
Risk score21

Schedule の設定:

項目設定値
Runs every5 minutes
Additional look-back time1 minute

「Continue」をクリックし、「Create & enable rule」で保存します。

※ノイズ削減(重複アラートの圧縮や正常動作の除外)は別の回で扱います。


Step 6:過去データに対してルールを確認する

このサンプルは2025-03-18の過去データです。ルールを有効化しても、ルールは「現在時刻からの直近ウィンドウ」を見るため、今すぐアラートが自動生成されることはありません。これは故障ではなく正常な動作です。

過去データを確認するための2つの方法を使い分けます。Rule preview の手順:

  1. ルール編集画面右上の「Rule preview」をクリック
  2. 時間範囲を設定する
    • 開始:2025-03-18 10:00:00(UTC)/ 画面表示では 19:00:00 JST
    • 終了:2025-03-18 10:30:30(UTC)/ 画面表示では 19:30:30 JST
  3. 「Refresh」をクリック

期待値:12件のアラートが表示される(内部侵害4件 + 外部ブルートフォース8件)

Manual run の手順:

  1. ルール詳細画面の右上メニューから「Manual run」を選ぶ
  2. 時間範囲を過去データの期間に合わせて指定する
  3. 「Run」をクリック
  4. Security → Alerts を開き、Alerts画面の時間範囲も「Last 2 years」などに広げる

※Additional look-back timeをかなり長くとる方法も合います


アラートが見えないときの確認手順

手順確認内容
Discoverで同じKQLを実行してヒットするか確認する
各画面の時間範囲が過去データに合っているか確認する
securitySolution:defaultIndextraining-security-logs が入っているか確認する(第1回参照)
ルール詳細の「Execution results」タブを確認する。「Succeeded」はクエリが正常終了したことを意味するだけで、ヒット件数がゼロのまま正常終了することがある

生成されたアラートから読み取れること

Manual run後に Security → Alerts を開くと、次の状況が確認できます。

サマリー画面で全体傾向を把握する

画面上部の Summary タブでは、検知結果の全体傾向が一目でわかります。

確認項目このデータでの期待値
Severity levelsすべて「Low」、計12件
Alerts by nameFailed Login Detection (Basic Rule):12件
Top alerts by source.ip45.33.21.11(約66%)、192.168.1.100(約33%)

「どの送信元からの攻撃が多いか」がひと目でわかります。

テーブルで個別アラートを確認する

テーブルビューで確認すべき主なフィールドは次のとおりです。

フィールド確認すること
@timestampいつ発生したか(時間が集中していないか)
Ruleどのルールで検知されたか
Severity / Risk Score重要度(今回は Low / 21)
host.name攻撃対象のホスト(PROD-SRV-01)
user.name試されたユーザー名(admin_root, guest など)

今回の12件のアラートから、次の状況が推測できます。

  • 同一ホスト(PROD-SRV-01)に対して
  • 複数のユーザー名(admin_rootadministratorguestadminroot)で
  • 複数回のログイン失敗が発生している
  • 送信元IPが2つあり、45.33.21.11 が大多数を占める

これはブルートフォース攻撃の典型的な兆候です。ただしこの時点では「疑いがある」という段階です。次の第3回でTimelineを使って攻撃の流れを詳しく追います。


この章のまとめ

  • event.outcome:"failure" だけでは、ログイン失敗以外の失敗イベントも含まれる
  • event.action:"user-login" and event.outcome:"failure" で、ログイン失敗だけを正確に絞れる
  • event.category はマルチバリューフィールドのため、ルールのKQL条件に使うとエラーになる場合がある
  • 最初のルールには Custom query を使い、件数ではなく1件1件を検知する
  • 過去データの確認には、Rule preview(シミュレーション)と manual run(本番実行)を使い分ける

第2回チェックリスト

  • [ ] event.outcome:"failure" で18件、event.action:"user-login" and event.outcome:"failure" で12件ヒットする
  • [ ] Failed Login Detection (Basic Rule) が作成され、有効化されている
  • [ ] Rule preview または manual run でアラートが確認できている
  • [ ] Alertsのサマリーで 45.33.21.11192.168.1.100 の2つの送信元が見えている

次回は: Timelineを使って、192.168.1.100 からの攻撃をポートスキャンからデータ持ち出しまで1本の時系列で読み解きます。「アラートを見る」から「攻撃の流れを説明できる」へ進みます。