セキュリティエンジニアのための EQL 入門:Elastic で脅威を見つけるクエリ言語

Tech Blog banner: laptop with a vibrant burst of colors emerging from the screen, overlaid with Japanese title about EQL for security engineers. BLOG

想定読者:SOC アナリスト、脅威ハンター、検知エンジニア。SIEM の経験はあるが Elastic / EQL は初めて、あるいは復習したい方。 読了時間:約 15 分

セキュリティ運用の現場では、毎日とんでもない量のログを見ます。Elasticsearch は「ログを保存して検索する」のはとても得意です。でも、脅威の検出となると話が一段難しくなります。

なぜか。攻撃は単独のイベントではなく、複数のステップが時間軸の上で連なる流れだからです。

たとえば、次のような流れを「ひとかたまり」として検出したいとします。

  1. ファイルが Temp フォルダに作成された
  2. その直後にそのファイルが実行された
  3. さらにそのプロセスが外部に通信した

普通のクエリでは、これを 3 回別々に検索して、ID やタイムスタンプで突き合わせる必要があります。これがしんどい。

EQL(Event Query Language)は、この「流れ全体」を一度のクエリで捕まえるために作られた言語です。本記事では、セキュリティエンジニアが EQL を実務で使えるようになるための最短ルートを紹介します。

  1. EQL とは何か
    1. EQL を動かすための前提
    2. 通常の検索クエリ(KQL/Lucene)と何が違うか
  2. Splunk SPL を使っている人へ:EQL との対応表
    1. 同じ検出を SPL と EQL で書き比べる
    2. EQL の SPL に対する優位点
  3. EQL の基本構文
    1. 最小単位の形
    2. 例 1:PowerShell 実行の検出
    3. 例 2:複数条件の組み合わせ
    4. EQL の演算子チートシート
    5. == と : の使い分け(ハマりやすい)
  4. ECS:Elastic Common Schema を理解する
    1. ECS とは何か
    2. セキュリティで頻出する ECS フィールド
  5. タスク文を EQL に変換するフレームワーク
    1. 5 ステップ翻訳法
    2. 実演:タスク文を 5 ステップで翻訳する
    3. キーワード → ECS フィールドの早見表
  6. sequence と時間制約:流れの検出
    1. 構文
    2. by の力:複数フィールドで相関
    3. イベント間で値を引き継ぐ:per-event by
    4. maxspan の選び方
  7. 実例:セキュリティ検出パターン 5 選
    1. パターン 1:暗号化されていない通信の検出(コンプライアンス)
    2. パターン 2:PowerShell ダウンロードからの C2 接続
    3. パターン 3:Office アプリからのプロセス起動(Living off the Land)
    4. パターン 4:マルウェア配置 → 実行 → C2 通信
    5. パターン 5:横展開の検出(ラテラルムーブメント)
  8. よくあるミス と正しい書き方
    1. ミス 1:ECS でないフィールド名を使う
    2. ミス 2:大文字小文字の罠
    3. ミス 3:event.action と event.type の混同
    4. ミス 4:sequence の順序逆転
    5. ミス 5:maxspan の単位忘れ
    6. ミス 6:EQL 関数の大文字小文字を間違える
    7. ミス 7:関数の引数の大文字小文字でヒットしない
  9. 実際に動かす方法
    1. 方法 1:Kibana の Dev Tools で試す
    2. 方法 2:Elastic Security の Timeline
    3. 方法 3:Detection Rule として登録
  10. まとめ
  11. 参考資料

EQL とは何か

EQL は Elastic が開発した、イベントベースのクエリ言語です。SQL や KQL に少し似ていますが、決定的に違うのは「複数のイベントの順序と関係性を表現できる」点です。

ひとことで言うと:

EQL は「A が起きて、その後に B が起きて、さらに C が起きた」を 1 つのクエリで書ける言語。

これは脅威検出と相性が抜群です。なぜなら、攻撃チェーン(MITRE ATT&CK で言うところの Tactics の連鎖)は、まさにそういう構造をしているからです。

EQL を動かすための前提

ここで先に伝えておきたいことがあります。EQL は ECS(Elastic Common Schema)を前提に設計されているため、検索対象のデータには @timestampevent.category フィールドが必要です。Elastic 公式ドキュメントにも、EQL はデフォルトでこの 2 つのフィールドを使うと明記されています。

