表达式、运算符和其他结构

支持的环境:

本文档包含的信息可帮助您使用表达式构建 YARA-L 规则和查询。

布尔表达式

布尔表达式是布尔类型的表达式,包括比较表达式、函数表达式以及引用列表或数据表表达式。您可以在 YARA-L 规则或查询的 eventsoutcome 部分中使用布尔表达式。

比较表达式

比较表达式是指对两个表达式应用比较运算符的表达式。表达式可以是事件字段、变量、字面量或函数表达式。

示例:比较表达式

$e.source.hostname = "host1234"
$e.source.port < 1024
1024 < $e.source.port
$e1.source.hostname != $e2.target.hostname
$e1.metadata.collected_timestamp.seconds > $e2.metadata.collected_timestamp.seconds
$port >= 25
$host = $e2.target.hostname
"google-test" = strings.concat($e.principal.hostname, "-test")
"email@google.org" = re.replace($e.network.email.from, "com", "org")

函数表达式

某些函数表达式会返回布尔值,可用作 events 部分中的单个谓词,例如:

re.regex()

net.ip_in_range_cidr()

示例:函数表达式

re.regex($e.principal.hostname, `.*\.google\.com`)
net.ip_in_range_cidr($e.principal.ip, "192.0.2.0/24")

引用列表或数据表

您可以在 eventsoutcome 部分中使用引用列表或数据表。如需详细了解引用列表和数据表的行为和语法,请参阅引用列表使用数据表

示例:引用列表的语法

以下示例展示了查询中各种类型的引用列表的语法:

// STRING reference list
$e.principal.hostname in %string_reference_list

// Regular expression reference list
$e.principal.hostname in regex %regex_reference_list

// CIDR reference list
$e.principal.ip in cidr %cidr_reference_list

示例:数据表的语法

// STRING data table
$e.target.hostname in %data_table_name.column_name

// Regular expression data table
$e.target.hostname in regex %regex_table_name.column_name

// CIDR data table
$e.principal.ip in cidr %cidr_table_name.column_name

示例:在引用列表语法中使用 notnocase

// Exclude events whose hostnames match substrings in my_regex_list.
not $e.principal.hostname in regex %my_regex_list

// Event hostnames must match at least 1 string in my_string_list (case insensitive).
$e.principal.hostname in %my_string_list nocase

nocase 运算符与 STRING 列表和 REGEX 列表兼容。

出于性能方面的原因,引用列表和数据表的使用存在以下限制:

  • 查询中 in 语句的最大数量(无论是否包含特殊运算符):10
  • 包含 regex 运算符的 in 语句的最大数量:5
  • 包含 cidr 运算符的 in 语句的最大数量:5

逻辑表达式

您可以在 events 部分中使用逻辑 andor 运算符。

示例:逻辑表达式

$e.metadata.event_type = "NETWORK_DNS" or $e.metadata.event_type = "NETWORK_DHCP"
($e.metadata.event_type = "NETWORK_DNS" and $e.principal.ip = "192.0.2.12") or ($e.metadata.event_type = "NETWORK_DHCP" and $e.principal.mac = "AB:CD:01:10:EF:22")
not $e.metadata.event_type = "NETWORK_DNS"

默认情况下,优先级从高到低的顺序是 notandor。例如,如果在表达式中明确定义了运算符 orand,则“a or b and c”会被评估为“a or (b and c)”。

events 部分中,如果未明确定义运算符,则谓词会使用 and 运算符联接。如果表达式中隐含了 and 运算符,则评估顺序可能会有所不同。 请考虑以下比较表达式,其中明确定义了 or,而隐含了 and 运算符。

$e1.field = "bat"
or $e1.field = "baz"
$e2.field = "bar"

其解读如下:

($e1.field = "bat" or $e1.field = "baz")
and ($e2.field = "bar")

由于明确定义了 or,因此系统会先对周围的谓词进行分组和评估。最后一个谓词是 $e2.field = "bar"。使用 and 隐式联接。结果是评估顺序发生了变化。

