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.20192.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),系統會同時在父項和子項層級取消巢狀結構。這會產生所有元素的笛卡兒乘積。

在下列範例中,事件 $esecurity_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_distinctarray_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 會優先考量擷取速度,盡快顯示初始快訊。不過,背景擴充程序 (例如解析 GeoIPASNUDM 中繼資料) 採用最終一致性模型。

初始執行 (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 != "",檢查所有經過擴充的欄位 (GeoIPASNFile Path),以同步處理即時和歷來行為。
缺少中繼資料 偵測結果會顯示在資訊主頁中,並附上空白的 GeoIPFile Path 欄位。 這是 T0 執行的預期行為。如要修正這個問題,請在執行時間表中加入 field != "" 檢查,或增加首次執行的偏移量,以便有更多時間擷取資料。

驗證和測試

如要確認規則是否正確處理延遲擴充功能,請執行下列操作:

  1. 找出延遲:找出您認為是偽陽性的偵測結果。在「偵測類型」欄中,檢查是否有 <span class="material-icons">lightbulb</span> 圖示。如果警示沒有這個圖示,表示警示來自初始執行作業,而這類作業最常發生擴充延遲。

  2. 更新規則邏輯:為邏輯中使用的所有已擴充資料點新增 field != "" 檢查。
    範例 (檔案路徑):
    $e.target.process.parent_process.file.full_path != ""

  3. 測試及驗證:

    • 使用「執行測試」功能,確保邏輯仍與預期的歷來資料相符。
    • 填入擴充欄位後,確認規則現在只會在調整期間觸發 (或正確排除)。

詳情請參閱「管理規則執行排程」和「設定規則的自訂排程」。

還有其他問題嗎?向社群成員和 Google SecOps 專業人員尋求答案。