つまり、

process where process.name == "powershell.exe"

の process は、実際には「event.category が process のイベント」を意味します。

Elastic Agent や Elastic Defend、Beats から取り込んだデータは ECS に準拠しているのでそのまま EQL が動きます。独自データの場合は、最低限この 2 フィールドをマッピングしておく必要があります。

通常の検索クエリ(KQL/Lucene)と何が違うか

特性通常のクエリ (KQL)EQL
1 つのイベント検索✅ 得意✅ 得意
集計・統計✅ 得意⚠️ 限定的
複数イベントの順序関係❌ 自前で組み立てネイティブ対応
時間窓での相関❌ 困難✅ maxspan で簡単
ECS フィールドの活用

「単一イベントを検索したい」なら KQL でも十分です。「攻撃の流れを検出したい」なら EQL です。

Splunk SPL を使っている人へ:EQL との対応表

SOC 経験者の多くは Splunk SPL の知識があるはずです。両者の対応関係を理解しておくと、EQL の学習速度が一気に上がります。

やりたいことSplunk SPLElastic EQL
単一イベント検索search index=… process=”…”process where process.name == “…”
複数イベントの相関transaction host maxspan=30ssequence by host.name with maxspan=30s
ストリーミング相関streamstatssequence
データモデル / 正規化CIM (Common Information Model)ECS (Elastic Common Schema)
フィールド指定process_name(CIM)process.name(ECS)
否定NOTnot / !=
ワイルドカード** (: または like 演算子)

⚠️ これは厳密な機能対応ではなく、考え方を理解するための対応表です。 Splunk の transaction はイベントをまとめて後処理するイメージが強く、EQL の sequence は「順序あるイベント列」をネイティブに表現する処理です。考え方として近い、というレベルで捉えてください。

同じ検出を SPL と EQL で書き比べる

シナリオ: PowerShell が実行され、30 秒以内に外部 HTTPS 接続が発生

Splunk SPL:

(index=endpoint sourcetype=process process_name="powershell.exe")

  OR (index=endpoint sourcetype=network dest_port=443)

| transaction host maxspan=30s

| where mvcount(sourcetype)>1

Elastic EQL:

sequence by process.entity_id with maxspan=30s

  [process where process.name == "powershell.exe"]

  [network where destination.port == 443]

EQL の方が「意図がそのまま構文になっている」のがわかります。「これが起きて、次にこれが起きる」と読める。(process.entityの代わりに広域な相関でhost.name を使う事も可能です)

EQL の SPL に対する優位点

実務でメリットになるのは、おおむね以下の点です。

  • 構文が攻撃チェーンのメンタルモデルと一致 — sequence … [event A] [event B] という形が、そのままアナリストの思考順序になる
  • 時間ウィンドウの指定が一行 — with maxspan=30s を足すだけ
  • ECS により書いたクエリの再利用性が高い — process.name を含むデータであれば、Windows、Linux、各種 EDR を横断して同じクエリが使える
  • 検知ルールにそのまま流用可能 — Elastic Security の Detection Engine が EQL をネイティブサポート
  • オープンスタンダードに沿った設計 — ECS は OpenTelemetry の Semantic Conventions に統合される方向で進化している

逆に EQL が苦手なこと も正直に書いておきます。

  • 大規模な統計集計(カウント、平均、グルーピング)→ ES|QL や Lens の方が向いている
  • 複雑な条件分岐や後処理 → ES|QL を併用するのが現実的
  • フィールド同士の比較(例:「1 回目の host.name と 2 回目の host.name が違う」)→ EQL 単独では難しい。ES|QL での後続分析と組み合わせる

EQL は「順序ある脅威検出」のためのツール。集計や複雑な比較が必要なら別のツールと組み合わせるのが Elastic 流です。

EQL の基本構文

ここから手を動かす段階に入ります。

最小単位の形

event_category where condition

たったこれだけ。読むと:

  • event_category:何のイベントを見るか(process、file、network、authentication、registry など。内部的には event.category の値)
  • where:条件を続けますよ、という宣言
  • condition:実際の条件

例 1:PowerShell 実行の検出

process where process.name == "powershell.exe"

例 2:複数条件の組み合わせ

process where process.name == "powershell.exe"

  and process.command_line : "*DownloadString*"

