🛡

Google SecOps:カスタムルールで柔軟な脅威検出を実現する

2025/03/07に公開

はじめに

こんにちは、クラウドエースの潘です。

今回は Google Security Operations(以下 Google SecOps)における SIEM のカスタムルールによる脅威検出について説明していきます。

マネージド脅威検出の機能紹介については以前別の記事で紹介しているので、こちらと比較しながら見ていただければと思います。
https://zenn.dev/cloud_ace/articles/google-secops-siem-detections

また、前提知識として、UDM 検索について理解している必要があります。
UDM 検索について以下の記事で説明しておりますのでこちらをご覧ください。
https://zenn.dev/cloud_ace/articles/google-secops-log-search

概要

Google SecOps では、取り込んだログから、不審と思われるイベントパターンを検出するカスタムルールを作成することができます。

以下のような要望を実現したい場合、カスタムでルールを作成するのが有効です。

  • マネージドな検出ルールで補いきれない脅威を検出したい
  • 会社独自の制約に違反したイベントを検出したい

カスタムルールによる脅威検出では、YARA-L という言語を用いてルールを作成します。
詳細な言語仕様や構文については公式ドキュメントを参照してください。
https://cloud.google.com/chronicle/docs/detection/yara-l-2-0-overview?hl=ja

本記事では、YARA-L の記法を用いてカスタムルールを作成するための基礎知識の習得を目指します。

細かい構文は一部割愛しますが、「なんとなく理解できた」レベルになっていただければ幸いです。

カスタムルール作成画面へのアクセス

① Google SecOps のスタート画面から、画面左のメニューバーを開き、Rules & Detections をクリックします。
yaral-menu1
Rules Editor のタブに遷移します。
New をクリックすることで、カスタムルールの編集画面が表示されます。
yaral-menu2

YARA-L 言語によるルール作成の活用

YARA-L では以下の6つのセクションを組み合わせてルールを記載します。

ルールの一般的な構造は以下の通りです。

sample.yara
rule <rule Name>
{
meta:
// ルールの詳細情報(作成者、検出対象、バージョン管理など)
// 必須

events:
// イベントをフィルタリングする条件や、イベント間の関係を定義
// 必須

match:
// 期間を指定し、一致が見つかったときに検出
// 省略可能(マルチイベントルールでは必須)
// ※以下ルール例の CASE 2 以降で解説

outcome:
// 各検出から抽出された追加情報
// 省略可能

condition:
// events および match で指定された変数に対して検出する際の条件を記述
// 必須

options:
// このルールを実行する際にオンまたはオフにするオプション
// 省略可能
}

以下、具体例を見ながら理解を深めていきましょう。
コード内の赤文字のコメントはポイントとなる部分なので、一部詳細な解説を記載しています。

CASE1:1 種類のイベントの存在を検出

yaral-rule1
図:最初にログインしたユーザ検出ルール

以下に示すルールは、ユーザログインのイベントを検索し、ヒットしたものを検出します。

yaral-rule1-code

コードのスニペット
sample_single_event.yara
rule SingleEventRule {
  meta:
    author = "hogohoge@example.com"

  events:
    $process.metadata.event_type = "USER_LOGIN"
    $process.metadata.vendor_name = "Microsoft"

  match:
    $user

  condition:
    $process
}

上記ルールで検出している内容は、UDM 検索において「Microsoft ユーザのログインイベントを検索」した場合と同様です。

events セクションとcondition セクションに関する詳細な説明は以下に記載しています。

events セクションと condition セクションについて

events セクション】
events セクションでは以下のようなことを実施します。

  • 検出したいイベントの指定
  • 別のセクション(condtionmatch)で条件を指定するための変数を定義

CASE1 では、「ユーザログインに関するイベントタイプ」を検出するために
$process.metadata.event_type = "USER_LOGIN"
のように変数を定義しています。

この例では、process が変数という扱いになり、以降の metadata.event_type は UDM フィールドが指定されています。

このように、events セクションにおいては、「変数 + UDM またはエンティティフィールド」 という形で変数を宣言します。

また、CASE1 の例のように、同じ変数名で異なる UDM フィールド( metadata.event_typemetadata.vendor_name)を指定することで、AND 条件で絞り込むことが可能です。

condition セクション】
condition セクションでは events セクションで定義されているイベント変数の条件を指定します。

単に $ 記号の後に変数名が記載されている場合、「events セクションで指定した条件に当てはまるログが一件でもあれば検出する」という意味になります。

特定の件数より大きい場合に検出したい場合、以下のように # 記号を用いて記述します。

#e > 3 // 変数 e で指定したイベントの件数が 3 より大きい場合に検出する

CASE2:一定の時間内における 1 種類のイベントの連続発生を検出

yaral-rule2
図:短期間に大量にログインしたユーザ検出ルール