逻辑表达式中的数据表查找

events 部分中使用数据表查找(in %list 语法)时,适用以下语法限制:

  • 类型独占:您无法在同一逻辑块中混用标准字段比较(例如 $field = "value")和数据表查找。

  • 运算符限制:数据表查找只能使用 OR 运算符与其他数据表查找联接。这些表达式不支持 AND 运算符。

  • 使用 OR 的事件变量独占:使用 OR 运算符组合数据表查找时,OR 表达式中的所有查找都必须引用来自同一事件变量的字段。例如,($e.user in %table1 OR $e.group in %table2) 是有效的。但是,不支持 ($e.user in %table OR $g.user in %table) 等表达式。这是因为,在 OR 条件下,跨不同事件变量(例如 $e$g)的查找缺少共同的等式锚点,这会导致编译器在运行时失败,并显示 RULE ERROR: error processing rule

示例:语法错误导致结果无效

// Invalid: Mixing a field comparison with a data table lookup
($field = "value" OR $field in %list)

// Invalid: Using AND with data table lookups
($field_A in %list_A AND $field_B in %list_B)

示例:有效示例

// Valid: Multiple data table lookups joined by OR
($field in %list_A OR $field in %list_B)

示例:无效的跨变量 OR

// Invalid: OR condition across different event variables
($e.user in %table OR $g.user in %table)

如果您的逻辑既需要标准字段检查,又需要数据表查找,则必须在 events 部分中将它们定义为单独的独立谓词。

枚举类型

您可以将运算符与枚举类型搭配使用。它可以应用于规则,以简化和优化(使用运算符而不是引用列表)性能。

在以下示例中,“USER_UNCATEGORIZED”和“USER_RESOURCE_DELETION”分别对应于 15000 和 15014,因此该规则将查找所有列出的事件:

$e.metadata.event_type >= "USER_CATEGORIZED" and $e.metadata.event_type <= "USER_RESOURCE_DELETION"

Nocase 修饰符

如需在字符串值或正则表达式之间的比较表达式中忽略大小写,请在表达式末尾附加 nocase,如以下示例所示。

示例:nocase 修饰符

$e.principal.hostname != "http-server" nocase
$e1.principal.hostname = $e2.target.hostname nocase
$e.principal.hostname = /dns-server-[0-9]+/ nocase
re.regex($e.target.hostname, `client-[0-9]+`) nocase

当字段类型是枚举值时,不能使用 nocase 修饰符。以下示例无效,并会产生编译错误:

$e.metadata.event_type = "NETWORK_DNS" nocase
$e.network.ip_protocol = "TCP" nocase

评论

