结果部分语法

支持的平台:

YARA-L 查询的 outcome 部分定义了结果变量,用于指定搜索和信息中心查询的输出,以及在触发规则时检测到的其他上下文和信息。这些变量可用于各种用途,例如在信息中心内显示相关数据和创建风险评分。

定义结果部分

使用 $ 字符,后跟变量名称,可在单个查询的 outcome 部分中定义结果变量。您最多可以定义 20 个结果变量。变量名称本身是任意的。对于规则,系统会根据每次检测计算并汇总结果值。

使用表达式为每个结果变量分配一个值。

此规则会搜索来自新位置的登录失败事件:

rule failed_logins
{
  meta:
   author = "Security Team"
   description = "Detects multiple failed user logins within 10-minute windows."
   severity = "HIGH"

  events:
   $e.metadata.event_type = "USER_LOGIN"
   $e.security_result.action = "FAIL"
   $user = $e.target.user.userid

  match:
   $user over 10m

  outcome:
   $failed_login_count = count($e.metadata.id)
   $first_fail_time = min($e.metadata.event_timestamp.seconds)

  condition:
   #e >= 5
}

outcome 部分对事件和占位变量执行了汇总操作:统计登录失败次数、统计不同的 IP 数,并获取发生失败的时间。

outcome:
   $failed_login_count = count($e.metadata.id)
   $first_fail_time = min($e.metadata.event_timestamp.seconds)

如果您包含并填充了特殊的 $risk_score 结果变量,则其值(整数或浮点数)会显示在查询生成的提醒的提醒和 IoC 页面上。

如果您未在查询的 outcome 部分中添加 $risk_score 变量,系统会设置以下默认值之一:

  • 如果查询配置为生成提醒,则 $risk_score 设置为 40。

  • 如果查询未配置为生成提醒,则 $risk_score 设置为 15。

$risk_score 的值存储在 security_result.risk_score UDM 字段中。

风险得分结果变量

Google SecOps 风险分析会自动将检测结果和提醒与检测结果或提醒相关的实体关联起来。risk_score 结果变量用于分配风险量。如果未设置此值,则使用默认的检测或提醒值。您可以在“设置”中配置默认值。

为确保整个平台的一致性,我们建议您在为自定义检测分配 risk_score 时使用以下得分范围。这种一致性有助于标准化警报优先级和响应工作流程。

严重程度 得分范围 说明 示例
提醒 - 严重 90 - 100 正在进行的入侵,可能会对单个用户账号或端点以外的范围造成影响。需要立即审核。 在网域控制器上执行的 Mimikatz。
提醒 - 高 80 - 89 单个端点或实体的活跃入侵。应立即接受审核。 生产环境服务器调用最近已知的 C2。
提醒 - 中 50 - 79 需要调查的潜在安全问题。未确认设备被破解,但可能会升级。 凭据泄露,但未发现滥用迹象。
非提醒 - 低 20 - 49 低影响安全事件,与其他指标或观测结果结合使用时,可能会导致更严重的事件。一般无需审核,可通过复合规则与其他检测结果结合使用,以创建提醒。 内部端口扫描。
非提醒型观测结果 1 - 19 通常,基于信息的检测旨在建立对威胁的情境感知。通常不需要审核;可以通过复合规则与其他检测结果结合使用,以生成提醒。 登录事件,无滥用迹象。

由于 risk_score 是结果变量,因此您的规则可以根据威胁情报或其他并发条件等因素来表达细微差别。

实体风险得分可用于近乎实时地生成基于风险的提醒。如需了解详情,请参阅风险分析概览

结果变量数据类型

每个结果变量可以具有不同的数据类型,该数据类型由用于计算结果变量的表达式决定。Google SecOps 支持以下结果数据类型:

  • 整数
  • 浮点数
  • 字符串
  • 整数列表
  • 浮点数列表
  • 字符串列表

条件逻辑

您可以使用条件逻辑来计算结果的值。条件使用以下语法模式指定:

if(BOOL_CLAUSE, THEN_CLAUSE)
if(BOOL_CLAUSE, THEN_CLAUSE, ELSE_CLAUSE)

您可以将条件表达式理解为“如果 BOOL_CLAUSE 为 true,则返回 THEN_CLAUSE,否则返回 ELSE_CLAUSE”。