この章では、一定の時間内における異常なイベントパターンを検知したい場合について述べます。

例えば、「10 分間で 10 回のログインを実施したユーザ」がいた場合、その人は悪意を持ってログインを突破しようとしている可能性が疑われます。

このようなケースを検知したい場合、YARA-L では以下の様に記述します。

yaral-rule2-code

コードのスニペット
sample_match_event.yara
rule MatchEventRule {
  meta:
    author = "hogohoge@example.com"

  events:
    $e.metadata.event_type = "USER_LOGIN"
    $e.principal.user.userid = $user

  match:
    $user over 10m

  condition:
    #e >= 10
}

上記の例では、events セクションで $e.principal.user.userid = $user のように右辺で変数を宣言しています。
これをプレースホルダ変数といい、ある変数で指定した値を別の変数で保持しておくものです。

プレースホルダ変数について

上記の例では左辺が UDM フィールドを表し、右辺では user という変数で、左辺で指定した値(ユーザ ID の一覧)を保持しています。

プレースホルダ変数は match セクションやcondition セクションにて使い回しができるため、柔軟なルール作成が可能になります。

match セクションでは、イベントパターンを検出する時間枠を指定します。
match セクションに関する詳細な説明は以下に記載しています。

match セクションについて

match セクションでは、events セクションで定義した変数に対し、over に続くイベント期間を指定し、イベントを期間でグルーピングします。(match セクションで指定した変数を match 変数といいます。)

上記の例では、10 分という期間の中で、USER_LOGIN のイベントタイプを持つログをユーザ ID ごとにグルーピングします。

指定できる最小時間は 1 分、最大時間は 48 時間です。

CASE3:一定の時間内における複数製品のログイベントの相関検知

yaral-rule3
図:プロセス実行した後、外部と通信したユーザの検出ルール

この章では、上記の図のように、異なる製品のログから取得したイベントを紐付けて検出ルールを作成する場合について述べます。

以下の例では、「特定のプロセスを起動した後、5分以内にプロキシ経由でネットワーク通信を行ったユーザ」 がいた場合にそれを検出します。

yaral-rule3-code

コードのスニペット
sample_edr_proxy_event.yara
rule sw_suspicious_download_office {
  meta:
    author = "hogohoge@example.com"

  events:
    $edr_event.metadata.product_event_type = "PROCESS_LAUNCH"
    $edr_event.metadata.product_name = "Falcon"
    $edr_event.metadata.vendor_name = "Crowdstrike"
    $edr_event.target.process.file.full_path = /\\excel\.exe/ nocase
    $edr_event.principal.user.userid = $user

    $proxy_event.metadata.event_type = "NETWORK_HTTP"
    $proxy_event.metadata.product_name = "NSS"
    $proxy_event.metadata.vendor_name = "Zscaler"
    $proxy_event.network.application_protocol = "HTTP"
    $proxy_event.target.url = /.*\.js$/
    $proxy_event.principal.user.userid = $user

    $proxy_event.metadata.event_timestamp.seconds >= 
    $edr_event.metadata.event_timestamp.seconds

  match:
    $user over 5m

  condition:
    $edr_event and $proxy_event
}

上記のように、同じプレースホルダ変数を複数箇所で利用することで、異なる製品のログイベントの紐付けによる相関分析が可能になります。

プレースホルダ変数を使った紐付けについて

上記の例では、EDR とプロキシのイベントから取得できるユーザ ID を、それぞれ user という名前の変数に格納することで、ユーザ ID による紐付けを実施しています。

これと同様に、例えば左辺で principal.hostname を指定し、右辺で hostname というように変数を指定すれば端末名で紐づけることも可能になります。

CASE3 では match セクションで 5 分、match 変数を user で指定しています。
これにより、同一ユーザーが 5 以内に events セクションで指定したパターンの行動をおこなっている場合に、EDR とプロキシのイベントの間に相関ありとみなしています。

ルールのテスト

作成したルールが作動するかどうか検証したい場合、以下の手順で過去の期間に対してもルールのテストを実施することができます。
yaral-test

【ルールの手順】

  • 画面下部の TEST RULE RESULTS をクリック
  • Time range to test で、テストを検証する期間を指定
  • RUN TEST をクリック

レトロハント

YARA-L を使ったカスタムルールを用いて、過去の期間のデータに対して検出を実行することも可能です。
この機能をレトロハントといいます。

レトロハントで検出を実施すると、過去のデータに対する、アラートや SOAR への CASE の発行が可能になります。
https://cloud.google.com/chronicle/docs/detection/run-rule-historical-data?hl=ja

まとめ

YARA-L は一見すると学習コストが高そうな言語ですが、本記事を参考にすれば基本的なルール作成の概要は把握できると思います。

カスタムルールを用いれば詳細な条件を指定して柔軟に脅威検出をすることが可能ですので、ぜひトライしてみてください!

Discussion