您可以在查询中使用评论来提供更多信息。您可以使用正斜杠字符来表示评论:

  • 对于单行评论,请使用两个正斜杠字符 (// comment)。
  • 对于多行评论,请使用一个正斜杠字符和一个星号字符 (/* comment */)。

字面量

YARA-L 支持非负整数和浮点数、字符串、布尔值和正则表达式字面量。字面量是查询条件中使用的固定值。YARA-L 还使用其他类似字面量的结构,例如用于模式匹配的正则表达式(用正斜杠括起来)和用于逻辑的布尔值 (true/false)。

字符串字面量

字符串字面量是用双引号 (") 或反引号 (`) 括起来的字符序列。字符串的解读方式因您使用的引号类型而异:

  • 双引号 ("hello\tworld"):用于普通字符串;必须包含转义字符,其中 \t 会被解读为制表符。
  • 反引号 (`hello\tworld`):用于按字面解释所有字符,其中 \t 不会被解读为制表符。

正则表达式字面量

对于正则表达式字面量,您有两种选择:

  • 如果您想在不使用 re.regex() 函数的情况下直接使用正则表达式,请使用 /regex/ 作为正则表达式字面量。

  • 如果您想使用字符串字面量作为正则表达式字面量,请使用 re.regex() 函数。请注意,对于双引号字符串字面量,您必须用反斜杠字符转义反斜杠字符,这看起来很奇怪。

以下示例展示了等效的正则表达式:

re.regex($e.network.email.from, `.*altostrat\.com`)

re.regex($e.network.email.from, ".*altostrat\\.com")

$e.network.email.from = /.*altostrat\.com/

Google 建议对正则表达式中的字符串使用英文反引号字符,以便于阅读。

运算符

运算符 说明
= 等于/声明
!= 不等于
< 小于
<= 小于或等于
> 大于
>= 大于或等于

了解如何在 YARA-L 中使用变量

在 YARA-L 中,所有变量都使用语法 $<variable name>。本部分介绍了在 YARA-L 中使用的变量类型。

事件变量

事件变量表示事件组或实体事件。您可以使用名称、事件来源和事件字段在 events 部分中指定事件变量的条件。

  • 事件来源为 udm(用于规范化事件)和 graph(用于实体事件)。如果省略来源,则 udm 设置为默认来源。

  • 事件字段表示为 .<field name> 链(例如 $e.field1.field2),并且字段链始终从顶级来源(UDM 或实体)开始。

匹配变量

匹配变量用于 match 部分,以根据指定时间窗口内的通用值对事件进行分组。

它们会成为查询的分组字段,因为对于每组唯一的匹配变量(以及每个时间范围),都会返回一行。当查询找到匹配项时,将返回匹配变量值。

您可以在 events 部分中指定每个匹配变量表示的内容。

占位符变量

您可以使用占位符变量从 UDM 事件字段捕获和存储特定值,以便在整个查询中引用和使用。 您可以使用它们将分散的事件链接在一起,尤其是在多事件查询中。通过为占位符分配通用值(例如 useridhostname),您可以在 match 部分中使用此占位符,以对指定时间窗口内共享该值的事件进行分组。

您可以在 events 部分中定义占位符变量,方法是将 UDM 字段的值分配给以 $ 为前缀的变量名称(例如 $targetUser = $e.target.user.userid)。

您还可以在以下部分中定义占位符变量:

  • condition 部分,用于指定 match 条件。
  • outcome 部分,用于执行计算、定义指标或从匹配的事件中提取特定数据点。
  • match 部分,用于按通用值对事件进行分组。

函数到占位符的分配

在 YARA-L 中,函数到占位符的分配是指转换 UDM 事件数据并存储结果以供整个规则使用的过程。 此操作可让您在 events 部分中执行计算或数据操作,并在 matchconditionoutcome 部分中引用这些结果。

以下是核心组件:

  • **函数**:内置操作,用于对特定事件字段执行计算或数据转换(例如字符串操作或数学运算)。
  • 占位符变量:用户定义的变量,以 $ 为前缀(例如 $user$ip),充当容器。它们存储直接从事件中提取的值或由函数输出生成的值。
  • 分配:将函数的输出链接到占位符变量的逻辑,使转换后的数据可供其余检测逻辑访问。

限制

使用函数到占位符的分配时,存在以下两个限制:

  1. 您必须将每个占位符分配给包含事件字段的表达式。

    有效示例

    $ph1 = $e.principal.hostname
    $ph2 = $e.src.hostname
    
    // Both $ph1 and $ph2 have been assigned to an expression containing an event field.
    $ph1 = strings.concat($ph2, ".com")
    
    $ph1 = $e.network.email.from
    $ph2 = strings.concat($e.principal.hostname, "@gmail.com")
    
    // Both $ph1 and $ph2 have been assigned to an expression containing an event field.
    $ph1 = strings.to_lower($ph2)
    

    无效示例

    $ph1 = strings.concat($e.principal.hostname, "foo")
    $ph2 = strings.concat($ph1, "bar") // $ph2 has NOT been assigned to an expression containing an event field.
    
  2. 函数调用应依赖于一个且仅一个 事件。但是,函数调用参数中可以使用来自同一事件的多个字段。

    有效示例

    $ph = strings.concat($event.principal.hostname, "string2")

    $ph = strings.concat($event.principal.hostname, $event.src.hostname)

    无效示例

    $ph = strings.concat("string1", "string2")

    $ph = strings.concat($event.principal.hostname, $anotherEvent.src.hostname)

使用关键字定义查询

在 YARA-L 中,关键字是保留字,用于定义检测查询的结构和逻辑。它们用于指定查询的不同部分、执行逻辑和数学运算,以及定义匹配事件的条件。这些关键字不能用作查询、字符串或变量的标识符。

关键字不区分大小写(例如,andAND 是等效的)。

YARA-L 2.0 关键字的主要类别

此列表并不详尽,但涵盖了 YARA-L 2.0 中用于构建可靠检测查询的主要关键字。

  • 查询定义
    • rule:启动新 YARA-L 查询的定义。
    • private:将查询指定为私有,防止其直接公开或在外部触发。
    • global:将查询标记为全局,表示应广泛应用。
  • 查询部分
    • meta:引入元数据部分,用于提供有关查询的说明性信息。
    • strings:表示定义字符串模式的部分。
    • condition:指定包含查询触发的布尔逻辑的部分。
    • events:定义用于指定事件变量及其条件的部分。
    • match:引入用于在时间窗口内聚合值的部分。
    • outcome:定义用于向触发的查询添加上下文和评分的部分。
  • 字符串修饰符
    • ascii:指定字符串应作为 ASCII 文本进行匹配。
    • wide:表示字符串应作为宽字符 (UTF-16) 进行匹配。
    • nocase:执行不区分大小写的字符串匹配。
    • fullword:要求字符串作为完整字词进行匹配。
    • xor:在匹配之前对字符串应用 XOR 转换。
    • base64base64wide:在匹配之前应用 Base64 编码。
  • 逻辑运算符
    • andornot:用于组合条件的标准布尔逻辑运算符。
    • all ofany of:用于评估条件内的多个表达式。
  • 比较和关系运算符
    • at:指定字符串匹配的确切偏移量。
    • contains:检查字符串是否包含子字符串。
    • startswithendswith:检查字符串是否以子字符串开头或结尾。
    • icontainsistartswithiendswithiequals:不区分大小写的版本。
    • matches:用于正则表达式匹配。
  • 数据类型和大小说明符
    • int8uint8int16uint16int32uint32:具有指定大小的整数类型。
    • int8beuint8beint16beuint16beint32beuint32be:整数类型的大端版本。
    • filesize:表示正在分析的文件的大小。
    • entrypoint:指可执行文件的入口点。

YARA-L 映射支持

YARA-L 支持 StructLabel 数据类型的映射,这些数据类型在某些 UDM 字段中使用。

如需在 Struct 和 Label 数据类型中搜索特定的键值对,请使用标准映射语法:

  • Struct 字段语法:$e.udm.additional.fields["pod_name"] = "kube-scheduler"
  • Label 字段语法:$e.metadata.ingestion_labels["MetadataKeyDeletion"] = "startup-script"

示例:映射的有效和无效使用

以下示例展示了映射的有效和无效使用。

映射的有效使用

在 events 部分中使用 Struct 字段

events:
  $e.udm.additional.fields["pod_name"] = "kube-scheduler"
  

在 outcome 部分中使用 Label 字段

outcome:
  $value = array_distinct($e.metadata.ingestion_labels["MetadataKeyDeletion"])
 

将映射值分配给占位符

$placeholder = $u1.metadata.ingestion_labels["MetadataKeyDeletion"]

在联接条件中使用映射字段

// using a Struct field in a join condition between two udm events $u1 and $u2
$u1.metadata.event_type = $u2.udm.additional.fields["pod_name"]

不支持使用映射

anyall 关键字与映射组合

all $e.udm.additional.fields["pod_name"] = "kube-scheduler"

其他类型的值

映射语法只能返回字符串值。对于 [Struct](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct) 数据类型,映射语法只能访问其值为字符串的键。 无法访问其值为其他原始类型(例如整数)的键。

映射中的重复值处理

映射访问旨在检索与特定键关联的单个值。这是标准行为,也是预期行为。 但是,在极少数情况下,map access 的上下文可能会无意中指向多个值。在映射访问引用多个值的罕见极端情况下,map access 将确定性地返回第一个值。如果标签具有重复的键,或者标签具有祖先重复字段,则可能会发生这种情况。

标签具有重复的键

标签结构表示映射,但不强制执行键的唯一性。按照惯例,映射应具有唯一的键,因此 Google SecOps 不建议使用重复的键填充标签。

示例:具有重复键的标签

如果对以下数据示例运行查询文本 $e.metadata.ingestion_labels["dupe-key"],则会返回 第一个可能的值 val1

    // Disrecommended usage of label with a duplicate key:
    event {
      metadata{
        ingestion_labels{
          key: "dupe-key"
          value: "val1" // This is the first possible value for "dupe-key"
        }
        ingestion_labels{
          key: "dupe-key"
          value: "val2"
        }
      }
    }
  

标签具有祖先重复字段

重复字段可能包含作为子字段的标签。顶级重复字段中的两个不同条目可能包含具有相同键的标签。

示例:具有祖先重复字段的标签

如果对以下 数据示例运行查询文本 $e.security_result.rule_labels["key"] ,则会返回第一个可能的值 `val3`:

    event {
      // security_result is a repeated field.
      security_result {
        threat_name: "threat1"
        rule_labels {
          key: "key"
          value: "val3" // This is the first possible value for "key"
        }
      }
      security_result {
        threat_name: "threat2"
        rule_labels {
          key: "key"
          value: "val4"
        }
      }
    }
  

访问映射中的结果变量

本部分介绍了如何以原始数据类型(例如整数、布尔值或这些类型的列表)访问映射中的结果变量,而不是仅以字符串形式访问。您可以使用此功能来提高查询逻辑的灵活性和准确性。

结果数据可在以下字段中找到:

  • 结果值在 variables 字段中保留其原始类型。
  • outcomes 字段存储 string 版本,以实现向后兼容性。

您可以使用 variables 映射访问这些结果值,以检索特定类型或使用数组索引访问序列中的元素。您可以按索引访问序列中的特定项,也可以选择整个序列以单独评估每个值。

语法

$d.detection.detection.variables[OUTCOME_NAME].TYPE_SUFFIX

序列的语法

$d.detection.detection.variables[OUTCOME_NAME].SEQUENCE_TYPE_SUFFIX.TYPE_VALS_SUFFIX

示例:访问映射中的结果变量

访问字符串结果

    $my_string_outcome = $d.detection.detection.variables["outcome_ip"].string_val
   

此示例直接检索字符串值(例如,"1.1.1.1" 如果 outcome_ip 是单个字符串)。

访问整数结果

    $my_int_outcome = $d.detection.detection.variables["outcome_port"].int64_value
    

此示例检索整数值(例如 30)。

使用 Int64Sequence 访问整数列表

   $my_int_list = $d.detection.detection.variables["outcome_ports"].int64_seq.int64_vals
   

此示例检索完整的整数列表,并像 重复字段一样将其取消嵌套(例如 [2, 3, 4])。

从整数列表中访问特定元素

    $first_int = $d.detection.detection.variables["outcome_ports"].int64_seq.int64_vals[0]
    

此示例从列表中检索第一个整数(例如 2)。

访问字符串列表 (StringSequence)

    $my_string_list = $d.detection.detection.variables["outcome_ips"].string_seq.string_vals
    

此示例检索完整的字符串列表,并像 重复字段一样将其取消嵌套(例如["1.1.1.1", "2.2.2.2"])。

从字符串列表中访问特定元素

    $first_ip = $d.detection.detection.variables["outcome_ips"].string_seq.string_vals[0]
    

此示例从列表中检索第一个 IP 地址(例如 "1.1.1.1")。

variables 的可用类型后缀

如需查看支持的后缀的完整列表,请参阅 FindingVariable

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