BOOL_CLAUSE 的求值结果必须为布尔值。BOOL_CLAUSE 表达式采用的格式与 events 部分中的表达式类似。例如,该表达式可以包含以下内容:

  • 具有比较运算符的 UDM 字段名称:

    if($context.graph.entity.user.title = "Vendor", 100, 0)

  • events 部分中定义的占位符变量:

    if($severity = "HIGH", 100, 0)

  • outcome 部分中定义的另一个结果变量:

    if($risk_score > 20, "HIGH", "LOW")

  • 返回布尔值的函数:

    if(re.regex($e.network.email.from, `.*altostrat.com`), 100, 0)

  • 参考列表中查找:

    if($u.principal.hostname in %my_reference_list_name, 100, 0)

  • 汇总比较:

    if(count($login.metadata.event_timestamp.seconds) > 5, 100, 0)

TheNN_CLAUSE 和 ELSE_CLAUSE 必须是相同的数据类型。我们支持整数、浮点数和字符串。

如果数据类型为整数或浮点数,则可以省略 ELSE_CLAUSE。如果省略,则 ELSE_CLAUSE 计算结果为 0。例如:

`if($e.field = "a", 5)` is equivalent to `if($e.field = "a", 5, 0)`

如果数据类型为字符串,或者 THEN_CLAUSE 是占位变量或结果变量,则必须提供 ELSE_CLAUSE。

数学运算

您可以使用数学运算来计算查询的 outcomeevents 部分中的整数或浮点数据类型。Google Security Operations 支持加法、减法、乘法、除法和模数作为计算中的顶级运算符。

以下代码段是 outcome 部分中的一个计算示例:

outcome:
  $risk_score = max(100 + if($severity = "HIGH", 10, 5) - if($severity = "LOW", 20, 0))

只要每个操作数和整个算术表达式都经过适当的汇总(请参阅汇总),就可以对以下类型的操作数执行数学运算:

  • 数字事件字段
  • events 部分中定义的数值占位符变量
  • outcome 部分中定义的数值结果变量
  • 返回整数或浮点数的函数
  • 返回整数或浮点数的聚合

不允许对浮点数取模。

结果中的占位符变量

计算结果变量时,您可以使用在查询的事件部分中定义的占位符变量。在此示例中,假设在规则的事件部分定义了 $email_sent_bytes

示例:不含匹配部分的单事件

// No match section, so this is a single-event query.

outcome:
  // Use placeholder directly as an outcome value.
  $my_outcome = $email_sent_bytes

  // Use placeholder in a conditional.
  $other_outcome = if($file_size > 1024, "SEVERE", "MODERATE")

condition:
  $e

示例:包含匹配部分的多事件

match:
  // This is a multi event query with a match section.
  $hostname over 5m

outcome:
  // Use placeholder directly in an aggregation function.
  $max_email_size = max($email_sent_bytes)

  // Use placeholder in a mathematical computation.
  $total_bytes_exfiltrated = sum(
    1024
    + $email_sent_bytes
    + $file_event.principal.file.size
  )

condition:
  $email_event and $file_event

结果分配表达式中的结果变量

结果变量可用于派生其他结果变量,类似于 events 部分中定义的占位符变量。您可以在分配其他结果变量时引用某个结果变量,方法是使用 $ 令牌,后跟变量名称。必须先定义结果变量,然后才能在查询文本中引用它们。在赋值表达式中使用时,结果变量不得进行聚合(请参阅聚合)。

在以下示例中,结果变量 $risk_score 的值源自结果变量 $event_count

示例:从另一个结果变量派生的结果变量

match:
  // This is a multi event query with a match section.
  $hostname over 5m

outcome:
  // Aggregates all timestamp on login events in the 5 minute match window.
  $event_count = count($login.metadata.event_timestamp.seconds)

  // $event_count cannot be aggregated again.
  $risk_score = if($event_count > 5, "SEVERE", "MODERATE")

  // This is the equivalent of the 2 outcomes combined.
  $risk_score2 = if(count($login.metadata.event_timestamp.seconds) > 5, "SEVERE", "MODERATE")

condition:
  $e

结果变量可用于结果分配右侧的任何类型的表达式,但以下表达式除外:

  • 数据汇总
  • Arrays.length() 函数调用
  • 使用 anyall 修饰符

数据汇总

重复事件字段是非标量值。也就是说,单个变量指向多个值。例如,事件字段变量 $e.target.ip 是一个重复字段,可以包含零个、一个或多个 IP 值。它是一个非标量值。而事件字段变量 $e.principal.hostname 不是重复字段,仅包含 1 个值(即标量值)。

