從 SPL 轉換為 YARA-L 2.0
本指南適用於已熟悉 Splunk 搜尋處理語言 (SPL) 的使用者。本課程將快速介紹 YARA-L 2.0,這是 Google Security Operations 中用於建構搜尋、資訊主頁和偵測規則的核心語言。
瞭解 YARA-L 2.0 結構
YARA-L 2.0 是 Google SecOps 採用的統一查詢語言,可對所有擷取的企業記錄資料進行強大的威脅搜尋、建構即時資訊主頁,以及建立高精確度的偵測規則。
這項語言可與 Google SecOps 偵測引擎搭配使用,讓您在大量資料中搜尋威脅和其他事件。
SPL 和 YARA-L 的基本結構差異
SPL 會使用以管道 (|) 字元串連的一系列指令,而 YARA-L 則是以區段為基礎。您可以使用不同的區段 (例如 events、outcome 和 condition) 定義查詢,描述要搜尋、偵測或視覺化的模式。
下表比較 SPL 和 YARA-L 的基本結構:
| 功能 | SPL (程序) | YARA-L (宣告式) |
|---|---|---|
| 核心概念 | 使用一連串指令,逐步轉換資料串流。 | 分析並將多部分結構的條件和轉換套用至安全性和作業資料串流,找出威脅並擷取寶貴的洞察資料。 |
| 資料流程 | 程序。一個指令的結果會透過管道傳輸,做為下一個指令的輸入內容。 | 宣告式結構,可大規模處理及關聯模式。不必再考慮效率問題。 |
| 事件關聯 | 依賴 join、transaction 和 stats 等明確指令。 |
內建功能:定義多個事件,並根據查詢邏輯中的通用欄位建立關聯。 |
| 時間區間設定 | 視為靜態搜尋視窗 (例如 last
60m)。每次新搜尋都是新的要求。 |
系統會將其視為查詢中定義的連續滑動時間範圍 (例如 over 5m)。 |
| 語法 | 指令驅動 (例如 index=web)。 |
簡潔且以邏輯為依據 (例如 metadata.event_type=
"USER_LOGIN")。 |
查詢的特定結構
YARA-L 會強制執行查詢的特定結構,這與 SPL 的循序管道指令不同。SPL 會串連指令來建構結果,而 YARA-L 則會在不同區段中定義查詢的不同層面。
| 指令 | 動作 | 必填 | 選填 |
|---|---|---|
meta
|
設定規則的說明中繼資料,例如作者、說明和嚴重程度。 | 僅適用於規則。 |
events
|
定義及篩選事件。 | 必要 (查詢的核心邏輯)。 |
match
|
依事件分組,並可指定時間範圍 (例如 by 5m)。 |
(選用步驟) 僅適用於多事件關聯查詢。 |
outcome |
計算重要指標並取得洞察資料。 | 選填。 |
condition
|
評估查詢變數條件,判斷結果是否適用 (例如 #event >5)。 |
只有規則需要。搜尋和資訊主頁可選用。 |
dedup |
根據主要變數 (例如 target.user.userid、target.ip>、principal.hostname) 將事件分組,藉此移除重複事件。 |
選填。 |
order
|
根據特定欄位 (例如 asc) 定義,排序收集到的事件結果。 |
選填。 |
limit |
限制查詢傳回的事件數量上限。 | 選填。 |
SPL 和 YARA-L 的常見指令
YARA-L 區段結構可讓您使用 SP 中常見的相同指令。本節將說明兩者的相似之處和差異。
SPL search 指令 = YARA-L events 區段
SPL 中的 search 指令等同於 YARA-L 中的 events 區段。events 部分會定義事件和事件的初始篩選方式。其他區段 (例如 match 或 outcome) 為選用區段,但 events 區段是每條規則的基礎。
例如:
metadata.event_type = "USER_LOGIN"
或:
principal.hostname != "" AND metadata.event_type = "NETWORK_CONNECTION"
在規則 (和進階查詢) 的 events 部分,您可以使用事件變數簡化邏輯。
事件變數可做為篩選器的邏輯分組,代表符合特定條件的特定事件或事件群組。
舉例來說,如要定義事件變數 (例如 $e),請在查詢的 events 區段中,將該變數做為所有相關事件和篩選器的前置字元。然後,您可以在查詢的其他部分 (例如 match 或 outcome) 使用該變數,參照特定事件群組及其資料欄位。
事件變數最常見的用途是在偵測規則中。以下範例說明如何在規則中使用事件變數 ($e) 將事件分組,並找出使用者在一天內登入失敗的次數。如果超過定義的門檻,系統就會觸發規則。
在規則範例中,每個事件都是以事件變數 ($e) 定義。$e 變數也會在 metadata.id 中參照,將規則中繼資料連結回定義的事件。
rule DailyFailedLoginAttempts {
meta:
author = "Alex"
description = "Detects a high number of failed login attempts for a single user within a day."
events:
// Alias for each event
$e.metadata.event_type = "USER_LOGIN"
$e.security_result.action = "FAIL"
$e.principal.user.userid != ""
$userid = $e.principal.user.userid
match:
// Group events by principal.user.userid within a 24-hour window
$userid over 1d
outcome:
// Count the number of unique event IDs for each user per day
$daily_failed_login_count = count($e.metadata.id)
condition:
// Trigger a detection if the daily failed login count exceeds a threshold
// You should adjust this threshold based on your environment's baseline.
#e > 0
}
為確保規則會觸發,您通常需要檢查分組事件的計數。您可以使用事件變數,在 condition 區段中指定最小值。舉例來說,條件 (#e > 0) 會檢查是否至少有一個符合條件的事件。
SPL eval 指令 = YARA-L outcome 區段
eval 指令是基本的 SPL 函式,用於操縱及定義搜尋結果中的欄位值。
- 用途:計算及定義新的欄位值。
- 功能:評估數學、字串或布林運算式。
- 結果:評估結果會建立新欄位,或覆寫現有欄位的值。
- 串連:您可以使用逗號串連多個運算式 (例如
| eval A=1, B=A+1)。 - 循序處理:系統會循序處理鏈結中的運算式,讓後續的計算作業參照先前運算式建立或修改的欄位,並以此為基礎。
下表 (和後續) 中的範例說明瞭這個指令結構:
| 功能 | 說明 | YARA-L 範例 |
|---|---|---|
| 布林運算子 | 在 events 和 condition 中使用。請參閱「在條件部分使用 OR」。 |
|
| 計算結果欄位 | 用於「outcome」部分。 |
|
| 建立動態欄位名稱 | 用於「outcome」部分。 |
請參閱「比較 SPL 與 YARA-L」一文中的範例。 |
範例:建立包含計算結果的新欄位
使用 YARA-L 在每個事件中建立新欄位「bytes」。將「已傳送」bytes欄位和「已接收」bytes欄位中的值相加,即可計算位元組。
metadata.event_type = "SCAN_NETWORK"
principal.hostname != ""
$host = principal.hostname
match:
$host
outcome:
$bytes = cast.as_int(sum(network.sent_bytes))
範例:串連兩個欄位的值
使用半形句號 (.) 字元,將 first_name 欄位中的值與 last_name 欄位中的值串連起來。使用引號 ("") 在兩個欄位之間插入空格字元。串連時,無論實際值為何,系統都會將值讀取為字串。
在 SPL 中,查詢內容會類似於:
| eval full_name = first_name+" "+last_name
在 YARA-L 中,搜尋查詢會類似於以下內容:
principal.user.first_name = $first_name
principal.user.last_name = $last_name
outcome:
$full_name = strings.concat(principal.user.first_name = $first_name
principal.user.last_name = $last_name
outcome:
$full_name = strings.concat($first_name, " ", $last_name))
以登入失敗查詢範例為例,以下範例可讓您找出在 10 分鐘內登入失敗次數達五次以上的使用者 (10m),並使用事件和預留位置變數:
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
target.user.userid = $userid
match:
$userid by 10m
outcome:
$login_count= count(metadata.id)
condition:
$login_count > 5
SPL where 指令 = YARA-L condition 區段
SPL where 指令等同於 YARA-L 中的 events、outcome 或 condition 區段。您可以使用 events 區段宣告事件,並為事件指定特定屬性 (例如 priniciapal.hostname = "xyz")。宣告事件後,您可以使用布林運算子、比較運算子和匯總函式結果 (來自 outcome 區段),定義事件必須符合的參數,查詢才會傳回結果。
以下範例說明如何針對匯總計數設定門檻條件。這項查詢的結構是計算每個使用者 ID 的登入失敗事件總數,然後使用 condition 區段,只輸出記錄五次以上登入失敗的使用者結果。
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
match:
target.user.userid
outcome:
// metadata.id counts all unique events associated with failed logins.
$count = count(metadata.id)
//metadata.id counts all unique events associated with blocked logins.
condition:
$count > 5
SPL dedup 指令 = YARA-L dedup 區段
SPL dedup 指令等同於 YARA-L 中的 dedup 區段。使用 dedup 區段,移除 events 區段中事件指定的任何重複結果。
例如:
principal.hostname = "foo"
dedup:
target.ip
SPL stats 指令 = YARA-L match 或 outcome 區段 (或兩者)
在 SPL 中,匯總作業通常由stats 系列指令處理,這些指令會指定匯總類型 (例如 count、distinct count、max、min) 和 "group by" 欄位。
在 YARA-L 中,match 和 outcome 區段共同提供這項功能:
匯總邏輯:
match區段會定義要納入考量的事件群組 (match: $grouping_field by time),藉此建立匯總。接著,outcome區段會定義要對該群組計算的特定匯總函式 (例如count()、min()、max())。時間區間:
match區段支援指定時間區間,將事件分組。使用over關鍵字 (適用於規則) 或by(適用於搜尋和資訊主頁),例如match: $userid by 1h。這項功能與 SPL 類似,例如"timechart"、"streamstats"和"eventstats"。詳情請參閱「時間視窗」。
範例:計算依主機名稱和目標 IP 分組的位元組總和
以下範例使用 match 區段,根據主機名稱和目標 IP 位址,在一天的時間範圍內定義匯總群組。然後在 outcome 區段中計算傳送的位元組總和。
metadata.event_type = "NETWORK_CONNECTION"
network.sent_bytes > 0
principal.hostname != ""
target.ip != ""
// Define placeholder variables for grouping
$principal_hostname = principal.hostname
$target_ip = target.ip
// Group events by principal hostname, target IP, and day
match:
$principal_hostname, $target_ip by day
// Calculate the sum of sent bytes for each group
outcome:
$daily_bytes_sent = sum(network.sent_bytes)
將 SPL 對應至 YARA-L
SPL 會透過管道指令逐步處理資料,而 YARA-L 則使用以區段為基礎的宣告式結構,定義模式和動作。儘管方法有這些根本差異,YARA-L 的表達能力仍可讓您執行許多與 SPL 相同的工作,從基本篩選到複雜的彙整和關聯性分析,都能輕鬆完成。
本節將說明這些差異,方法是將您熟悉的 SPL 功能對應至 YARA-L 架構中的對等項目。
比較 SPL 與 YARA-L
下表比較常見 SPL 語言中的常見函式和概念,以及 YARA-L 2.0 中的對應項目,或 YARA-L 查詢結構中處理概念的方式。
| SPL 指令或概念 | 用途 | YARA-L 對等項目 | 說明和 YARA-L 對應 | YARA-L 導入範例 |
|---|---|---|---|---|
search |
初始資料篩選 | events 專區 |
定義事件欄位和條件。不需要 events:前置字串即可搜尋或查看資訊主頁。請參閱範例。 |
|
where |
進一步篩選結果 | events 和 condition 區段 |
套用布林邏輯,通常是針對匯總結果。請參閱範例。 |
|
eval |
根據現有欄位、匯總和資料查詢計算新值 | outcome或 events部分 |
請參閱 SPL eval 範例。
|
|
stats |
匯總 (count、sum、平均值) |
match或outcome |
依「match」中的欄位分組。在 outcome 中計算匯總。請參閱「匯總和統計查詢」和「SPL stats 指令」中的範例。 |
|
dedup |
根據一或多個欄位移除重複事件 | dedup 專區 |
指定要用來去重複的欄位。 |
|
table |
定義資料表欄輸出內容 | select 或 unselect
|
用於資訊主頁。在搜尋結果中顯示 outcome 個變數。 |
|
sort |
依遞增或遞減順序顯示結果 | order 專區 |
請參閱下一個表格儲存格中的範例。 |
|
limit |
限制傳回的結果數量 | limit 專區 |
請參閱下一個儲存格中的範例。 |
|
| 多值函式 | 使用 mv* 函式處理 (mvexpand、mvfilter) |
內建支援 | YARA-L 會自動取消事件部分中的巢狀陣列。 如有需要,陣列函式可在 outcome 中使用。 |
請參閱多值函式範例。 |
| 時間區間設定 | earliest=-5m, latest=now |
match部分,over,by |
如要持續偵測,請使用 match: $field over 5m or by 5m。如果是搜尋 UI 中的資訊主頁,請使用 match: $field by 5m。 |
請參閱「時間視窗化」一文中的範例。 |
匯總和統計查詢
在 YARA-L 中,匯總和統計函式通常會放在 outcome 區段,而匯總作業則會放在 match 區段。
stats 指令是在 YARA-L 查詢中實作資料彙整的主要機制。這項功能會將原始事件資料轉換為摘要安全指標。eval 指令會處理欄位層級的逐列轉換 (類似於 SELECT 運算式),而 stats 則會執行集合層級的匯總 (類似於 SQL 中的 GROUP BY)。
下表提供核心語法和用法,說明如何有效使用 stats,根據資料模式和統計離群值導入複雜的安全邏輯。
| SPL 函式 | 說明 | YARA-L 對等項目 | YARA-L 導入範例 |
|---|---|---|---|
count |
計算事件數量。 | count() |
|
dc (count_distinct) |
計算欄位的不重複值數量。 | count_distinct() |
|
sum |
計算欄位值的總和。 | sum() |
|
avg |
計算欄位的平均值。 | avg() |
|
min/max |
找出欄位的最小值或最大值。 | min()或max() |
|
median() |
找出中位數值。 | window.median |
|
first() and last() |
根據搜尋結果中事件的順序傳回值。 | window.first/window.last |
|
STDDEV() |
計算標準差,用來測量資料集的離散程度。 | window.stddv |
|
詳情請參閱其他函式。
舉例來說,多階段查詢可以追蹤多個登入失敗事件,並進行分層匯總。詳情請參閱多階段匯總範例和在 YARA-L 中建立多階段查詢。
多階段匯總 (每小時到每週的平均值)
這個多階段範例會先匯總資料,找出每個主機每小時傳輸的位元組數。接著,系統會使用該匯總資料,計算過去 7 天內每小時的整體平均值。
stage bytes_per_host {
metadata.event_type = "SCAN_NETWORK"
principal.hostname != ""
$host = principal.hostname
match:
$host by hour
outcome:
$bytes = cast.as_int(sum(network.sent_bytes))
}
$host = $bytes_per_host.host
match:
$host
outcome:
$hour_buckets = array_distinct(timestamp.get_timestamp($bytes_per_host.window_start))
$num_hour_buckets = count_distinct($bytes_per_host.window_start)
$avg_hourly_bytes = avg($bytes_per_host.bytes)
多值函式 (讀取陣列)
YARA-L 的語法可瞭解欄位可能有多個值。在 events 區段中撰寫查詢時,如果查詢包含具有多值欄位的事件,語言會自動檢查陣列中的每個值。您不需要使用特殊函式來篩選陣列,只要陳述要比對的條件即可。舉例來說,如果記錄事件的 principal.ip 欄位包含下列內容,YARA-L 引擎會自動檢查 principal.ip 陣列中的每個值。如果任一值為 "10.1.1.5",即符合條件。
["10.1.1.5", "10.2.2.6", "10.3.3.7"]
下表比較 YARA-L 和 SPL,說明如何管理記錄資料中的多值欄位。結構化記錄中常見多值欄位,例如 IP 位址陣列或使用者群組清單。
| SPL 函式 | Purpose | YARA-L 對等項目 | YARA-L 導入範例 |
|---|---|---|---|
mvfilter() |
篩選多值欄位,只保留相符的值。 | 在 YARA-L 查詢的 events 區段中使用時,請列出要比對的欄位。YARA-L 會自動檢查群組陣列中的任何值是否與「`admin`」相符。 |
|
mvcount() |
計算多重值欄位中的值數量。 | count() 套用至 outcome 查詢區段中的欄位。不需要先取消巢狀結構。 |
請參閱「計算屬於 IT 員工群組的使用者人數」範例。 |
mvexpand |
為多重值欄位中的每個值建立新事件。 | 原生且隱含地處理多值欄位,並自動取消巢狀結構。 | 請參閱「計算屬於 IT 員工群組的使用者人數」範例。 |
mvjoin |
將多值欄位中的所有值併入單一字串,以利格式化資料。 | 系統會自動將這些值儲存為結果中的陣列。YARA-L 的輸出內容是結構化內容,而非平面字串。如果需要進一步操控陣列,系統會將欄位顯示為陣列。詳情請參閱陣列函式。 |
範例:計算 admin 登入次數
在下列範例中,條件 $metadata.event_type = "USER_LOGIN" 會篩選 event_type 為 "USER_LOGIN" 的事件:
events:
metadata.event_type = "USER_LOGIN" // Changed to a more appropriate event type for login
principal.user.group_identifiers = "admin"
outcome:
// This counts each unique event ID where the principal user is in the `"admin"` group.
$admin_login_count = count(metadata.id)
$principal.user.group_identifiers= "admin" 欄位是重複欄位 (陣列)。
- 隱含取消巢狀結構:YARA-L 會在查詢評估期間,自動在內部取消巢狀結構這個欄位。
- 條件檢查:如果
$principal.user.group_identifiers陣列中的任何值等於"admin",事件就會符合條件。 - 不需要明確的指令:與 SPL 不同,您不需要
mvexpand等特定取消巢狀結構指令。
「對匯總的影響 (outcome)」一節表示,隱含取消巢狀結構在 outcome 區段中至關重要 (例如 outcome: $admin_login_count = count(metadata.id))。請注意下列影響:
- 如果單一 UDM 事件的重複欄位中有多個相符值,系統可能會產生多個內部資料列,以評估查詢。
- 由於
events區段已根據$principal.user.group_identifiers中的每個相符值,有效取消巢狀結構事件,因此count(metadata.id)匯總會計算每個取消巢狀結構的例項。
範例:計算屬於 IT 員工群組的使用者人數
SPL:
index=<your_index_name> user_id="jsmith"
| where match(memberOf, "Domain Admins|IT Staff|HR")
| mvexpand memberOf
| stats count by memberOf
| mvexpand actions
| table memberOf, count, actions
YARA-L (搜尋):
principal.user.userid = "jsmith"
additional.fields["memberOf"] = $group
$group = /Domain Admins|IT Staff|HR/ nocase
match:
$group by 1h
outcome:
$group_count = count_distinct(metadata.id)
$memberOf = array_distinct($group)
$risk_score = max(50)
範例:建立規則,在出現特定檔案雜湊時發出警示
SPL:
| eval file_hashes="hash12345,hash67890,hashABCDE"
| makemv delim="," file_hashes
| mvexpand file_hashes
| search file_hashes="hash67890"
| table _time, file_hashes
YARA-L (規則):
rule specific_file_hash_detected {
meta:
rule_name = "Specific File Hash Detected"
description = "Detects events where a specific file hash is present."
severity = "Medium"
events:
$e.target.file.sha256 == "hash67890"
outcome:
$time = array_distinct($e.metadata.event_timestamp)
$file_hashes = array_distinct($e.target.file.sha256)
condition:
$e
}
時間區間設定
在 YARA-L 中,時間區間是一種方法,可將特定滾動時間範圍內的事件相互關聯。在規則中使用時,這個時間區間會隨著傳入的資料持續移動,因此可持續即時偵測隨時間變化的模式。
這個程序是自動偵測設計的重要環節,也是使用 YARA-L 的優點之一。指定時間範圍後,偵測結果和資訊主頁就會持續使用即時資料。
| 功能 | SPL | YARA-L |
|---|---|---|
| 主要目標 | 靜態搜尋、隨選分析 | 持續偵測、自動關聯 |
| 主要功能 |
earliest, latest, span, transaction
|
over、by |
| 5 分鐘範例 | earliest=-5m (靜態搜尋)或
transaction maxspan=5m
|
match:[event] over 5m (規則中的持續偵測)或
[event] by 5m (搜尋和資訊主頁)
|
本節的範例說明 YARA-L 中滑動時間視窗 (使用 by) 和滑動時間視窗 (使用 over) 的差異。
滾動式時間區間 (by <time_unit>)
概念:用於 YARA-L 搜尋,滾動式時間區間會建立固定大小的固定時間間隔,且不會重疊。系統會根據每個事件的時間戳記,將事件指派給一個特定時間值區。這些固定間隔是絕對值,且嚴格遵守標準時間標記,例如天、小時或分鐘。
用途:通常用於 Google SecOps 搜尋查詢和資訊主頁,將資料匯總到不連續的時間區隔。
示例:每位使用者每天成功登入的次數
這項搜尋查詢會依每個日曆天中每位不重複的使用者,將登入成功事件分組。以下範例說明 YARA-L 搜尋的滾動時間範圍 (by day):
events:
//Filter for successful login events
metadata.event_type = "USER_LOGIN"
principal.user.userid != ""
match:
//Group by each unique user ID, aggregated over a calendar day.
principal.user.userid by day
outcome:
//Count how many successful logins occurred for this user on this specific day.
$daily_success_count = count(metadata.id)
//Get the timestamp of the FIRST event within this daily group.
$first_event_time = window.first(metadata.event_timestamp.seconds, timestamp.get_timestamp(metadata.event_timestamp.seconds))
//Get the timestamp of the LAST event within this daily group.
$last_event_time = window.last(metadata.event_timestamp.seconds, timestamp.get_timestamp(metadata.event_timestamp.seconds))
運作方式:如果使用者 jdoe 在 Nov 17 成功登入 10 次,在 Nov 18 成功登入 15 次,這項查詢會為 jdoe 產生兩列資料,每天各一列,並分別列出登入次數。「Nov 17」類別包含來自「2025-11-17 00:00:00 to 23:59:59 UTC」的活動。
滑動時間範圍 (over <duration>)
概念:滑動時間區間用於 YARA-L 規則,是指定時間長度的移動時間區間,可能重疊。這類事件最適合用來關聯在彼此附近發生的事件。
用途:主要用於 YARA-L 規則,偵測連續時間範圍內的模式或事件序列。
範例:在 5 分鐘內偵測到多次登入失敗
如果單一使用者在任何滾動 5-minute 期間內嘗試超過 5 failed logins 次,這項 YARA-L 規則範例就會產生偵測結果:
rule TooManyFailedLogins_SlidingWindow {
meta:
author = "Alex"
description = "Detects when a user has more than 5 failed logins within a 5-minute sliding window."
severity = "Medium"
events:
// Define an event variable $e for failed login attempts
$e.metadata.event_type = "USER_LOGIN"
$e.security_result.action = "FAIL"
$e.principal.user.userid != ""
$userid = $e.principal.user.userid
match:
// Group events by userid over a continuous 5-minute sliding window.
// Any events for the same $userid within 5 minutes of each other are grouped.
$userid over 5m
outcome:
// Count the number of failed login events within each 5-minute window for the grouped userid.
$failed_count = count($e.metadata.id)
condition:
// Trigger a detection if the count of failed logins in ANY 5-minute window is greater than 5.
#e > 5
}
運作方式:系統會持續監控登入失敗次數。系統會考量每位使用者在過去 5 分鐘內發生的事件。舉例來說,如果使用者 jdoe 在 10:02:30 和 10:07:30 之間累積六次登入失敗,系統就會觸發偵測。這個時間範圍會不斷向前滑動,因此無論日曆界線為何,系統都能即時偵測模式。
後續步驟
- 深入瞭解 YARA-L 2.0 總覽
- 瞭解完整的 YARA-L 2.0 語言語法
- 瞭解如何撰寫 Detection Engine 規則
- Google SecOps 部落格新訊
還有其他問題嗎?向社群成員和 Google SecOps 專業人員尋求答案。