YARA-L 中的单事件规则和多事件规则
本文档展示了使用 YARA-L 2.0 编写的查询。每个示例都展示了如何关联查询规则语言中的事件,以识别安全威胁、监控实体行为,以及通过业务逻辑丰富检测结果。
将这些示例用作 YARA-L 2.0 的构建块,包括单事件检测、正则表达式匹配和网络范围过滤。这些示例按功能类别整理,可帮助您从基本逻辑逐步过渡到高级多事件关联和复合检测。
基础语法和基本
本部分中的示例展示了如何有效地关联 UDM 事件,以及如何在规则语言中构建查询。
| 主题 | 示例 |
|---|---|
| 单事件查询 | 初始用户登录搜索; 5 分钟登录检测 |
| 查询和调优 | 基于排除的进程检测 |
| 网络范围和逻辑 | 单次活动匹配(IP 范围) |
| 查询中的正则表达式 | 电子邮件过滤; 主机名正则表达式; 原始日志搜索 |
| 具有通用条件的重复字段 | 可疑登录 IP 验证 |
单事件查询
使用场景:基本检测特定事件类型(例如 USER_LOGIN),无需在时间窗口内进行关联。
关键逻辑:仅使用“事件”和“条件”部分来识别单次发生。单事件规则可以是:
- 没有
match部分的任何规则。 - 包含
match部分和condition部分的规则仅检查是否存在一个事件(例如$e、#e > 0、#e >= 1、1 <= #e、0 < #e)。
示例:初始用户登录搜索
规则
以下规则示例会搜索用户登录 (USER_LOGIN) 事件,并返回在 Google SecOps 账号中存储的企业数据中遇到的首个事件:
rule SingleEventRule {
meta:
author = "noone@altostrat.com"
events:
$e.metadata.event_type = "USER_LOGIN"
condition:
$e
}
搜索
此非汇总搜索示例直接输出各个事件。由于此查询不需要事件关联,因此省略了事件变量(例如 $e1)。
metadata.event_type = "USER_LOGIN"
信息中心
由于此查询逻辑侧重于以原始状态呈现特定的非相关事件,因此它不使用信息中心可视化图表所需的 match 或 outcome 部分。
示例:5 分钟登录检测
规则
以下示例展示了一个单事件规则,该规则使用 match 部分查找在 5 分钟 (5m) 时间范围内至少发生过一次登录事件的任何用户。它会检查用户登录事件是否存在。
rule SingleEventRule {
meta:
author = "alice@example.com"
description = "windowed single event example rule"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.principal.user.userid = $user
match:
$user over 5m
condition:
#e > 0
}
搜索
此统计搜索示例将 activity 汇总到 5 分钟 (5m) 的滚动窗口中,每个用户在每个窗口中输出一行。由于查询侧重于每个窗口的容量计数,因此省略了 event 变量和 condition 部分,因为结果本身就包含一个或多个事件。此版本使用翻滚窗口而非跳跃窗口,以确保结果在平台内正确呈现。
metadata.event_type = "USER_LOGIN"
principal.user.userid = $user
match:
$user by 5m
信息中心
以下示例包含一个 outcome 部分,用于计算每位用户的总事件数,这有助于将数据绘制为随时间变化的统计值。该查询使用翻滚窗口而非跳跃窗口,以确保数据点映射到离散的非重叠存储分区,并为信息中心趋势提供更清晰的可视化效果。
metadata.event_type = "USER_LOGIN"
principal.user.userid = $user
match:
$user by 5m
outcome:
$event_count = count(metadata.id)
查询和调整
使用情形:检测从非标准目录启动的 Windows svchost.exe。
关键逻辑:否定 (not) 与正则表达式匹配相结合。
示例:基于排除的进程检测
规则
以下规则会检查事件数据中是否存在特定模式,如果找到这些模式,则会创建检测结果。此规则包含一个用于跟踪事件类型和 metadata.event_type UDM 字段的变量 $e1。该规则使用 e1 检查正则表达式匹配项是否出现特定次数。当发生 $e1 事件时,系统会创建检测结果。规则中包含 not 条件,以排除某些非恶意路径。您可以添加 not 条件来防止出现假正例。
rule suspicious_unusual_location_svchost_execution
{
meta:
author = "Google Cloud Security"
description = "Windows 'svchost' executed from an unusual location"
yara_version = "YL2.0"
rule_version = "1.0"
events:
$e1.metadata.event_type = "PROCESS_LAUNCH"
re.regex($e1.principal.process.command_line, `\bsvchost(\.exe)?\b`) nocase
not re.regex($e1.principal.process.command_line, `\\Windows\\System32\\`) nocase
condition:
$e1
}
搜索
此示例执行的是非汇总搜索,以输出各个事件。由于此搜索不需要跨多个实例进行事件关联,因此无需使用 $e1 等事件变量。
metadata.event_type = "PROCESS_LAUNCH"
re.regex(principal.process.command_line, `\bsvchost(\.exe)?\b`) nocase
not re.regex(principal.process.command_line, `\\Windows\\System32\\`) nocase
信息中心
此语法包含 match 和 outcome 部分,用于计算一段时间内的事件量。timestamp.get_timestamp() 函数按天对结果进行分桶,以便直观呈现趋势。
metadata.event_type = "PROCESS_LAUNCH"
re.regex(principal.process.command_line, `\bsvchost(\.exe)?\b`) nocase
not re.regex(principal.process.command_line, `\\Windows\\System32\\`) nocase
$date = timestamp.get_timestamp(metadata.event_timestamp.seconds)
match:
$date
outcome:
$event_count = count(metadata.id)
网络范围和逻辑
使用情形:根据特定 IP 子网 (CIDR) 过滤活动,并与多个可能的主机名进行匹配。
主要概念:
net.ip_in_range_cidr():此函数用于检查给定的 IP 地址是否包含在给定的无类别域间路由 (CIDR) 子网中,以进行子网匹配,并用于字符串数组的 OR 运算符。- 逻辑运算符
OR:用于组合多个条件。事件部分中的条件会隐式与AND结合使用。OR运算符会针对多个可能的主机名进行检查。
示例:单事件匹配(IP 范围)
规则
以下示例展示了一条单事件规则,用于搜索两个特定主机名和特定 IP 地址范围之间的匹配项:
rule OrsAndNetworkRange {
meta:
author = "noone@altostrat.com"
events:
// Checks CIDR ranges.
net.ip_in_range_cidr($e.principal.ip, "203.0.113.0/24")
// Detection when the hostname field matches either value using or.
$e.principal.hostname = /pbateman/ or $e.principal.hostname = /sspade/
condition:
$e
}
搜索
以下查询示例用于识别特定 IP 地址位于已定义的 CIDR 范围内且主机名与特定用户模式匹配的事件:
net.ip_in_range_cidr(principal.ip, "203.0.113.0/24")
principal.hostname = /pbateman/ or principal.hostname = /sspade/
由于这是搜索查询,而不是检测规则,因此如果满足过滤条件,系统会自动返回整个事件。match 部分按 principal.ip 和 principal.hostname 对数据进行分组。不需要 condition 部分,并且省略了事件变量 ($e),因为未执行任何事件相关性分析。
信息中心
以下示例查询通过对唯一 IP 和主机名对进行分组来汇总结果:
net.ip_in_range_cidr(principal.ip, "203.0.113.0/24")
principal.hostname = /pbateman/ or principal.hostname = /sspade/
match:
principal.ip, principal.hostname
查询中的正则表达式
使用情形:搜索灵活的字符串模式(例如,电子邮件中的特定网域),同时忽略大小写。此功能最常用于“搜索”和“规则”中。
关键逻辑:使用 /regex/ nocase 进行基本匹配,使用 re.regex() 函数进行复杂的字段分析。
示例:电子邮件过滤
规则
以下 YARA-L 2.0 正则表达式示例搜索从 altostrat.com 网域收到电子邮件的事件。由于 nocase 已添加到 $host 变量 regex 比较和 regex 函数,因此这些比较都不区分大小写。
rule RegexRuleExample {
meta:
author = "noone@altostrat.com"
events:
$e.principal.hostname = $host
$host = /.*HoSt.*/ nocase
re.regex($e.network.email.from, `.*altostrat\.com`) nocase
match:
$host over 10m
condition:
#e > 10
}
搜索
在搜索界面中,此逻辑用于高保真威胁搜寻和数据探索。分析师无需等待自动提醒,即可手动查询 UDM,以发现符合命名惯例的主机名和目标电子邮件网域的具体实例。这是在将这些事件升级为持久检测规则之前验证其数量的主要方法。
principal.hostname = $host
$host = /.*HoSt.*/ nocase
re.regex(network.email.from, `.*altostrat\.com`) nocase
match:
$host over 10m
```
信息中心
以下逻辑通过将 hostname 和 email 遥测数据汇总到 10 分钟 (10m) 的存储分区中,来识别感兴趣的模式。在信息中心内使用时,此逻辑可让分析师直观呈现特定资产(与 host 匹配)与 altostrat.com 网域之间的通信频次。此视图对于监控内部数据移动趋势和识别关键基础设施中的顶级对话者至关重要。
principal.hostname = $host
$host = /.*HoSt.*/ nocase
re.regex(network.email.from, `.*altostrat\.com`) nocase
match:
$host over 10m
```
示例:主机名正则表达式
规则
以下示例用于识别任何日志活动,其中正文 hostname 被识别为 Web (webserver) 或开发 (devserver) 服务器。它使用不区分大小写的正则表达式,以确保命名惯例的差异不会导致检测遗漏。
rule WebServerOrDevServerActivity {
meta:
author = "Alex"
description = "Detects events where the principal hostname is 'webserver' or 'devserver', ignoring case."
severity = "Informational"
events:
$e.principal.hostname = /webserver|devserver/ nocase
condition:
$e
}
搜索
在以下示例中,principal.hostname = /webserver|devserver/ nocase 可匹配 "WebServer01"、"devserver-test"、"MyWebServers" 等主机名。这是查找特定事件的常见用例。
// Use /regex/ followed by nocase for a case-insensitive match
principal.hostname = /webserver|devserver/ nocase
信息中心
虽然此特定示例未在信息中心内直观呈现,但此规则可提供主动提醒和持续检测。与需要手动审核的信息中心不同,此功能可确保系统自动标记并记录检测引擎中的这些服务器上的每项活动,以便立即进行搜索。
示例:搜索原始日志
规则
虽然您可以使用手动搜索进行时间点调查,但检测规则可提供持续的全天候遥测监控。您可以将成功的搜索查询转换为 YARA-L 规则,以自动执行提醒流程。
规则的主要优势:
- 实时提醒:在匹配项进入系统时自动标记。
- 持久保留:无需手动重新输入搜索字词。
- 结果操作:直接输入到检测视图中,供分析师进行分诊和突发事件响应。
搜索
安全分析师经常使用 regex 在 Google SecOps 中搜索原始的未解析日志。此操作可实现灵活的模式匹配,以便查找特定制品,即使这些制品并非完全结构化或已编入索引。该语法使用正斜线:
raw = /host/
此查询会返回出现字符序列 "host" 的任何原始日志行。匹配的原始日志内容示例可能包括 "hostname": "myhost123"。
信息中心
此特定活动类型没有专用信息中心变体。如需大规模直观呈现这些检测结果,您可以:
- 在信息中心构建器中将
metadata.event_type映射到条形图或饼图。 - 跟踪这些事件在 7 天、30 天或 90 天时间范围内的频次,以发现用户行为中的异常情况。
具有通用条件的重复字段
应用场景:审核包含数据列表(重复字段)的事件,确保不存在任何可信的例外情况,例如,验证与登录相关联的每个 IP 地址是否都在已知安全范围之外。
关键逻辑:使用 all 运算符针对特定条件评估重复字段中的每个元素,并演示了如何通过将重复字段分配给占位变量(例如 $ip)来为列表中的每个唯一值创建不同的检测。
示例:可疑登录 IP 验证
规则
以下规则会搜索所有来源 IP 地址在 5 分钟 (5m) 的时间范围内与已知安全的 IP 地址不匹配的登录事件。
rule SuspiciousIPLogins {
meta:
author = "alice@example.com"
events:
$e.metadata.event_type = "USER_LOGIN"
// Detects if all source IP addresses in an event do not match "100.97.16.0"
// For example, if an event has source IP addresses
// ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
// it will be detected since "100.97.16.1", "100.97.16.2",
// and "100.97.16.3" all do not match "100.97.16.0".
all $e.principal.ip != "100.97.16.0"
// Assigns placeholder variable $ip to the $e.principal.ip repeated field.
// There will be one detection per source IP address.
// For example, if an event has source IP addresses
// ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
// there will be one detection per address.
$e.principal.ip = $ip
match:
$ip over 5m
condition:
$e
}
搜索
metadata.event_type = "USER_LOGIN"
// Detects if all source IP addresses in an event do not match "100.97.16.0"
// For example, if an event has source IP addresses
// ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
// it will be detected since "100.97.16.1", "100.97.16.2",
// and "100.97.16.3" all do not match "100.97.16.0".
all principal.ip != "100.97.16.0"
// Assigns placeholder variable $ip to the $e.principal.ip repeated field.
// There will be one detection per source IP address.
// For example, if an event has source IP addresses
// ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
// there will be one detection per address.
principal.ip = $ip
match:
$ip over 5m
信息中心
metadata.event_type = "USER_LOGIN"
// Detects if all source IP addresses in an event do not match "100.97.16.0"
// For example, if an event has source IP addresses
// ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
// it will be detected since "100.97.16.1", "100.97.16.2",
// and "100.97.16.3" all do not match "100.97.16.0".
all principal.ip != "100.97.16.0"
// Assigns placeholder variable $ip to the $e.principal.ip repeated field.
// There will be one detection per source IP address.
// For example, if an event has source IP addresses
// ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
// there will be one detection per address.
principal.ip = $ip
match:
$ip over 5m
高级窗口化
本部分介绍多阶段模式以及由其他规则的活动触发的检测。
| 主题 | 示例 |
|---|---|
| 多事件相关性分析 | 多城市登录检测; 快速创建和删除用户 |
| 查询中的滑动窗口 | 检测缺失的连续事件 |
| 多事件查询 | 高频登录检测 |
| 包含计算结果的多事件查询 | 暴力破解后成功登录; 按时间窗口匹配主机 |
多事件关联
本部分展示了一些示例,说明如何跨多个事件或时间窗口跟踪实体(用户或主机)以识别行为模式。
应用场景:检测不可能的行程,即单个用户在不到 5 分钟 (5m) 的时间内从两个或多个城市登录。
关键逻辑:使用 match 部分按 $user 和 #city > 1 分组,以查找不同的位置值。
示例:多城市登录检测
规则
以下规则会在 5 (5m) 分钟内搜索从两个或多个城市登录过您的企业的用户,其中 $user 是 match 变量,$udm 是事件变量,$city 和 $user 是占位变量:
rule DifferentCityLogin {
meta:
events:
$udm.metadata.event_type = "USER_LOGIN"
$udm.principal.user.userid = $user
$udm.principal.location.city = $city
match:
$user over 5m
condition:
$udm and #city > 1
}
以下说明介绍了此规则的运作方式:
- 对用户名为 (
$user) 的事件进行分组,并在找到匹配项时返回该值 ($user)。 - 时间范围为 5 分钟 (
5m),表示只有间隔不到 5 分钟 (5m) 的事件相关联。 - 搜索事件类型为
USER_LOGIN的事件组 ($udm)。 - 对于该事件组,该规则会将用户 ID 命名为
$user,并将登录城市命名为$city。 - 如果 5 分钟 (
5m) 时间范围内事件组 ($udm) 中的不同city值(以#city表示)数量大于1,则返回匹配项。
搜索
以下示例查询会运行等效的统计搜索,以识别不可能的出行模式。它按用户对 USER_LOGIN 事件进行分组,时间范围为 5 分钟 (5m),并过滤结果以仅显示检测到单个身份有多个不同城市的情况。
events:
metadata.event_type = "USER_LOGIN"
principal.user.userid = $user
principal.location.city = $city
match:
$user over 5m
condition:
#city > 1
信息中心
以下示例查询会生成一个等效的信息中心可视化图表,用于跟踪潜在的账号盗用情况。该查询会按用户在 5 分钟 (5m) 的时间范围内汇总 USER_LOGIN 事件,并过滤出与多个不同城市 (#city) 关联的单个身份,以便您随时间绘制这些高风险的地理位置异常情况。
events:
metadata.event_type = "USER_LOGIN"
principal.user.userid = $user
principal.location.city = $city
match:
$user over 5m
condition:
#city > 1
快速创建和删除用户
使用情形:识别创建后在 4 小时内删除的临时账号。
关键逻辑:基于共享的
$user变量联接两种事件类型(USER_CREATION和USER_DELETION),并比较时间戳。
示例:快速创建和删除用户
规则
以下规则示例可搜索在 4 小时内创建然后删除的用户(4h),其中 $create 和 $delete 是事件变量,$user 是 match 变量,并且没有占位变量:
rule UserCreationThenDeletion {
meta:
events:
$create.target.user.userid = $user
$create.metadata.event_type = "USER_CREATION"
$delete.target.user.userid = $user
$delete.metadata.event_type = "USER_DELETION"
$create.metadata.event_timestamp.seconds <=
$delete.metadata.event_timestamp.seconds
match:
$user over 4h
condition:
$create and $delete
}
搜索
以下示例展示了用于识别快速账号生命周期变化的多事件统计信息搜索。此查询会针对 4 小时窗口内的每位用户输出一行,用于关联身份的创建和删除。
由于搜索默认返回包含指定事件的任何窗口,因此不需要 condition 部分。
$create.target.user.userid = $user
$create.metadata.event_type = "USER_CREATION"
$delete.target.user.userid = $user
$delete.metadata.event_type = "USER_DELETION"
$create.metadata.event_timestamp.seconds <=
$delete.metadata.event_timestamp.seconds
match:
$user over 4h
信息中心
以下示例展示了旨在绘制一段时间内的账号生命周期趋势的多事件信息中心搜索。通过使用翻滚窗口 (by 4h),结果会映射到离散的非重叠时间存储分区,非常适合用于可视化。
此变体包含一个 outcome 部分,用于计算每个窗口内创建事件的去重计数。与之前的搜索不同,此版本不需要返回特定的事件变量,因为重点是汇总统计值,而不是单个日志行。
$create.target.user.userid = $user
$create.metadata.event_type = "USER_CREATION"
$delete.target.user.userid = $user
$delete.metadata.event_type = "USER_DELETION"
$create.metadata.event_timestamp.seconds <=
$delete.metadata.event_timestamp.seconds
match:
$user by 4h
outcome:
$event_count = count_distinct($create.metadata.id)
查询中的滑动窗口
使用情形:检测潜在的安全问题,即在特定时间范围内,初始事件(来自 firewall_1)之后未在同一主机上发生预期的后续事件(来自 firewall_2)。
关键逻辑:
- 透视事件:规则围绕来自
firewall_1的事件展开,这些事件被指定为$e1。每次发生$e1事件时,该事件都会充当透视点。 - 时间窗口:
match部分 ($host over 10m after $e1) 定义了一个 10 分钟的窗口,该窗口从每个$e1事件发生后立即开始。此窗口会随着每个新的$e1事件而滑动。 - 相关性:事件按主机名 (
$host) 分组。 - 检测条件(
$e1和$e2):如果满足以下条件,系统会针对给定主机触发检测:- 存在来自
firewall_1($e1) 的事件。 AND,在特定$e1事件发生后的 10 分钟内,系统会找到来自firewall_2($e2) 的NO事件,该事件的宿主与$e1事件的宿主相同。
- 存在来自
示例:检测缺失的连续事件
规则
以下示例用于识别在主触发器触发后未能发生次要事件的实例。通过在 10 分钟的时间范围内使用 !$e2 条件,此规则会标记缺失的遥测数据,特别是当在某个位置看到防火墙日志,但在下一个预期跃点中未看到该日志时,这表明可能存在可见性差距或流量下降。
rule MissingSequentialEvent {
meta:
author = "alice@example.com"
events:
$e1.metadata.product_name = "firewall_1"
$e1.principal.hostname = $host
$e2.metadata.product_name = "firewall_2"
$e2.principal.hostname = $host
match:
// $e1 is the pivot; the 10-minute window starts at the $e1 timestamp
$host over 10m after $e1
condition:
$e1 and !$e2
}
搜索
以下示例展示了如何使用顺序搜索来识别两个来源之间的遥测数据缺口。通过将 $e1 用作透视,搜索会查找在 10 分钟内未在第二个防火墙上跟有相应事件的主防火墙事件。在调查期间,这是一种非常有效的手动查找网络流量或日志记录故障中的“黑洞”的方法。
$e1.metadata.product_name = "firewall_1"
$e1.principal.hostname = $host
$e2.metadata.product_name = "firewall_2"
$e2.principal.hostname = $host
match:
// $e1 is the pivot; the 10-minute window starts at the $e1 timestamp
$host over 10m after $e1
condition:
$e1 and !$e2
信息中心
以下示例提供了一个旨在用于信息中心视图的曝光度差距分析。通过汇总次要事件未能紧随主要事件发生的情况,您可以直观地了解日志记录流水线随时间推移的可靠性。绘制这些“缺失”事件有助于识别网络可见性或特定主机名中的配置问题。
$e1.metadata.product_name = "firewall_1"
$e1.principal.hostname = $host
$e2.metadata.product_name = "firewall_2"
$e2.principal.hostname = $host
match:
// $e1 is the pivot; the 10-minute window starts at the $e1 timestamp
$host over 10m after $e1
condition:
$e1 and !$e2
多事件查询
应用场景:通过在特定时间窗口内跟踪单个实体(例如用户或主机)的多次事件发生情况,来识别高频或暴力活动。
关键逻辑:使用
match部分按特定变量对事件进行分组,并使用condition部分检查在定义的时间范围内是否达到阈值数量(例如#e >= 10)。
典型的多事件规则包括:
- 用于区分事件的事件变量。
- 一个
match部分,用于指定需要对事件进行分组的时间范围。 condition部分,用于指定应触发检测和检查多个事件是否存在的条件。
在 Google 搜索中,多事件查询是指查询中包含多个事件。对于规则,您可以通过以下两种方式定义此属性:
多个活动(例如
event1 = successful login, event2 = failed login)。基于条件的触发器:条件声明为仅当多个事件满足条件(例如
event1 > 10)时才触发。此类规则还需要包含outcome部分。
示例:高频登录检测
规则
以下规则会搜索在 10 分钟内至少登录了 10 次的用户:
rule MultiEventRule {
meta:
author = "noone@altostrat.com"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.principal.user.userid = $user
match:
$user over 10m
condition:
#e >= 10
}
搜索
以下示例使用多事件统计信息搜索来识别高频登录活动。它会标记单个用户在 10 分钟 (10m) 时间范围内生成 10 个或更多登录事件的任何实例。
$e.metadata.event_type = "USER_LOGIN"
$e.principal.user.userid = $user
match:
$user by 10m
condition:
#e >= 10
信息中心
以下示例使用多事件搜索来监控潜在的账号盗用情况。通过关联 10 分钟滑动窗口内的登录尝试,该功能可识别特定用户和主机多次登录失败后成功登录的情况,让您能够实时直观地了解高风险的身份验证模式。
$e.metadata.event_type = "USER_LOGIN"
$e.principal.user.userid = $user
match:
$user by 10m
condition:
#e >= 10
包含计算结果的多事件查询
使用情形:应用条件逻辑,根据资产严重程度或网络流量设置
risk_score。关键逻辑:使用
outcome部分计算变量,并使用条件部分按这些变量进行过滤。
示例:暴力破解后成功登录
以下示例使用 outcome 部分来统计 match 时间窗口内的事件。此查询生成的输出与标准多事件查询相同,但演示了如何将计算变量纳入检测逻辑中。
规则
rule PossibleBruteForceThenSuccessfulLogin {
meta:
author = "Alex"
description = "Detects multiple failed login attempts followed by a successful login for the same user and host within a 10-minute window."
severity = "High"
tactic = "Credential Access"
events:
// Define the first type of event: Failed Login
// We use $failed to represent any event matching these criteria.
$failed.metadata.event_type = "USER_LOGIN"
$failed.security_result.action = "FAIL"
// Extract common fields to correlate on
$failed.target.user.userid = $user
$failed.principal.hostname = $hostname
// Define the second type of event: Successful Login
// We use $success to represent any event matching these criteria.
$success.metadata.event_type = "USER_LOGIN"
$success.security_result.action = "ALLOW"
// Correlate using the same user and hostname placeholders
$success.target.user.userid = $user
$success.principal.hostname = $hostname
match:
// This section is key for multi-event rules. It groups events:
// - By the common placeholder variables: $user and $hostname.
// - Within a time window: by 10m.
// The rule will evaluate all events matching $failed or $success that share the same $user and $hostname within any given 10-minute period.
$user, $hostname by 10m
outcome:
// Calculate aggregate values from the events within the match window.
$failed_login_count = count($failed.metadata.id)
$successful_login_count = count($success.metadata.id)
condition:
// The conditions that must be met *within each matched group* ($user, $hostname over 10m).
// - #failed >= 5: There must be 5 or more events matching the $failed criteria.
// - #success >= 1: There must be at least 1 event matching the $success criteria.
#failed >= 5 and #success >= 1
}
搜索
// Define the first type of event: Failed Login
// We use $failed to represent any event matching these criteria.
$failed.metadata.event_type = "USER_LOGIN"
$failed.security_result.action = "FAIL"
// Extract common fields to correlate on
$failed.target.user.userid = $user
$failed.principal.hostname = $hostname
// Define the second type of event: Successful Login
// We use $success to represent any event matching these criteria.
$success.metadata.event_type = "USER_LOGIN"
$success.security_result.action = "ALLOW"
// Correlate using the same user and hostname placeholders
$success.target.user.userid = $user
$success.principal.hostname = $hostname
match:
// This section is key for multi-event rules. It groups events:
// - By the common placeholder variables: $user and $hostname.
// - Within a sliding time window: over 10m.
// The rule will evaluate all events matching $failed or $success that share
// the same $user and $hostname within any given 10-minute period.
$user, $hostname over 10m
信息中心
// Define the first type of event: Failed Login
// We use $failed to represent any event matching these criteria.
$failed.metadata.event_type = "USER_LOGIN"
$failed.security_result.action = "FAIL"
// Extract common fields to correlate on
$failed.target.user.userid = $user
$failed.principal.hostname = $hostname
// Define the second type of event: Successful Login
// We use $success to represent any event matching these criteria.
$success.metadata.event_type = "USER_LOGIN"
$success.security_result.action = "ALLOW"
// Correlate using the same user and hostname placeholders
$success.target.user.userid = $user
$success.principal.hostname = $hostname
match:
// This section is key for multi-event rules. It groups events:
// - By the common placeholder variables: $user and $hostname.
// - Within a sliding time window: over 10m.
// The rule will evaluate all events matching $failed or $success that share
// the same $user and $hostname within any given 10-minute period.
$user, $hostname over 10m
示例:时间窗口化主机匹配
规则
以下规则会查看两个事件,以获取 $hostname 的值。如果 $hostname 的值在 5 分钟 (5m) 的时间段内匹配,则应用严重程度得分。在 match 部分中添加时间段时,规则会在指定的时间段内进行检查。
rule OutcomeRuleMultiEvent {
meta:
author = "Google Cloud Security"
events:
$u.udm.principal.hostname = $hostname
$asset_context.graph.entity.hostname = $hostname
$severity = $asset_context.graph.entity.asset.vulnerabilities.severity
match:
$hostname over 5m
outcome:
$risk_score =
max(
100
+ if($hostname = "my-hostname", 100, 50)
+ if($severity = "HIGH", 10)
+ if($severity = "MEDIUM", 5)
+ if($severity = "LOW", 1)
)
$asset_id_list =
array(
if($u.principal.asset_id = "",
"Empty asset id",
$u.principal.asset_id
)
)
$asset_id_distinct_list = array_distinct($u.principal.asset_id)
$asset_id_count = count($u.principal.asset_id)
$asset_id_distinct_count = count_distinct($u.principal.asset_id)
condition:
$u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")
}
搜索
// Define the first type of event: Failed Login
// We use $failed to represent any event matching these criteria.
$failed.metadata.event_type = "USER_LOGIN"
$failed.security_result.action = "FAIL"
// Extract common fields to correlate on
$failed.target.user.userid = $user
$failed.principal.hostname = $hostname
// Define the second type of event: Successful Login
// We use $success to represent any event matching these criteria.
$success.metadata.event_type = "USER_LOGIN"
$success.security_result.action = "ALLOW"
// Correlate using the same user and hostname placeholders
$success.target.user.userid = $user
$success.principal.hostname = $hostname
match:
// This section is key for multi-event rules. It groups events:
// - By the common placeholder variables: $user and $hostname.
// - Within a sliding time window: over 10m.
// The rule will evaluate all events matching $failed or $success that share
// the same $user and $hostname within any given 10-minute period.
$user, $hostname over 10m
outcome:
// Calculate aggregate values from the events within the match window.
$failed_login_count = count($failed.metadata.id)
$successful_login_count = count($success.metadata.id)
```
信息中心
// Define the first type of event: Failed Login
// We use $failed to represent any event matching these criteria.
$failed.metadata.event_type = "USER_LOGIN"
$failed.security_result.action = "FAIL"
// Extract common fields to correlate on
$failed.target.user.userid = $user
$failed.principal.hostname = $hostname
// Define the second type of event: Successful Login
// We use $success to represent any event matching these criteria.
$success.metadata.event_type = "USER_LOGIN"
$success.security_result.action = "ALLOW"
// Correlate using the same user and hostname placeholders
$success.target.user.userid = $user
$success.principal.hostname = $hostname
match:
// This section is key for multi-event rules. It groups events:
// - By the common placeholder variables: $user and $hostname.
// - Within a sliding time window: over 10m.
// The rule will evaluate all events matching $failed or $success that share
// the same $user and $hostname within any given 10-minute period.
$user, $hostname over 10m
outcome:
// Calculate aggregate values from the events within the match window.
$failed_login_count = count($failed.metadata.id)
$successful_login_count = count($success.metadata.id)
复合检测
复合检测通过使用复合规则来增强威胁检测功能。这些复合规则使用其他规则的检测结果作为输入。这样一来,系统就能检测到单个规则可能无法检测到的复杂威胁。如需了解详情,请参阅复合检测概览。
| 主题 | 示例 |
|---|---|
| 高风险过滤 | 检测管理员用户 |
| 汇总和设置阈值 | 风险汇总 |
| 策略聚合 | MITRE 策略聚合 |
| 连续复合检测 | 暴力破解尝试后成功登录 |
| 情境感知检测 | 威胁情报扩充 |
| 共同出现检测 | 权限提升和数据渗出同时发生 |
高风险过滤
使用场景:过滤现有检测结果,以查找涉及管理账号等高风险属性的活动。
关键逻辑:对现有发现中的结果或元数据字段进行操作。
高风险过滤复合检测是最简单的复合检测形式,可对检测结果中的字段(例如结果变量或规则元数据)进行操作。它们有助于过滤可能表明风险较高的条件(例如管理员用户或生产环境)的检测结果。
示例:检测管理员用户
规则
以下复合规则会搜索任何现有检测结果,其中行为者被识别为管理员用户,并应用标准化风险评分。
rule composite_admin_detection {
meta:
rule_name = "Detection with Admin User"
author = "Google Cloud Security"
description = "Composite rule that looks for any detections where the actor is an admin user"
severity = "Medium"
events:
$rule_name = $d.detection.detection.rule_name
$principal_user = $d.detection.detection.variables["principal_users"]
$principal_user = /admin|root/ nocase
match:
$principal_user over 1h
outcome:
$risk_score = 75
$upstream_rules = array_distinct($rule_name)
condition:
$d
}
搜索
以下统计搜索可识别并汇总高权限账号的活动。旨在显示所有触发了涉及“admin”或“root”用户的检测的唯一规则名称。
在此特定查询中,系统会移除时间窗口,以便对所选时间范围内的所有检测结果执行一次统计分析。此外,由于这是针对现有检测数据的非汇总搜索,因此无需提供“事件”部分、“事件变量”和“条件”部分。
$rule_name = detection.detection.rule_name
$principal_user = detection.detection.variables["principal_users"]
$principal_user = /admin|root/ nocase
match:
$principal_user
outcome:
$upstream_rules = array_distinct($rule_name)
信息中心
通过此信息中心查询,您可以直观呈现哪些特定规则最常检测到与管理员相关的活动。旨在提供有关整个环境中的检测趋势的概览。
请注意,与之前的示例相比,match 变量和 outcome 聚合发生了变化。此查询按规则名称对结果进行分组,并计算检测到的每个规则的管理员用户数量。
$rule_name = detection.detection.rule_name
$principal_user = detection.detection.variables["principal_users"]
$principal_user = /admin|root/ nocase
match:
$rule_name
outcome:
$admin_detections = count($principal_user)
聚合和阈值处理
应用场景:识别生成大量提醒或随着时间的推移累积了较高风险得分的用户或主机。
关键逻辑:使用 sum() 或 count_distinct() 分析汇总的检测数据。
借助聚合复合检测规则,您可以根据共享属性(例如主机名或用户名)对检测结果进行分组,并分析汇总的数据。以下是常见的应用场景:
- 识别生成大量安全提醒或汇总风险的用户。
- 通过汇总相关检测结果来检测具有异常活动模式的主机。
示例:风险汇总
规则
此规则会汇总单个用户在 48 小时内的风险得分。它会识别在多次检测中累计风险超过特定阈值的用户。
在此更新后的逻辑中,detection.detection.outcomes 被存储 match 和 outcome 变量的映射字段变量所取代。此外,系统还会移除 $principal_users 结果变量,因为每次检测都只包含一个匹配变量值,而该值已捕获。
rule composite_risk_aggregation {
meta:
rule_name = "Risk Aggregation Composite"
author = "Google Cloud Security"
description = "Composite detection that aggregates risk of a user over 48 hours"
severity = "High"
events:
$rule_name = $d.detection.detection.rule_name
$principal_user = $d.detection.detection.outcomes["principal_users"]
$risk = $d.detection.detection.risk_score
match:
$principal_user over 48h
outcome:
$risk_score = 90
$cumulative_risk = sum($risk)
$upstream_rules = array_distinct($rule_name)
condition:
$d and $cumulative_risk > 500
}
搜索
这种统计搜索会汇总检测数据,以计算用户在 48 小时内的总风险。它会针对每个窗口为每个主用户输出一行,从而提供多种检测类型下的账号风险概览。
在此变体中,不需要事件变量。虽然规则引擎会自动过滤掉没有主用户的检测结果,但此搜索需要显式过滤条件 ($principal_user != "") 来确保结果仅包含已填充的数据。默认情况下,只有当指定用户存在一个或多个检测结果时,查询才会返回结果。
$rule_name = detection.detection.rule_name
$principal_user = detection.detection.variables["principal_user"]
$principal_user != ""
$risk = detection.detection.risk_score
match:
$principal_user over 48h
outcome:
$risk_score = 90
$cumulative_risk = sum($risk)
$upstream_rules = array_distinct($rule_name)
condition:
$cumulative_risk > 500
信息中心
此变体专门针对信息中心而设计,用于绘制用户风险和检测活动随时间变化的情况。它会将数据汇总到离散的桶中,非常适合直观呈现趋势,例如触发的唯一规则数量或每个用户的检测总数。
在此查询中,窗口从滑动(跳跃)窗口切换到翻滚窗口 (by 48h)。这样可确保数据点映射到不重叠的时间段,从而为时序图提供更清晰的可视化效果。与其他未汇总的搜索一样,此搜索不需要事件变量,并且 outcome 部分会展开,以包含规则名称和检测 ID 的不同计数。
$rule_name = detection.detection.rule_name
$principal_user = detection.detection.variables["principal_user"]
$principal_user != ""
$risk = detection.detection.risk_score
match:
$principal_user by 48h
outcome:
$cumulative_risk = sum($risk)
$rule_count = count_distinct($rule_name)
$detection_count = count_distinct(detection.id)
condition:
$cumulative_risk > 500
策略汇总
使用情形:识别活动触发了多个不同的 MITRE ATT&CK 策略检测的用户,这表明攻击生命周期正在推进(例如,从初始访问转变为数据渗漏)。
关键逻辑:使用 count_distinct($tactic) 仅在用户在 48 小时内跨越不同策略的特定阈值时触发。
示例:MITRE 策略聚合
规则
rule composite_tactic_aggregation {
meta:
rule_name = "MITRE Tactic Aggregation Composite"
author = "Google Cloud Security"
description = "Composite detection that detects if a user has triggered detections over multiple mitre tactics."
severity = "Medium"
events:
$principal_user = $d.detection.detection.outcomes["principal_users"]
$tactic = $d.detection.detection.outcomes["mitre_tactic"]
$rule_name = $d.detection.detection.rule_name
match:
$principal_user over 48h
outcome:
$mitre_tactics_count = count_distinct($tactic)
$mitre_tactics = array_distinct($tactic)
$calculated_risk = 50 + (15 * $mitre_tactics_count)
$upstream_rules = array_distinct($rule_name)
condition:
$d and $mitre_tactics_count > 1 }
搜索
以下示例展示了一种搜索变体,该变体专为需要关联现有检测结果并应用动态风险权重的安全开发者而设计。此查询逻辑从 detection 数据源中提取 MITRE ATT&CK 策略和用户信息,按主用户对活动进行分组,并根据观察到的策略的多样性计算自定义风险得分。
detection.detection.outcomes.key = "principal_users"
detection.detection.outcomes.key = "mitre_tactic"
$principal_user = detection.detection.outcomes["principal_users"]
$tactic = detection.detection.outcomes["mitre_tactic"]
$rule_name = detection.detection.rule_name
match:
$principal_user
outcome:
$mitre_tactics_count = count_distinct($tactic)
$mitre_tactics = array_distinct($tactic)
$upstream_rules = array_distinct($rule_name)
$calculated_risk = 50 + (15 * $mitre_tactics_count)
$risk_score = if($calculated_risk > 100, 100, $calculated_risk)
信息中心
以下示例展示了同一检测分析逻辑的信息中心变体。在 Google SecOps 信息中心内使用时,此查询可让开发者通过关联不同规则的检测结果来直观呈现高风险用户。该逻辑会提取主要用户和 MITRE 策略,汇总发现结果,并应用上限风险得分,以帮助直接在信息中心 widget 中确定调查工作的优先级。
detection.detection.outcomes.key = "principal_users"
detection.detection.outcomes.key = "mitre_tactic"
$principal_user = detection.detection.outcomes["principal_users"]
$tactic = detection.detection.outcomes["mitre_tactic"]
$rule_name = detection.detection.rule_name
match:
$principal_user
outcome:
$mitre_tactics_count = count_distinct($tactic)
$mitre_tactics = array_distinct($tactic)
$upstream_rules = array_distinct($rule_name)
$calculated_risk = 50 + (15 * $mitre_tactics_count)
$risk_score = if($calculated_risk > 100, 100, $calculated_risk)
```
顺序复合检测
使用情形:识别操作顺序至关重要的严重攻击模式,例如,检测到仅在同一 IP 地址发出一系列暴力破解尝试警报后才发生的成功账号登录。
关键逻辑:通过以下方式将之前的检测结果与后续的原始 UDM 事件相关联:基于一个共同的变量(例如 $bruteforce_ip)联接它们,并使用时间戳比较来确保事件按正确的顺序发生。
顺序复合检测可识别相关事件的模式,其中检测顺序非常重要,例如暴力破解登录尝试检测,然后是成功登录。这些模式可能涉及多个基本检测结果,也可能涉及基本检测结果和事件的组合。
示例:暴力破解尝试后成功登录
规则
以下复合规则用于识别相关事件的模式,其中序列非常重要。它会专门查找 Google Workspace 暴力破解检测,然后查找同一来源 IP 在 24 小时内发生的成功登录事件。
rule composite_bruteforce_login {
meta:
rule_name = "Bruteforce Login Composite"
author = "Google Cloud Security"
description = "Detects when an IP address associated with a Workspace brute force attempt successfully logs in"
severity = "High"
events:
$bruteforce_detection.detection.detection.rule_name = /Workspace Anomalous Failed Logins/
$bruteforce_ip = $bruteforce_detection.detection.detection.variables["principal_ips"]
$login_event.metadata.product_name = "login"
$login_event.metadata.product_event_type = "login_success"
$login_event.metadata.vendor_name = "Google Workspace"
$login_ip = $login_event.principal.ip
// Ensure the brute force detection and successful login occurred from the same IP
$login_ip = $bruteforce_ip
$target_account = $login_event.target.user.email_addresses
// Ensure the brute force detection occurred before the successful login
$bruteforce_detection.detection.detection_time.seconds < $login_event.metadata.event_timestamp.seconds
match:
$bruteforce_ip over 24h
outcome:
$risk_score = 90
$principal_users = array_distinct($target_account)
condition:
$bruteforce_detection and $login_event
}
搜索
$bruteforce_detection.detection.detection.rule_name = /Workspace Anomalous Failed Logins/
$bruteforce_ip = $bruteforce_detection.detection.detection.variables["principal_ips"]
$login_event.metadata.product_name = "login"
$login_event.metadata.product_event_type = "login_success"
$login_event.metadata.vendor_name = "Google Workspace"
$login_ip = $login_event.principal.ip
// Ensure the brute force detection and successful login occurred from the same IP
$login_ip = $bruteforce_ip
$target_account = $login_event.target.user.email_addresses
// Ensure the brute force detection occurred before the successful login
$bruteforce_detection.detection.detection_time.seconds < $login_event.metadata.event_timestamp.seconds
match:
$bruteforce_ip over 24h
outcome:
$principal_users = array_distinct($target_account)
condition:
$bruteforce_detection and $login_event
信息中心
信息中心侧重于直观呈现原始事件数据,而复合检测逻辑则会将现有检测提醒与后续事件相关联。这种多层分析针对检测引擎进行了优化,而不是实时信息中心 widget。
情境感知检测
使用情形:利用外部威胁情报丰富现有检测结果,以验证某项提醒是否涉及已知的恶意实体,例如,检查安全检测中标记的 IP 地址是否也列在全局 TOR 出口节点威胁 Feed 中。
关键逻辑:使用复合规则,通过匹配共享属性(例如 IP 地址)将检测结果与 GLOBAL_CONTEXT 图数据(例如 Google Cloud 威胁情报 Feed)联接起来。
情境感知复合检测功能可利用其他背景信息(例如威胁 Feed 中发现的 IP 地址)来丰富检测结果。
示例:威胁情报丰富化
规则
以下复合规则会自动将 TOR 情报 Feed 中的其他上下文信息添加到现有检测结果中。它会将之前检测到的 IP 地址与 TOR 退出节点 Feed 相关联,以提高发现结果的严重程度和风险评分。
rule composite_tor_enrichment {
meta:
rule_name = "Detection with IP from TOR Feed"
author = "Google Cloud Security"
description = "Adds additional context from the TOR intel feed to detections"
severity = "High"
events:
$rule_name = $d.detection.detection.rule_name
$gcti.graph.metadata.entity_type = "IP_ADDRESS"
$gcti.graph.metadata.vendor_name = "Google Cloud Threat Intelligence"
$gcti.graph.metadata.source_type = "GLOBAL_CONTEXT"
$gcti.graph.metadata.product_name = "GCTI Feed"
$gcti.graph.metadata.threat.threat_feed_name = "Tor Exit Nodes"
$detection_ip = $d.detection.detection.variables["principal_ips"]
$detection_ip = $gcti.graph.entity.ip
match:
$detection_ip, $rule_name over 1h
outcome:
$risk_score = 80
condition:
$d and $gcti
}
搜索
``` $rule_name = $d.detection.detection.rule_name
$gcti.graph.metadata.entity_type = "IP_ADDRESS" $gcti.graph.metadata.vendor_name = "Google Cloud Threat Intelligence" $gcti.graph.metadata.source_type = "GLOBAL_CONTEXT" $gcti.graph.metadata.product_name = "GCTI Feed" $gcti.graph.metadata.threat.threat_feed_name = "Tor Exit Nodes"
$detection_ip = $d.detection.detection.variables["principal_ips"] $detection_ip = $gcti.graph.entity.ip
match: $detection_ip, $rule_name over 1h
条件: $d 和 $gcti ```
信息中心
共同出现检测
使用场景:检测同一实体在特定时间范围内触发的相关策略组合,例如,识别在 48 小时内同时触发了权限升级检测和数据渗漏检测的用户。
关键逻辑:使用一种聚合形式,通过在 match 部分中基于共享实体变量(例如 $pe_user)联接多个不同的检测类型,将它们相关联。
共同出现复合检测是一种聚合形式,可以检测相关事件的组合,例如用户触发的权限升级和数据渗漏检测的组合。
示例:提权和数据渗出同时发生
规则
以下复合规则会搜索在 48 小时内与同一用户相关联的特定检测序列或组合(即提权后进行数据渗出)。
rule composite_privesc_exfil_sequential {
meta:
rule_name = "Privilege Escalation and Exfiltration Composite"
author = "Google Cloud Security"
description = "Looks for a detection sequence of privilege escalation followed by exfiltration."
severity = "High"
events:
$privilege_escalation.detection.detection.rule_labels["tactic"] = "TA0004"
$exfiltration.detection.detection.rule_labels["tactic"] = "TA0010"
$privesc_user = $privilege_escalation.detection.detection.variables["principal_users"]
$exfil_user = $exfiltration.detection.detection.variables["principal_users"]
$privesc_user = $exfil_user
$privilege_escalation.detection.detection_time.seconds < $exfiltration.detection.detection_time.seconds
match:
$privesc_user over 48h
outcome:
$risk_score = 75
$privesc_rules = array_distinct($privilege_escalation.detection.detection.rule_name)
$exfil_rules = array_distinct($exfiltration.detection.detection.rule_name)
condition:
$privilege_escalation and $exfiltration
}
搜索
$privilege_escalation.detection.detection.rule_labels["tactic"] = "TA0004"
$exfiltration.detection.detection.rule_labels["tactic"] = "TA0010"
$privesc_user = $privilege_escalation.detection.detection.variables["principal_users"]
$exfil_user = $exfiltration.detection.detection.variables["principal_users"]
$privesc_user = $exfil_user
$privilege_escalation.detection.detection_time.seconds < $exfiltration.detection.detection_time.seconds
match:
$privesc_user over 48h
outcome:
$privesc_rules = array_distinct($privilege_escalation.detection.detection.rule_name)
$exfil_rules = array_distinct($exfiltration.detection.detection.rule_name)
condition:
$privilege_escalation and $exfiltration
信息中心
结果和变量管理
本部分展示了如何计算风险以及如何对数据进行归一化处理以供下游使用。
| 主题 | 示例 |
|---|---|
| 结果条件 | 按计算出的风险评分过滤 |
| 包含结果的单事件查询 | 时间点严重程度标记 |
| 基于网络的风险评分 | 基于网络的风险评分规则 |
| 重构多事件逻辑(重构前) | 结果重构(重构前) |
| 重构多事件逻辑(重构后) | 结果重构(重构后) |
| 函数到占位符的分配 |
包含 outcome 部分的查询
您可以在 YARA-L 2.0 规则中添加可选的 outcome 部分,以提取每次检测的其他信息。在 condition 部分中,您还可以指定结果变量的条件。您可以使用检测规则的 outcome 部分来设置供下游使用的变量。例如,您可以根据正在分析的事件中的数据设置严重程度得分。
详情请参阅以下内容:
结果条件
应用场景:根据计算出的风险得分过滤检测结果,以减少噪声并确保只有高置信度或高严重程度的事件才会触发提醒。这有助于抑制未达到特定业务阈值的低风险活动。
关键逻辑:使用条件数学(例如,根据文件大小或一天中的时间添加风险)在 outcome 部分中定义变量,然后在 condition 部分中引用这些变量来控制检测。
示例:按计算出的风险评分进行过滤
规则
在 condition 部分中,您可以使用 outcome 部分中定义的 outcome 变量。以下示例演示了如何使用结果条件根据风险得分进行过滤,以减少检测中的噪声。
rule OutcomeConditionalRule {
meta:
author = "alice@example.com"
description = "Rule that uses outcome conditionals"
events:
$u.metadata.event_type = "FILE_COPY"
$u.principal.file.size = $file_size
$u.principal.hostname = $hostname
// 1 = Sunday, 7 = Saturday.
$dayofweek = timestamp.get_day_of_week($u.metadata.collected_timestamp.seconds)
outcome:
$risk_score =
if($file_size > 500*1024*1024, 2) + // Files 500MB are moderately risky
if($file_size > 1024*1024*1024, 3) + // Files over 1G get assigned extra risk
if($dayofweek=1 or $dayofweek=7, 4) + // Events from the weekend are suspicious
if($hostname = /highly-privileged/, 5) // Check for files from highly privileged devices
condition:
$u and $risk_score >= 10
}
搜索
metadata.event_type = "FILE_COPY"
principal.file.size = $file_size
principal.hostname = $hostname
// 1 = Sunday, 7 = Saturday.
$dayofweek = timestamp.get_day_of_week(metadata.collected_timestamp.seconds)
outcome:
$risk_score =
if($file_size > 500*1024*1024, 2) + // Files 500MB are moderately risky
if($file_size > 1024*1024*1024, 3) + // Files over 1G get assigned extra risk
if($dayofweek=1 or $dayofweek=7, 4) + // Events from the weekend are suspicious
if($hostname = /highly-privileged/, 5) // Check for files from highly privileged devices
信息中心
此查询添加了 $hostname 结果变量,以直观呈现哪些主机与每个风险得分相关联。
metadata.event_type = "FILE_COPY"
principal.file.size = $file_size
principal.hostname = $hostname
// 1 = Sunday, 7 = Saturday.
$dayofweek = timestamp.get_day_of_week(metadata.collected_timestamp.seconds)
outcome:
$host = $hostname
$risk_score =
if($file_size > 500*1024*1024, 2) + // Files 500MB are moderately risky
if($file_size > 1024*1024*1024, 3) + // Files over 1G get assigned extra risk
if($dayofweek=1 or $dayofweek=7, 4) + // Events from the weekend are suspicious
if($hostname = /highly-privileged/, 5) // Check for files from highly privileged devices
包含结果的单事件查询
使用情形:使用即时情境丰富时间点检测,例如根据用户列表或文件属性分配严重程度标记,而无需时间窗口或事件关联。
关键逻辑:在缺少 match 部分的规则中使用 outcome 部分。这样一来,您就可以针对符合条件的每个单独事件提取元数据并执行条件逻辑(例如,根据参考列表检查用户)。
示例:时间点严重程度标记
规则
以下示例展示了如何在单事件规则中使用 outcome 部分来设置供下游使用的变量,例如根据文件复制事件中涉及的特定用户和文件大小来设置严重程度得分。
rule OutcomeRuleSingleEvent {
meta:
author = "alice@example.com"
events:
$u.metadata.event_type = "FILE_COPY"
$u.principal.file.size = $file_size
$u.principal.hostname = $hostname
outcome:
$suspicious_host = $hostname
$admin_severity = if($u.principal.user.userid in %admin_users, "SEVERE", "MODERATE")
$severity_tag = if($file_size > 1024, $admin_severity, "LOW")
condition:
$u
}
搜索
以下示例用于识别文件创建事件,并使用 outcome 部分为每个结果动态分配严重程度。与多事件规则不同,这种非汇总搜索不需要事件变量或 match 部分。相反,它会单独处理每个日志,以输出 1 row per event,并根据文件大小和用户权限通过自定义逻辑进行扩充。
metadata.event_type = "FILE_CREATION"
principal.file.size = $file_size
principal.hostname = $hostname
outcome:
$suspicious_host = $hostname
$admin_severity = if(principal.user.userid in %a1, "SEVERE", "MODERATE")
$severity_tag = if($file_size > 1024, $admin_severity, "LOW")
信息中心
在此示例中,信息中心变体并不适用,因为主要目的是标记和丰富单个事件。虽然信息中心可以汇总这些事件(例如,计算每个严重程度标记的事件总数),但这样做会掩盖此非汇总搜索旨在呈现的精细行级详细信息。
基于网络的风险评分
使用情形:通过计算一组事件的累计网络流量来识别高风险数据传输。这样一来,您就可以识别总数据阈值超过特定限制(例如 1024 字节)的威胁,同时将相关资产的漏洞严重程度纳入考虑范围。
关键逻辑:在 outcome 部分中使用 sum() 聚合函数,以在 match 窗口中跨所有事件组合 sent_bytes 和 received_bytes。对于规则,查询使用 if 语句,如果该总和超过定义的阈值,则应用更高的风险得分。
示例:基于网络的风险评分规则
规则
以下示例演示了如何使用 outcome 部分根据网络活动计算动态风险评分。通过对事件组中传输的总字节数求和,该规则可为超出特定数据阈值(1024 字节)的匹配项应用更高的优先级,同时将相关资产的漏洞严重程度纳入考虑范围。
rule OutcomeRuleMultiEvent {
meta:
author = "alice@example.com"
events:
$u.udm.principal.hostname = $hostname
$asset_context.graph.entity.hostname = $hostname
$severity = $asset_context.graph.entity.asset.vulnerabilities.severity
match:
$hostname over 5m
outcome:
$total_network_bytes = sum($u.network.sent_bytes) + sum($u.network.received_bytes)
$risk_score = if($total_network_bytes > 1024, 100, 50) +
max(
if($severity = "HIGH", 10)
+ if($severity = "MEDIUM", 5)
+ if($severity = "LOW", 1)
)
$asset_id_list =
array(
if($u.principal.asset_id = "",
"Empty asset id",
$u.principal.asset_id
)
)
$asset_id_distinct_list = array_distinct($u.principal.asset_id)
$asset_id_count = count($u.principal.asset_id)
$asset_id_distinct_count = count_distinct($u.principal.asset_id)
condition:
$u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")
}
搜索
以下示例展示了一种搜索变体,该变体将 UDM 网络事件与实体情境图 (ECG) 中的资产情境相关联。它利用 5 分钟的match窗口按主机名汇总网络流量,根据数据量和漏洞严重程度计算风险评分,并应用条件过滤条件从最终结果集中排除特定资产 ID。
$u.udm.principal.hostname = $hostname
$asset_context.graph.entity.hostname = $hostname
$severity = $asset_context.graph.entity.asset.vulnerabilities.severity
match:
$hostname over 5m
outcome:
$total_network_bytes = sum($u.network.sent_bytes) + sum($u.network.received_bytes)
$risk_score = if($total_network_bytes > 1024, 100, 50) +
max(
if($severity = "HIGH", 10)
+ if($severity = "MEDIUM", 5)
+ if($severity = "LOW", 1)
)
$asset_id_list =
array(
if($u.principal.asset_id = "",
"Empty asset id",
$u.principal.asset_id
)
)
$asset_id_distinct_list = array_distinct($u.principal.asset_id)
$asset_id_count = count($u.principal.asset_id)
$asset_id_distinct_count = count_distinct($u.principal.asset_id)
condition:
$u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")
信息中心
以下示例展示了一个信息中心变体,该变体通过资产漏洞数据丰富了实时网络遥测数据。此查询通过在 5 分钟的滑动窗口内匹配主机名,让开发者能够构建可直观呈现资产风险级别的信息中心 widget。该逻辑会根据网络吞吐量和资产上发现的最高严重程度的漏洞动态调整风险得分,从而提供可能遭到入侵的系统的优先视图。
$u.udm.principal.hostname = $hostname
$asset_context.graph.entity.hostname = $hostname
$severity = $asset_context.graph.entity.asset.vulnerabilities.severity
match:
$hostname over 5m
outcome:
$total_network_bytes = sum($u.network.sent_bytes) + sum($u.network.received_bytes)
$risk_score = if($total_network_bytes > 1024, 100, 50) +
max(
if($severity = "HIGH", 10)
+ if($severity = "MEDIUM", 5)
+ if($severity = "LOW", 1)
)
$asset_id_list =
array(
if($u.principal.asset_id = "",
"Empty asset id",
$u.principal.asset_id
)
)
$asset_id_distinct_list = array_distinct($u.principal.asset_id)
$asset_id_count = count($u.principal.asset_id)
$asset_id_distinct_count = count_distinct($u.principal.asset_id)
condition:
$u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")
重构多事件 outcome 规则(重构前)
使用场景:通过将多事件规则转换为单事件规则,提高系统性能并缩短处理延迟时间。这非常适合最初仅设计了匹配部分以启用结果部分,但实际上不需要跨多个不同事件进行关联的规则。
关键逻辑:从 outcome 部分中移除 match 部分和所有聚合函数(例如 max()、sum() 或 count())。此过渡会将规则从按时间对事件进行分组转变为单独评估每个到达的事件。
match 部分)和多事件规则(包含 match 部分的规则)。
您可以将 outcome 部分用于单事件规则(不含 match 部分的规则)和多事件规则(含 match 部分的规则)。如果您之前将规则设计为多事件规则只是为了使用结果部分,那么您可以选择删除 match 部分来重构这些规则,以提高性能。请注意,由于您的规则不再包含应用分组的 match 部分,您可能会收到更多检测结果。
示例:结果重构(重构前)
规则
以下示例展示了仅使用一个事件变量的多事件结果规则。由于它使用了 match 部分,因此规则引擎必须在 5 分钟的时间窗口内对事件进行分组,然后才能计算结果,这比单事件评估消耗更多资源。
rule OutcomeMultiEventPreRefactor {
meta:
author = "alice@example.com"
description = "Outcome refactor rule, before the refactor"
events:
$u.udm.principal.hostname = $hostname
match:
$hostname over 5m
outcome:
$risk_score = max(if($hostname = "my-hostname", 100, 50))
condition:
$u
}
搜索
等效的统计信息查询
events:
$u.udm.principal.hostname = $hostname
match:
$hostname over 5m
outcome:
$risk_score = max(if($hostname = "my-hostname", 100, 50))
condition:
$u
信息中心
events:
$u.udm.principal.hostname = $hostname
match:
$hostname over 5m
outcome:
$risk_score = max(if($hostname = "my-hostname", 100, 50))
condition:
$u
重构多事件 outcome 规则(重构后)
使用情形:完成查询优化,以提高处理速度。通过移除分组要求,查询现在会在单个匹配事件到达时立即触发检测,这对于规则引擎来说效率更高。
关键逻辑:删除 match 部分,并从 outcome 变量赋值中移除 aggregate 函数(例如 max())。if 语句中的逻辑保持不变,但现在应用于单个事件,而不是一组事件。
您可以删除 match 部分来重构查询。注意:您还必须移除 outcome 部分中的汇总,因为查询现在是单事件查询。如需详细了解聚合,请参阅结果聚合。
示例:结果重构 (: #outcome-post-refactor)
规则
rule OutcomeSingleEventPostRefactor {
meta:
author = "alice@example.com"
description = "Outcome refactor rule, after the refactor"
events:
$u.udm.principal.hostname = $hostname
// We deleted the match section.
outcome:
// We removed the max() aggregate.
$risk_score = if($hostname = "my-hostname", 100, 50)
condition:
$u
}
搜索
events:
$u.udm.principal.hostname = $hostname
outcome:
$risk_score = if($hostname = "my-hostname", 100, 50)
信息中心
events:
$u.udm.principal.hostname = $hostname
outcome:
$risk_score = if($hostname = "my-hostname", 100, 50)
函数到占位符分配
使用情形:对数据进行规范化处理(例如,标准化电子邮件网域),以验证匹配部分中的分组是否准确。
关键逻辑:将 re.capture() 或 strings.concat() 的结果分配给占位符变量。
示例:函数到占位变量分配
您可以将占位符变量分配给函数调用的结果,并可以在规则的其他部分(例如 match 部分、outcome 部分或 condition 部分)中使用该占位符变量。
规则
rule FunctionToPlaceholderRule {
meta:
author = "alice@example.com"
description = "Rule that uses function to placeholder assignments"
events:
$u.metadata.event_type = "EMAIL_TRANSACTION"
// Use function-placeholder assignment to extract the
// address from an email.
// address@website.com -> address
$email_to_address_only = re.capture($u.network.email.to , "(.*)@")
// Use function-placeholder assignment to normalize an email:
// address@-> address@company.com
$email_from_normalized = strings.concat(
re.capture($u.network.email.from , "(.*)@"),
"@company.com"
)
// Use function-placeholder assignment to get the day of the week of the event.
// 1 = Sunday, 7 = Saturday.
$dayofweek = timestamp.get_day_of_week($u.metadata.event_timestamp.seconds)
match:
// Use placeholder (from function-placeholder assignment) in match section.
// Group by the normalized from email, and expose it in the detection.
$email_from_normalized over 5m
outcome:
// Use placeholder (from function-placeholder assignment) in outcome section.
// Assign more risk if the event happened on weekend.
$risk_score = max(
if($dayofweek = 1 or $dayofweek = 7, 10, 0)
)
condition:
// Use placeholder (from function-placeholder assignment) in condition section.
// Match if an email was sent to multiple addresses.
#email_to_address_only > 1
}
搜索
metadata.event_type = "EMAIL_TRANSACTION"
// Use function-placeholder assignment to extract the
// address from an email.
// address@website.com -> address
$email_to_address_only = re.capture(network.email.from , "(.*)@")
// Use function-placeholder assignment to normalize an email:
// address@??? -> address@company.com
$email_from_normalized = strings.concat(
re.capture(network.email.to , "(.*)@"),
"@company.com"
)
// Use function-placeholder assignment to get the day of the week of the event.
// 1 = Sunday, 7 = Saturday.
$dayofweek = timestamp.get_day_of_week(metadata.event_timestamp.seconds)
match:
// Use placeholder (from function-placeholder assignment) in match section.
// Group by the normalized from email, and expose it in the detection.
$email_from_normalized over 5m
outcome:
// Use placeholder (from function-placeholder assignment) in outcome section.
// Assign more risk if the event happened on weekend.
$risk_score = max(
if($dayofweek = 1 or $dayofweek = 7, 10, 0)
)
condition:
// Use placeholder (from function-placeholder assignment) in condition section.
// Match if an email was sent to multiple addresses.
#email_to_address_only > 1
信息中心
以下示例展示了针对时序可视化图表进行了优化的信息中心变体。此查询使用一天翻滚窗口,而不是分钟级粒度,可生成稳定且不重叠的数据点,非常适合绘制较长时间内的风险评分图表。该逻辑可对电子邮件实体进行归一化处理,并为周末交易应用更高的风险权重,从而提供清晰的每日可疑电子邮件活动趋势,以便进行长期监控。
metadata.event_type = "EMAIL_TRANSACTION"
// Use function-placeholder assignment to extract the
// address from an email.
// address@website.com -> address
$email_to_address_only = re.capture(network.email.from , "(.*)@")
// Use function-placeholder assignment to normalize an email:
// address@??? -> address@company.com
$email_from_normalized = strings.concat(
re.capture(network.email.to , "(.*)@"),
"@company.com"
)
// Use function-placeholder assignment to get the day of the week of the event.
// 1 = Sunday, 7 = Saturday.
$dayofweek = timestamp.get_day_of_week(metadata.event_timestamp.seconds)
match:
// Use placeholder (from function-placeholder assignment) in match section.
// Group by the normalized from email, and expose it in the detection.
$email_from_normalized over 5m
outcome:
// Use placeholder (from function-placeholder assignment) in outcome section.
// Assign more risk if the event happened on weekend.
$risk_score = max(
if($dayofweek = 1 or $dayofweek = 7, 10, 0)
)
condition:
// Use placeholder (from function-placeholder assignment) in condition section.
// Match if an email was sent to multiple addresses.
#email_to_address_only > 1
优化和过滤
有效的规则优化依赖于精确的数据过滤,以确保检测引擎仅处理有意义的信息。通过排除“嘈杂”或不完整的数据,您可以显著提高规则性能,并确保生成的提醒可据以采取行动。
| 主题 | 示例 |
|---|---|
| 零值排除 | 显式和隐式零值排除 |
零值排除
使用情形:通过明确过滤掉不提供可据以采取行动的安全数据的空字符串、null 值或通用占位账号(例如“Guest”),确保规则准确性并减少误报。
关键逻辑:利用规则引擎对 match 部分中使用的变量进行隐式零值过滤,同时对其他事件字段使用显式不等运算符 (!= ""),以确保只有填充的数据会触发检测。
规则引擎会隐式过滤掉 match 部分中使用的所有占位符的零值。使用 allow_zero_values 选项可停用此功能。不过,对于其他引用的事件字段,除非您明确指定此类条件,否则不会排除零值。如需了解详情,请参阅“匹配”部分中的零值。
示例:显式和隐式零值排除
规则
rule ExcludeZeroValues {
meta:
author = "alice@example.com"
events:
$e1.metadata.event_type = "NETWORK_DNS"
$e1.principal.hostname = $hostname
// $e1.principal.user.userid may be empty string.
$e1.principal.user.userid != "Guest"
$e2.metadata.event_type = "NETWORK_HTTP"
$e2.principal.hostname = $hostname
// $e2.target.asset_id cannot be empty string as explicitly specified.
$e2.target.asset_id != ""
match:
// $hostname cannot be empty string. The rule behaves as if the
// predicate, `$hostname != ""` was added to the events section, because
// `$hostname` is used in the match section.
$hostname over 1h
condition:
$e1 and $e2
}
搜索
您必须明确声明 hostname 不能是空字符串,因为 match 部分中的占位符没有隐式零值过滤条件。
$e1.metadata.event_type = "NETWORK_DNS"
$e1.principal.hostname = $hostname
// $e1.principal.user.userid may be empty string.
$e1.principal.user.userid != "Guest"
$e2.metadata.event_type = "NETWORK_HTTP"
$e2.principal.hostname = $hostname
// $e2.target.asset_id and hostname cannot be empty string as explicitly specified.
$e2.target.asset_id != ""
$hostname != ""
match:
$hostname over 1h
信息中心
您必须明确声明 hostname 不能是空字符串,因为 match 部分中的占位符没有隐式零值过滤条件。
$e1.metadata.event_type = "NETWORK_DNS"
$e1.principal.hostname = $hostname
// $e1.principal.user.userid may be empty string.
$e1.principal.user.userid != "Guest"
$e2.metadata.event_type = "NETWORK_HTTP"
$e2.principal.hostname = $hostname
// $e2.target.asset_id and hostname cannot be empty string as explicitly specified.
$e2.target.asset_id != ""
$hostname != ""
match:
$hostname over 1h