同样,在具有匹配窗口的查询的 outcome 部分中使用的非重复事件字段和重复事件字段都是非标量值。

示例:包含匹配部分和非重复字段的群组事件

以下查询使用“match”部分对事件进行分组,并在“outcome”部分中引用非重复事件字段:

rule OutcomeAndMatchWindow{
  ...
  match:
    $userid over 5m
  outcome:
    $hostnames = array($e.principal.hostname)
  ...
}

查询执行的任何 5 分钟窗口都可能包含零个、一个或多个事件。结果部分会处理匹配窗口中的所有事件。结果部分中引用的任何事件字段变量都可以指向匹配窗口中每个事件的零个、一个或多个字段值。例如,如果 5 分钟的时间段内包含 5 个 $e 事件,则结果部分中的 $e.principal.hostname 会指向 5 个不同的主机名。在此查询的 outcome 部分,事件字段变量 $e.principal.hostname 被视为非标量值。

由于结果变量必须始终产生单个标量值,因此任何结果分配所依赖的非标量值都必须进行聚合,以产生单个标量值。 在结果部分中,以下是非标量值,必须进行汇总:

  • 当查询使用 match 部分时,事件字段(重复或非重复)
  • 当查询使用 match 部分时,事件占位符(重复或非重复)
  • 当查询未使用 match 部分时,重复的事件字段
  • 当查询未使用 match 部分时,重复的事件占位符

在不包含 match 部分的查询中,标量事件字段、标量事件占位符和常量可以封装在聚合函数中。不过,在大多数情况下,这些聚合会返回封装的值,因此没有必要使用它们。不过,array() 聚合是一个例外,您可以使用它将标量值显式转换为数组。

结果变量的处理方式与聚合类似:在其他结果分配中引用时,不得重新聚合。

您可以使用以下聚合函数:

聚合函数 说明
max() 输出所有可能值的最大值。仅适用于整数和浮点数。
min() 输出所有可能值的最小值。仅适用于整数和浮点数。
sum() 输出所有可能值的总和。仅适用于整数和浮点数。
count_distinct() 收集所有可能的值,然后输出不同数量的可能的值。
count() 行为类似于 `count_distinct()`,但会返回相同数量的可能的值。
array_distinct() 收集所有可能的不同值,然后输出这些值的列表。它会将不同的值列表截断为 1,000 个随机元素。系统会先进行去重以获得不重复的列表,然后再进行截断。
array() 行为类似于 array_distinct(),但会返回一个包含重复值的列表。它也会将值列表截断为 1,000 个随机元素。

当规则包含指定必须存在多个事件的 condition 部分时,聚合函数很重要,因为聚合函数会对生成检测的所有事件进行运算。

示例:针对多个事件的条件

以下是针对多个事件的条件的示例。如果您的结果和条件部分包含:

outcome:
  $asset_id_count = count($event.principal.asset_id)
  $asset_id_distinct_count = count_distinct($event.principal.asset_id)

  $asset_id_list = array($event.principal.asset_id)
  $asset_id_distinct_list = array_distinct($event.principal.asset_id)

condition:
  #event > 1

由于“condition”部分要求每项检测存在多个“event”,因此聚合函数将对多个事件进行运算。假设以下事件生成了一项检测:

event:
  // UDM event 1
  asset_id="asset-a"

event:
  // UDM event 2
  asset_id="asset-b"

event:
  // UDM event 3
  asset_id="asset-b"

则结果的值将是:

    $asset_id_count = 3
    $asset_id_distinct_count = 2
    $asset_id_list = `["asset-a", "asset-b", "asset-b"]
    $asset_id_distinct_list = `["asset-a", "asset-b"]

限制

  • outcome 部分不能引用尚未在 events 部分或 outcome 部分中定义的新占位符变量。

  • outcome 部分不能使用尚未在 events 部分中定义的事件变量。

  • outcome 部分可以使用未在 events 部分中使用的事件字段,前提是该事件字段所属的事件变量已在 events 部分中定义。

  • outcome 部分只能关联已在 events 部分中关联的事件变量。当来自不同事件变量的两个事件字段相等时,就会发生相关性。

如需查看 outcome 部分的示例,请参阅 YARA-L 2.0 概览

如需详细了解如何通过 outcome 部分对检测进行重复数据删除,请参阅创建情境感知分析

后续步骤

其他信息

需要更多帮助?获得社区成员和 Google SecOps 专业人士的解答。