YARA-L 2.0 已知问题和限制

本文档面向希望调试规则逻辑并优化 YARA-L 2.0 执行的检测工程师。它介绍了如何处理非标准引擎行为,例如字段取消嵌套、汇总中的笛卡尔积扩展以及信息增补的最终一致性。按照这些方法,您可以防止逻辑错误导致结果值膨胀或检测遗漏。

YARA-L 2.0 使用特定的执行模型,其中重复字段在评估期间会扩展为单独的事件行。由于此转换发生在引擎级别,因此引用多个重复字段或对无符号 UDM 类型执行算术运算需要使用特定的语法变通方法,以避免编译器错误或不正确的结果集。本文档概述了这些技术限制以及解决这些限制所需的逻辑模式。

准备工作

在测试或修改 YARA-L 2.0 规则之前,请确保您的账号具有以下技术权限:

所需 IAM 角色

  • roles/chronicle.viewer(安全运营查看者):用于查看现有规则和检测元数据。
  • roles/chronicle.editor(安全运营编辑器):用于修改规则逻辑并保存更改。

所需权限

  • 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)时,取消嵌套会同时发生在父级和子级。这会导致所有元素的笛卡尔积。

在以下示例中,事件 $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 ALLOW
aaaaaaaaa Google SecOps FAIL
aaaaaaaaa Google SecOps CHALLENGE
aaaaaaaaa Google SecOps BLOCK

对无关字段的影响

当规则引用一个或多个重复字段,且父字段也是重复字段时,规则评估中的这种取消嵌套行为可能会产生意外的结果汇总。非不同汇总(例如 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 ALLOW
aaaaaaaaa Google SecOps google.com FAIL
aaaaaaaaa Google SecOps google.com CHALLENGE
aaaaaaaaa Google SecOps google.com BLOCK

取消嵌套行为的变通方法

为确保在发生取消嵌套时结果值准确无误,请使用所选汇总的不同版本。以下函数会忽略取消嵌套创建的重复行:

  • 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

这可能会导致最大总和为 6,即使 $e2 只能对应于 3 个不同的事件也是如此。

这会影响总和、计数和数组。对于计数和数组,使用 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" AND $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 触发的可能性。这提高了规则的整体精确度。

了解如何排查信息增补延迟问题。

问题排查

本部分概述了性能预期,并针对实时检测行为与测试结果不同的常见问题提供了自助式修复。

未来日期的事件

多事件规则旨在按提取时间顺序处理事件。如果您指定并激活多事件规则,该规则不会为具有未来时间戳的事件创建检测,例如当 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"),但规则仍会触发,因为该字段在初始运行期间为 null。 向事件部分添加非 null 检查,以确保在评估之前增补数据,例如:

$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 专业人士的解答。