YARA-L 2.0 已知問題和限制
本文適用於想偵錯規則邏輯,並最佳化 YARA-L 2.0 執行的偵測工程師。本文說明如何處理非標準引擎行為,例如欄位取消巢狀結構、彙整中的笛卡爾乘積擴充,以及擴充最終一致性。只要遵循這些方法,就能避免邏輯錯誤,進而防止結果值膨脹或偵測遺漏。
YARA-L 2.0 使用特定執行模型,在評估期間,重複欄位會展開為個別事件資料列。由於這項轉換是在引擎層級進行,因此如要參照多個重複欄位,或對未簽署的 UDM 型別執行算術運算,就必須使用特定語法解決方案,以免發生編譯器錯誤或產生不正確的結果集。本文將說明這些技術限制,以及解決問題所需的邏輯模式。
事前準備
測試或修改 YARA-L 2.0 規則前,請確認帳戶具備下列技術授權:
必要的 IAM 角色
roles/chronicle.viewer(Security Operations 檢視者):查看現有規則和偵測中繼資料。roles/chronicle.editor(Security Operations 編輯者):修改規則邏輯並儲存變更。
所需權限
chronicle.rules.runTest:必須具備這項權限,才能對歷來資料執行「執行測試」功能。chronicle.detections.get:檢查偵測資訊主頁中未巢狀化的事件輸出內容。
重要術語
- UDM (統合式資料模型):用於建構平台中所有擷取安全性遙測資料的標準化結構定義。
- 取消巢狀結構:引擎層級的擴充作業,將包含重複欄位 (陣列) 的單一 UDM 事件擴充為多列。每列代表陣列中的一個獨特元素,這可能會導致規則評估期間出現列乘法。
- T₀ (初始執行):規則首次對傳入的遙測資料執行。這會在「串流」階段發生,通常是在完成背景擴充程序 (例如 GeoIP 或 ASN 調整) 之前。
結果匯總 (含重複欄位取消巢狀結構)
如果規則在含有多個元素的事件變數中參照重複欄位,每個元素都會分割成個別的事件資料列。
舉例來說,事件 $e 中重複欄位 target.ip 的兩個 IP 位址會分成兩個 $e 執行個體,每個執行個體都有不同的 target.ip 值。
rule outbound_ip_per_app {
meta:
events:
$e.principal.application = $app
match:
$app over 10m
outcome:
$outbound_ip_count = count($e.target.ip) // yields 2.
condition:
$e
}
事件記錄:取消巢狀結構前後
本節中的表格說明如何將包含 IP 位址陣列的單一事件,轉換為兩筆不同的記錄。
取消巢狀結構前
下表顯示取消巢狀結構重複欄位前的事件記錄:
| metadata.id | principal.application | target.ip |
|---|---|---|
aaaaaaaaa |
Google SecOps |
[192.0.2.20、192.0.2.28] |
取消巢狀結構後
下表顯示取消巢狀結構重複欄位後的事件記錄:
| metadata.id | principal.application | target.ip |
|---|---|---|
aaaaaaaaa |
Google SecOps |
192.0.2.20 |
aaaaaaaaa |
Google SecOps |
192.0.2.28 |
巢狀重複欄位 (笛卡兒乘積)
如果規則參照巢狀結構中的重複欄位 (例如 security_results.action),系統會同時在父項和子項層級取消巢狀結構。這會產生所有元素的笛卡兒乘積。
在下列範例中,事件 $e 在 security_results 上有兩個重複值,在 security_results.actions 上也有兩個重複值,因此會取消巢狀結構,變成四個執行個體。
rule security_action_per_app {
meta:
events:
$e.principal.application = $app
match:
$app over 10m
outcome:
$security_action_count = count($e.security_results.actions) // yields 4.
condition:
$e
}
巢狀解除巢狀化前的事件記錄
原始記錄會將動作儲存在巢狀陣列結構中。
| metadata.id | principal.application | security_results |
|---|---|---|
aaaaaaaaa |
Google SecOps |
[ { actions: [ ALLOW, FAIL ] }、{ actions: [ CHALLENGE, BLOCK ] } ] |
巢狀結構取消巢狀結構化後的事件記錄
展開後,每個不重複的動作都會成為獨立的資料列,這可能會導致非不重複的匯總資料出現非預期的計數。
| metadata.id | principal.application | security_results.actions |
|---|---|---|
aaaaaaaaa |
Google SecOps |
允許 |
aaaaaaaaa |
Google SecOps |
不通過 |
aaaaaaaaa |
Google SecOps |
挑戰 |
aaaaaaaaa |
Google SecOps |
封鎖 |
對不相關欄位的影響
當規則參照一或多個重複欄位,且父項欄位也是重複欄位時,規則評估中的這項取消巢狀結構行為可能會產生非預期的結果彙整。非相異的匯總 (例如 sum()、array() 和 count()) 無法說明因取消巢狀結構行為而產生的相同事件中,其他欄位的值重複。
在下列範例中,事件 $e 只有一個主機名稱 (google.com),但結果 (hostnames) 會彙整四個未巢狀的相同事件 $e 執行個體,每個執行個體都有重複的 principal.hostname 值。由於 security_results.actions 中重複的值未巢狀化,因此這項結果會產生四個主機名稱 (而非一個)。
rule security_action_per_app {
meta:
events:
$e.principal.application = $app
match:
$app over 10m
outcome:
$hostnames = array($e.principal.hostname) // yields 4.
$security_action_count = count($e.security_results.action) // yields 4.
condition:
$e
}
取消巢狀結構前,含有不相關欄位的事件記錄
主機名稱是單一值,但會與重複的安全結果並列。
| metadata.id | principal.application | principal.hostname | security_results |
|---|---|---|---|
aaaaaaaaa |
Google SecOps |
google.com |
[ { action: [ ALLOW, FAIL ] }、{ action: [ CHALLENGE, BLOCK ] } ] |
取消巢狀結構後,與不相關的欄位一起記錄事件
主機名稱現在會重複出現在四列中,導致 array() 函式會選取四次。
| metadata.id | principal.application | principal.hostname | security_results.action |
|---|---|---|---|
aaaaaaaaa |
Google SecOps |
google.com |
允許 |
aaaaaaaaa |
Google SecOps |
google.com |
不通過 |
aaaaaaaaa |
Google SecOps |
google.com |
挑戰 |
aaaaaaaaa |
Google SecOps |
google.com |
封鎖 |
解決取消巢狀結構行為的替代方案
為確保取消巢狀結構時結果值正確無誤,請使用所選彙整的相異版本。下列函式會忽略取消巢狀結構建立的重複資料列:
max()min()array_distinct()count_distinct()
使用多個事件變數匯總結果
如果規則包含多個事件變數,系統會針對偵測到的每個事件組合,在彙整中顯示個別項目。舉例來說,如果針對下列列出的事件執行範例規則:
events:
$e1.field = $e2.field
$e2.somefield = $ph
match:
$ph over 1h
outcome:
$some_outcome = sum(if($e1.otherfield = "value", 1, 0))
condition:
$e1 and $e2
event1:
// UDM event 1
field="a"
somefield="d"
event2:
// UDM event 2
field="b"
somefield="d"
event3:
// UDM event 3
field="c"
somefield="d"
系統會針對每個事件組合計算總和,讓您在結果價值計算中同時使用事件變數。計算時會使用下列元素:
1: $e1 = event1, $e2 = event2
2: $e1 = event1, $e2 = event3
3: $e1 = event2, $e2 = event1
4: $e1 = event2, $e2 = event3
5: $e1 = event3, $e2 = event1
5: $e1 = event3, $e2 = event2
因此,即使 $e2 最多只能對應 3 個不同的事件,總和仍可能達到 6。
這會影響總和、計數和陣列。如果是計數和陣列,使用 count_distinct 或 array_distinct 即可解決問題,但總和沒有解決方法。
運算式開頭的半形括號
規則編輯器不支援以半形括號開頭的運算式,否則會觸發剖析錯誤。
語法無效
parsing: error with token: ")"
invalid operator in events predicate
下列範例會產生這類錯誤:
($event.metadata.ingested_timestamp.seconds -
$event.metadata.event_timestamp.seconds) / 3600 > 1
有效的語法變體
以下語法變體會傳回相同結果,但語法有效:
$event.metadata.ingested_timestamp.seconds / 3600 -
$event.metadata.event_timestamp.seconds / 3600 > 1
1 / 3600 * ($event.metadata.ingested_timestamp.seconds -
$event.metadata.event_timestamp.seconds) > 1
1 < ($event.metadata.ingested_timestamp.seconds -
$event.metadata.event_timestamp.seconds) / 3600
結果中的索引陣列需要匯總
不允許直接為重複欄位在 outcome 區段中建立陣列索引。這需要暫時的預留位置變數。
outcome:
$principal_user_dept = $suspicious.principal.user.department[0]
解決方法
在 events 區段中,將特定陣列索引擷取至預留位置變數,然後在結果中參照該預留位置。
events:
$principal_user_dept = $suspicious.principal.user.department[0]
outcome:
$principal_user_department = $principal_user_dept
OR 條件不存在
如果您在兩個不同的事件變數之間套用 OR 條件,且規則符合不存在的項目,規則會成功編譯,但可能會產生偽陽性偵測。
舉例來說,下列規則語法可能會比對出含有 $event_a.field = "something" 的事件,即使不應如此:
events:
not ($event_a.field = "something" **or** $event_b.field = "something")
condition:
$event_a and #event_b >= 0
解決方法
將不存在檢查分成每個變數的個別區塊,以維持邏輯完整性。
events:
not ($event_a.field = "something")
not ($event_b.field = "something")
condition:
$event_a and #event_b >= 0
使用未簽署的事件欄位進行算術運算
如果您嘗試在算術運算中使用整數常數,但 UDM 欄位的類型為不帶正負號的整數,系統會顯示錯誤訊息。例如:
events:
$total_bytes = $e.network.received_bytes * 2
標準整數常數預設為帶正負號的整數,與定義為不帶正負號整數的 UDM 欄位 (例如 network.received_bytes) 不相容。
解決方法
您可以透過除法運算,強制整數常數以浮點數形式運作,藉此略過這個錯誤。
events:
$total_bytes = $e.network.received_bytes * (2/1)
GeoIP 擴充功能和最終一致性
在初始擴充階段 (串流和延遲敏感) 中,系統會優先考量速度而非立即準確度,因此可能會遺漏資料,也可能出現偽陽性。系統會在背景繼續擴充資料,但執行規則時可能無法使用資料。這是正常的最終一致性程序。
為避免因資料擴充延遲而造成誤判,請先明確檢查欄位是否為空白,再評估其值。
舉例來說,假設有以下規則事件:
$e.principal.ip_geo_artifact.network.asn = "16509" AND
$e.principal.ip_geo_artifact.location.country_or_region = "United Kingdom"
這項規則的依據是事件必須同時具有 $e.principal.ip_geo_artifact.network.asn = "16509" 和 $e.principal.ip_geo_artifact.location.country_or_region = "United Kingdom",這兩者都是經過擴充的欄位。如果未及時完成擴充,規則就會產生偽陽性。
為避免這種情況,這項規則的較佳檢查方式如下:
$e.principal.ip_geo_artifact.network.asn != "" AND
$e.principal.ip_geo_artifact.network.asn = "16509" AND
$e.principal.ip_geo_artifact.location.country_or_region != "" AND
$e.principal.ip_geo_artifact.location.country_or_region = "United Kingdom"
這項規則可避免事件是由 ASN 16509 的 IP 觸發,但這些 IP 位於英國境外。這有助於提升規則的整體準確度。
瞭解如何排解擴充功能延遲的問題。
疑難排解
本節將說明效能期望,並提供自助式修正方法,解決常見的即時偵測行為與測試結果不同的問題。
日後的活動
多事件規則的設計宗旨,是按照擷取時間順序處理事件。如果您指定並啟用多事件規則,系統不會為時間戳記在未來的事件建立偵測結果,例如 event.timestamp 的日期和時間設定在 ingest.timestamp 之後。
補充資料延遲
Google SecOps 會優先考量擷取速度,盡快顯示初始快訊。不過,背景擴充程序 (例如解析 GeoIP、ASN 或 UDM 中繼資料) 採用最終一致性模型。
初始執行 (T₀)
背景擴充功能完成前,即時引擎可能會評估規則。視邏輯是否依據經過擴充的欄位進行偵測或排除,這可能會導致下列暫時性差異:
負面結果 (偵測延遲):這是常見的結果。如果規則依據的欄位經過擴充 (例如
target.user.department == "Finance"),且該欄位為null,則規則在首次執行時不會相符。偽陽性 (排除項目遺漏):如果規則使用經過擴充的欄位來篩除已知良好的活動 (例如
NOT target.ip_geo_country == "US"),但「排除」資料尚未套用,規則可能會觸發偽陽性。
結算執行作業
這些背景執行作業會在延遲一段時間後 (例如 45 分鐘或 30 小時),重新評估資料。這會「修正」偵測狀態,如下所示:
延遲偵測:在 T₀ 時為「偽陰性」的事件,在完成擴充後會產生偵測結果。
更正:系統中仍會保留任何 T₀ 偽陽性結果,但您可以在 UDM 檢視器中查看完整豐富的資料,手動進行分類。
執行測試差異
「執行測試」工具會對已完成對帳的歷來資料進行操作。由於您執行手動測試時,資料已完全經過擴充,因此可以立即查看「調整」結果。也就是說,您不會看到在初始執行期間發生的 T₀ 偽陰性或排除項目偽陽性。
錯誤修正
請參閱下表,解決即時快訊和測試結果之間的差異。
| 問題 | 說明 | 可執行的修正方式 |
|---|---|---|
| 排除失敗 | 即使有排除條件 (例如 != "ASN_123"),規則仍會觸發,因為在初始執行期間,該欄位為空值。 |
在事件部分新增非空值檢查,確保資料在評估前已擴充,例如:$e.principal.ip_geo_artifact.network.asn != ""
|
| 與測試賽相比 | 即時規則會觸發快訊,但對相同資料執行測試時,系統會顯示 "No Results」。 |
新增 $e.field != "",檢查所有經過擴充的欄位 (GeoIP、ASN、File Path),以同步處理即時和歷來行為。 |
| 缺少中繼資料 | 偵測結果會顯示在資訊主頁中,並附上空白的 GeoIP 或 File Path 欄位。 |
這是 T0 執行的預期行為。如要修正這個問題,請在執行時間表中加入 field != "" 檢查,或增加首次執行的偏移量,以便有更多時間擷取資料。 |
驗證和測試
如要確認規則是否正確處理延遲擴充功能,請執行下列操作:
找出延遲:找出您認為是偽陽性的偵測結果。在「偵測類型」欄中,檢查是否有
<span class="material-icons">lightbulb</span>圖示。如果警示沒有這個圖示,表示警示來自初始執行作業,而這類作業最常發生擴充延遲。更新規則邏輯:為邏輯中使用的所有已擴充資料點新增
field != ""檢查。
範例 (檔案路徑):
$e.target.process.parent_process.file.full_path != ""測試及驗證:
- 使用「執行測試」功能,確保邏輯仍與預期的歷來資料相符。
- 填入擴充欄位後,確認規則現在只會在調整期間觸發 (或正確排除)。
還有其他問題嗎?向社群成員和 Google SecOps 專業人員尋求答案。