ここで重要な演算子を整理しておきます。

EQL の演算子チートシート

演算子意味使いどころ
==厳密一致(大文字小文字を区別)プロセス名、ポート番号など正確に一致させたい時
!=一致しない除外条件
:大文字小文字を区別しない文字列一致(ワイルドカード *、? 対応)パス、コマンドライン、拡張子(実体は like~ と等価)
likeワイルドカード一致(大文字小文字を区別するパターンマッチ
like~ワイルドカード一致(大文字小文字を区別しない: と同じ
inリストのいずれか(区別あり)process.name in (“cmd.exe”, “powershell.exe”)
in~リストのいずれか(区別なし)大文字小文字が揺れるデータに
not否定not process.name == “explorer.exe”
and / or論理演算子条件の組み合わせ

💡 メモ: : は「ワイルドカードが使える ==」と覚えると間違いません。文字列の比較で、== より柔軟(大文字小文字も吸収、* ? も使える)。

== と : の使い分け(ハマりやすい)

# ❌ ハマるパターン:ファイル拡張子に == を使うと小文字限定

file where file.extension == "exe"   # .EXE は引っかからない

# ✅ : を使えば大文字小文字の揺れを吸収

file where file.extension : "exe"    # .exe も .EXE もマッチ

Windows の拡張子は大文字小文字が混在することがよくあります。ファイルパスや拡張子は基本的に : を使う方が安全です。

ECS:Elastic Common Schema を理解する

EQL を本気で使うには、ECS の理解が欠かせません。これは Splunk の CIM に相当する概念です。

ECS とは何か

ECS は「Elasticsearch にイベントデータを保存するときの共通フィールド仕様」です。

セキュリティログは多種多様なソースから来ます。

  • Windows Sysmon
  • Linux Auditd
  • ファイアウォール
  • EDR
  • クラウドサービスの監査ログ

これらが全部バラバラのフィールド名(proc_name、process_name、pname、Image…)だと、検索のたびにスキーマを覚え直す羽目になります。

ECS はこれを process.name のような共通名に統一する仕様です。ECS 対応のデータであれば、同じ意味の情報を同じフィールド名で扱えるようになります。

⚠️ 注意: ECS は「共通化のルール」であって「すべてのデータソースが必ず全フィールドを持つ」保証ではありません。たとえばネットワーク機器のログには通常 process.name がありません。実際にどのフィールドが入っているかは、データソースやインテグレーションによって異なるため、Kibana の DiscoverData Views で確認してから書く習慣をつけましょう。

セキュリティで頻出する ECS フィールド

実務でほぼ毎日使うフィールドを覚えておきましょう。

プロセス

フィールド内容
process.nameプロセス名(例:powershell.exe)
process.executableフルパス(例:C:\Windows\System32\powershell.exe)
process.command_lineコマンドライン全文
process.pidプロセス ID(OS が割り当てる数値)
process.entity_idプロセスの一意識別子(Elastic Defend などが付与。推奨
process.parent.name親プロセス名
process.parent.entity_id親プロセスの entity_id

💡 process.pidprocess.entity_id の違い: PID は OS のプロセス識別子ですが、プロセス終了後に再利用されるため、長い時間ウィンドウのクエリでは別プロセスのイベントが混ざる可能性があります。Elastic Defend や Sysmon が付与する process.entity_id はプロセスごとに一意な値なので、sequence の by 句では process.entity_id を優先します。

ファイル

フィールド内容
file.pathフルパス
file.nameファイル名
file.extension拡張子(. なし)
file.sizeバイト数
file.hash.sha256SHA256 ハッシュ

ネットワーク

フィールド内容
destination.ip接続先 IP
destination.port接続先ポート
source.ip送信元 IP
network.protocolプロトコル
network.direction通信の向き。ホスト視点なら ingress / egressネットワーク観測点視点なら inbound / outbound / internal / external

💡 network.direction の値はデータソースによって違う: Elastic Defend や endpoint 系(Auditbeat、Sysmon 経由)は ingress/egress を使う傾向、Packetbeat や Zeek のような observer 系(ネットワーク監視目線)は inbound/outbound を使う傾向です。クエリを書く前に Discover で実際の値を確認しましょう。

イベント / 主体

フィールド内容
event.categoryイベント大分類(process、file、network 等)。EQL の必須フィールド
event.typeECS 標準のサブタイプ(creation、start、end、connection 等)
event.actionデータソース固有のアクション名(ソースによって値が異なる)
event.outcomesuccess / failure
user.nameユーザー名
host.nameホスト名
@timestampイベント時刻。EQL の必須フィールド

💡 event.typeevent.action の違い: event.type は ECS が定義する標準化されたサブタイプ(creation、deletion、start、connection など決められた値)。event.action はデータソース固有のアクション名(Windows なら file-created、Sysmon なら FileCreated など値がバラバラ)。ポータブルなクエリを書くなら event.type を使うのが基本です。

タスク文を EQL に変換するフレームワーク

検知エンジニアリングで一番難しいのは、「日本語の脅威シナリオを、ECS フィールドと EQL に翻訳すること」です。これさえ身につければ、新しい脅威ハンティングのアイデアをすぐクエリにできるようになります。

5 ステップ翻訳法

どんな日本語のシナリオも、次の 5 つの問いに答えれば EQL になります。

  • Step 1. 何のイベント?     → event.category    (process / file / network …)
  • Step 2. どんなアクション?  → event.type        (creation / start / connection …)
  • Step 3. 何に対して?       → file.* / process.* (オブジェクト)
  • Step 4. 誰が引き起こした?  → process.* / user.* (主体)
  • Step 5. 順序や時間制約?    → sequence / maxspan (流れ)

実演:タスク文を 5 ステップで翻訳する

タスク:実行ファイル Word ドキュメント作成し、30 秒以内に大量のデータ送信が起きたケースを検出したい」

誰が? → 実行ファイル
何を? → Word ドキュメント
どうした? → 作成した

EQL では、この「誰が・何を・どうした」を ECS フィールドに置き換えていきます。

誰が? → process.executable
何を? → file.extension
どうした? → event.type

つまり、今回の前半部分はこういう考え方になります。

.exe の実行ファイルが
.doc / .docx の Word ドキュメントを
作成した

file where event.type == "creation"
  and process.executable : "*.exe"
  and file.extension : ("doc", "docx")

ここで大事なのは、file.* と process.* の見方です。

file.* は、作られたものの情報です。
今回であれば、作られたものは Word ドキュメントなので、file.extension : ("doc", "docx") になります。

一方で、process.* は、そのイベントを起こしたプログラムの情報です。
今回であれば、Word ドキュメントを作ったのは実行ファイルなので、process.executable : "*.exe" になります。

つまり、ファイル作成イベントでは、次のように考えるとわかりやすいです。

process が file を event.type した

今回なら、こうです。

.exe が .doc/.docx を creation した

次に、後半の条件「30 秒以内に大量のデータ送信が起きた」を見ます。

これはネットワークイベントです。大量のデータ送信は、たとえば source.bytes で表現できます。

「作成」→ 「30 秒以内」→ 「大量送信」、流れの検出 → sequence + maxspan

sequence with maxspan=30s

  [file where event.type == "creation"

    and process.executable : "*.exe"

    and file.extension : ("doc", "docx")]

  [network where source.bytes > 1000000]

完成です。日本語から EQL までの距離が、思ったより近いのが伝わったでしょうか。

キーワード → ECS フィールドの早見表

翻訳作業でつまずきやすい「日本語キーワード」と「対応する ECS フィールド」の対応表です。

日本語キーワード条件フィルターよく組み合わせるフィールド
実行された / 起動されたevent.type == "start"process.nameprocess.executable
作成された / 保存されたevent.type == "creation"file.namefile.pathfile.extension
削除されたevent.type == "deletion"file.*
変更されたevent.type == "change"file.*registry.*
外部に通信 / 接続event.type == "connection"destination.ipdestination.port
ログインしたevent.category == "authentication"event.outcomeuser.namesource.ip

sequence と時間制約:流れの検出

EQL の真骨頂は sequence です。詳しく見ていきます。

構文

sequence [by FIELD] [with maxspan=TIME]

  [event_category where condition_1]

  [event_category where condition_2]

  [event_category where condition_3]
  • by FIELD:イベント間を「何でつなぐか」(join key)。host.name、process.entity_id、user.name など
  • with maxspan=TIME:「全体が何秒以内に起きたら検出するか」(s / m / h / d)
  • […]:各ステップのイベント条件

by の力:複数フィールドで相関

sequence by host.name, user.name with maxspan=5m

  [authentication where event.outcome == "failure"]

  [authentication where event.outcome == "success"]

「同じホスト、同じユーザーで、ログイン失敗の後に成功」を 5 分以内で検出。ブルートフォースの成功を捕まえる典型パターンです。

イベント間で値を引き継ぐ:per-event by

ここが少しトリッキーで、よく間違えるところです。

やりたいこと: ファイルが作られて、その同じファイル名のプロセスが起動した

sequence by host.name with maxspan=1m

  [file where event.type == "creation" and file.extension : "exe"] by file.name

  [process where event.type == "start"] by process.name

sequence by host.name で ホスト全体の相関、各 […] の後の by file.name / by process.name で 値を引き継ぎます。これにより「file.name == process.name」という相関が成立。

⚠️ 重要: by のキー数は全イベントで揃える必要があります。[eventA] には by を付けて [eventB] に付けない、という書き方はできません。全イベントに付けるか、付けないかのどちらかです。

maxspan の選び方

シナリオ推奨 maxspan
プロセス起動 → 即時通信30s 〜 1m
マルウェア配置 → 実行1m 〜 5m
ログイン → 横展開5m 〜 30m
内部偵察 → 権限昇格1h 〜 4h
持続化 → 後日の C21d 以上(要注意:誤検知も増える)

短すぎると正規の動作も誤検知、長すぎると無関係なイベントが混ざる。ここは仮説に基づいてチューニングする領域です。

実例:セキュリティ検出パターン 5 選

そのままルールとして登録できる形にしてあります。

パターン 1:暗号化されていない通信の検出(コンプライアンス)

network where event.type == "connection"

  and (

    (destination.port == 80 and network.protocol == "http") or

    (destination.port == 21 and network.protocol == "ftp")

  )

  and network.direction in ("egress", "outbound")

社内から外向きの HTTP/FTP を可視化。PCI-DSS や社内ポリシー違反の検出に使えます。

パターン 2:PowerShell ダウンロードからの C2 接続

sequence by process.entity_id with maxspan=30s

  /* 
   * Step 1:
   * PowerShell が起動されたイベントを探す。
   * process.entity_id で後続の network イベントと同じプロセスに紐づける。
   */
  [process where event.type == "start"
    and process.name : "powershell.exe"

    /*
     * PowerShell のコマンドラインに、
     * ダウンロードやコード実行でよく使われる文字列が含まれているかを見る。
     * IEX / Invoke-Expression は、文字列として取得したコードを実行する時によく使われる。
     * DownloadString / Net.WebClient は、外部からスクリプトやペイロードを取得する時によく使われる。
     */
    and (
      process.command_line : "*IEX*" or
      process.command_line : "*DownloadString*" or
      process.command_line : "*Invoke-Expression*" or
      process.command_line : "*Net.WebClient*"
    )
  ]

  /*
   * Step 2:
   * 同じプロセスが 30 秒以内に HTTPS 通信しているかを見る。
   * destination.port == 443 は HTTPS 通信の代表的なポート。
   */
  [network where event.type == "connection"
    and destination.port == 443

    /*
     * 接続先がプライベート IP ではないことを確認する。
     * つまり、社内ネットワークではなく外部サーバーへ通信している可能性を見る。
     */
    and not cidrmatch(
      destination.ip,
      "10.0.0.0/8",
      "172.16.0.0/12",
      "192.168.0.0/16"
    )
  ]

PowerShell が「ダウンロード系」のコマンドを実行して、直後にプライベート IP 以外へ HTTPS 接続したケース。C2 ビーコンの典型形です。

ポイント: by process.entity_id で同一プロセス内の流れに限定しています。process.pid は再利用されるため誤検知の原因になりますが、process.entity_id は一意なので安全。

パターン 3:Office アプリからのプロセス起動(Living off the Land)

process where event.type == "start"

  and process.parent.name : ("winword.exe", "excel.exe", "powerpnt.exe", "outlook.exe")

  and process.name : ("cmd.exe", "powershell.exe", "wscript.exe", "cscript.exe", "mshta.exe", "rundll32.exe")

Office アプリがシェル系プロセスを起動するのは、ほぼマクロ起点の攻撃。現代の標的型攻撃で最頻出のパターンで、誤検知も少なめ。検知ルールとしてまず入れたい一本です。

パターン 4:マルウェア配置 → 実行 → C2 通信

sequence by host.name with maxspan=2m

  /*
   * Step 1:
   * 同じホスト上で、Temp フォルダに実行可能ファイルが作成されたイベントを探す。
   * Temp フォルダは、マルウェアやドロッパーが一時的にファイルを置く場所としてよく使われる。
   */
  [file where event.type == "creation"
    and file.path : "*\\Temp\\*"

    /*
     * exe / dll / scr は、攻撃で使われやすい実行可能ファイルの拡張子。
     * exe は通常の実行ファイル、dll はライブラリ、scr はスクリーンセーバー形式だが実行可能。
     */
    and file.extension : ("exe", "dll", "scr")
  ] by file.name

  /*
   * Step 2:
   * 直後に、作成されたファイルと同じ名前のプロセスが起動されたかを見る。
   * ここでは by file.name と by process.name を使い、
   * 「作られたファイル名」と「起動したプロセス名」を結びつけている。
   */
  [process where event.type == "start"] by process.name

  /*
   * Step 3:
   * さらに、そのプロセスが外部通信でよく使われるポートへ接続したかを見る。
   * 80 / 443 は HTTP / HTTPS、
   * 8080 は代替 HTTP、
   * 4444 は攻撃ツールやリバースシェルで使われることがある代表的なポート。
   */
  [network where event.type == "connection"
    and destination.port in (80, 443, 8080, 4444)
  ] by process.name

Temp に実行ファイルが落ちて → そのファイルが起動して → 外部通信、までを 2 分以内に検出。ドロッパー型マルウェアの典型挙動です。

パターン 5:横展開の検出(ラテラルムーブメント)

sequence by user.name with maxspan=30m

  /*
   * Step 1:
   * あるユーザーでログイン成功イベントが発生したかを見る。
   * 横展開では、攻撃者が盗んだ認証情報を使って、
   * まずどこかの端末やサーバーへログインすることがある。
   */
  [authentication where event.outcome == "success"]

  /*
   * Step 2:
   * 同じユーザーの操作として、横展開で使われやすいツールが起動されたかを見る。
   *
   * psexec.exe:
   *   Windows 環境でリモート端末上にコマンドを実行するためによく使われる。
   *
   * wmic.exe:
   *   WMI を使って、リモート端末の情報取得やコマンド実行に使われることがある。
   *
   * winrm.exe:
   *   Windows Remote Management を使ったリモート操作に関係する。
   */
  [process where event.type == "start"
    and process.name : ("psexec.exe", "wmic.exe", "winrm.exe")]

  /*
   * Step 3:
   * その後、同じユーザーで再びログイン成功イベントが発生したかを見る。
   * これは、別の端末やサーバーへ移動した可能性を確認するためのステップ。
   */
  [authentication where event.outcome == "success"]

「同じユーザーで、ログイン成功 → 横展開系ツール実行 → ログイン成功」という流れを 30 分以内で検出。侵入後の活動段階を捕まえます。

⚠️ EQL の限界:別ホストへのログイン」まで厳密に判定したい(1 回目と 2 回目の host.name が違う、という条件)場合、EQL の by 句では「値が等しい」しか表現できないため、これだけでは難しいです。実務では次のどちらかで対応します。

  1. EQL でこのクエリを実行して候補を絞り、Detection Rule の Investigation Guide で host.name の違いを確認する
  2. ES|QL で後続分析する(同じユーザーが複数ホストにログインしているかを集計)

よくあるミス と正しい書き方

実務でハマる典型パターンです。

ミス 1:ECS でないフィールド名を使う

# ❌

process where proc_name == "powershell.exe"

# ✅

process where process.name == "powershell.exe"

対策: Kibana の Data Views でフィールド名を確認するクセをつける。SPL からの移行者がいちばんやりがちなミス。

ミス 2:大文字小文字の罠

# ❌ 大文字の .EXE は引っかからない

file where file.extension == "exe"

# ✅

file where file.extension : "exe"

ミス 3:event.action と event.type の混同

# ⚠️ 動くかもしれないが、データソース依存(値が "file-created" や "FileCreated" など揺れる)

file where event.action == "creation"

# ✅ ECS 標準化された値を使う

file where event.type == "creation"

ミス 4:sequence の順序逆転

sequence は書いた順 = 起きた順です。

# ❌ 通信が先、プロセス起動が後…と書いている

sequence by process.entity_id

  [network where destination.port == 443]

  [process where process.name : "powershell.exe"]

# ✅ 「PowerShell 起動 → 通信」のシナリオなら

sequence by process.entity_id

  [process where process.name : "powershell.exe"]

  [network where destination.port == 443]

シナリオを先に日本語で書き下すと、順序ミスが減ります。

ミス 5:maxspan の単位忘れ

# ❌ 単位なしはエラー

with maxspan=30

# ✅

with maxspan=30s

s(秒)/ m(分)/ h(時間)/ d(日)を必ずつける。

ミス 6:EQL 関数の大文字小文字を間違える

EQL の関数名は大文字小文字を区別します。これでハマる人は多いです。

# ❌ Unknown function エラーになる
not cidrmatch(destination.ip, "10.0.0.0/8")

# ✅ camelCase が正解
not cidrMatch(destination.ip, "10.0.0.0/8")

よく使う関数の正しいスペル: cidrMatchstartsWithendsWithstringContainsindexOfconcat。関数を大文字小文字を無視させたいときは ~ を付けます(例: endsWith~(file.path, ".exe"))。

ミス 7:関数の引数の大文字小文字でヒットしない

関数名そのものに加えて、関数の引数(比較対象の文字列)もデフォルトで大文字小文字を区別します。Windows のファイルパスのように大文字小文字が揺れるデータでは、これで取りこぼします。

# ❌ .EXE や .Exe は引っかからない(小文字 .exe のみマッチ)
file where endsWith(file.path, ".exe") or endsWith(file.path, ".dll")

# ✅ ~ を付けると大文字小文字を吸収
file where endsWith~(file.path, ".exe") or endsWith~(file.path, ".dll")

ルール: 関数を大文字小文字を無視させたいときは、関数名の末尾に ~ を付けます。endsWith~startsWith~stringContains~indexOf~ などすべての文字列関数で使えます。

💡 :endsWith~ の使い分け: 単純な拡張子チェックなら file.extension : "exe" で十分。endsWith~ はパス末尾や任意の文字列末尾を見たいとき(例: process.command_line の末尾)に便利です。

実際に動かす方法

方法 1:Kibana の Dev Tools で試す

最も手軽な方法。

POST logs-endpoint.*/_eql/search

{

  "query": """

    sequence by process.entity_id with maxspan=30s

      [process where process.name : "powershell.exe"]

      [network where destination.port == 443]

  """

}

POST logs-endpoint.*/_eql/search

方法 2:Elastic Security の Timeline

Elastic Security の「Timeline」では、UI から直接 EQL クエリを実行できます。脅威ハンティングのインタラクティブな探索に向いています。

方法 3:Detection Rule として登録

  1. Elastic Security → ManageRulesCreate new rule
  2. Rule type で「Event Correlation」を選択(これが EQL)
  3. クエリを貼り付け
  4. 重要度、MITRE ATT&CK タグ、Investigation Guide を設定
  5. Save & enable

検証用のテストを必ず通してから本番有効化することをおすすめします。

まとめ

  • EQL は「順序ある脅威検出」のために作られたクエリ言語
  • EQL を動かす前提は @timestamp と event.category の 2 フィールド
  • Splunk SPL の transaction に近い考え方だが、構文が攻撃チェーンのメンタルモデルに直結している
  • ECS は『同じ意味のデータには同じフィールド名を使う』というルール。だから 1 つのクエリで複数データソースに対応できる。ただし、すべてのデータソースが ECS の全フィールドを持っているわけではないので、Discover で実際の中身は必ず確認。
  • 5 ステップ翻訳法(What → Action → Object → Actor → Sequence)で、日本語の脅威シナリオを EQL に変換できる
  • sequence + maxspan + by が真骨頂。順序と時間ウィンドウを 1 つのクエリで表現

セキュリティ運用の効率は、「使えるクエリ言語」と「使える脅威モデル」の組み合わせで決まります。EQL は前者の強力な武器です。

Elastic 公式の Detection Rules リポジトリ をフォローして、新ルールをキャッチアップ

参考資料