利用Splunk查找表加速检测工程

本文介绍了如何利用Splunk查找表快速实现基于字符串的检测规则,通过将Sigma规则转换为CSV格式的查找表,显著简化检测规则创建流程,并提供了三种具体实现方法及其优缺点分析。

概述

这是一篇关于我如何发现查找表可在Splunk中用于快速减少实现基于简单字符串检测的新检测规则时间的文章。例如"如果看到dump /service:krbtgt则触发"。

随着检测即代码的部署,可能会减少对此的需求。但我的经验表明,基于本质上只是字符串搜索的新规则推出时间通常过长。

背景

新规则开发的常见路径是阅读报告,识别TTP的独特实现,然后创建或获取规则,例如从https://sigmasearchengine.com、/https://detection.fyi/或直接从https://github.com/SigmaHQ/sigma找到Sigma规则。

即使使用检测即代码,这可能仍然是一个冗长的过程,也可能意味着我们拥有数百个检测规则,每个规则都有自己的管理开销,而这些规则本质上可能只是字符串指示器。

解决方案 - 使用查找表!

在Splunk中,查找表本质上是一个CSV表,可以存储我们想要查找的数据。

简化来说,Splunk中现有的IOC威胁匹配使用查找表/kv存储。我们只是将该概念扩展到包括字符串片段,如mimikatz,但添加了我们希望看到它们的字段 - 例如命令。

Sigma规则示例

以这个查找命令行参数的Sigma规则为例:

所有感兴趣的内容只是出现在CommandLine中的字符串。我们只是想采用像这样的简单Sigma规则的主题,并将其转换为CSV结构。

对于上面的示例,我们可以看到它查找多个命令行片段中的任何一个。这确实说明了基于查找的方法的局限性,因为如果我们不想承担必须拆分分隔字段的开销,那么它们都必须放在单独的行上,这对于某些规则来说可能相当"不整洁"。

示例查找文件

下面的示例查找文件存储了我们最感兴趣的信息,例如:

  • l_field = 我们希望找到值的字段
  • l_value = 我们希望找到的值(注意周围的通配符)
  • l_description/l_name = 此条目的名称和描述
  • l_references = 任何有用的调查参考
  • l_severity = 这可能触发的严重性(可在RBA计算中用作风险因子)

在Splunk搜索中使用

我们可以在Splunk搜索中以几种方式使用此查找表,每种方式的效率各不相同。总体思路是能够将其指向索引,告诉它我们关心的字段,然后进行查找。

重要步骤:

  1. 确保为查找表定义了查找定义
  2. 确保在查找定义中将搜索的字段启用了通配符字段
  3. 所有搜索项都应保存有周围的通配符*

示例SPL:方法1 - 首先使用inputlookup子搜索的Tstats

1
2
3
4
5
6
| tstats summariesonly=true c from datamodel="Endpoint.Processes"
where `rule_tuning_macro` [|inputlookup string_indicator_lookup | rename l_value as Processes.process | fields Processes.process] by _time Processes.process Processes.user host
| rename Proceses.* as *
| eval lookup_field="command"
| eval lookup_value=process
| lookup string_indicator_lookup l_field as lookup_field l_value as lookup_value

这里我们使用加速数据模型,并使用内部搜索,即inputlookup,我们在其中重命名然后仅将字符串输出到我们关心的字段中(此处为processes.process)

我们可以针对这个较小的数据集进行搜索,并直接使用查找来丰富任何发现。

与编写规则的良好实践一样,我们包括一个包含误报等的调优宏,包括使用原始数据中存在的其他字段进行调优。

缺点: 由于查找文件增长以及inputlookup命令在Splunk索引器上的工作方式,这可能相当慢。搜索需要定期运行且时间窗口要小。

示例SPL:方法2 - 使用Tstats提取所有数据然后进行查找

1
2
3
4
5
| tstats summariesonly=true c from datamodel="Endpoint.Processes" where `rule_tuning_macro` by _time Processes.process Processes.user host
| rename Proceses.* as *
| eval lookup_field="command"
| eval lookup_value=process
| lookup string_indicator_lookup l_field as lookup_field l_value as lookup_value

在这个示例中,我们查看加速端点数据模型中的所有命令(Processes.process),然后对每个命令进行查找,允许我们看到查找中的所有字段,如描述或参考。同样,我们使用调优宏。

缺点: 这可能相当慢,因为它首先将所有命令拉入内存,因此在短时间内运行,尽管查找文件增长对其影响可能较小。

示例SPL:方法3 - 在非数据模型数据上,使用inputlookup和lookup

1
2
3
4
5
{{YOUR DATA}}
| eval lookup_field="command"
| eval lookup_value=command
| search[|inputlookup string_indicator_lookup | eval search=l_value |fields search | format ]
| lookup string_indicator_lookup l_field as lookup_field l_value as lookup_value

这里我们不使用加速数据模型,但为了加速,我们使用两次传递。

第一个inputlookup在原始数据中查找我们关心的字符串 - 此时它可能出现在任何字段中,但应该大大减少后续查找的数据集。

我们随后进行查找,确保匹配发生在正确的字段上,并用查找中的上下文丰富它。

进一步探索

这些搜索相当基础,因此有一些我想探索的想法:

  • 分隔符以减少重复/多行 - 我相信涉及的解析可能会严重影响搜索时间,特别是因为我们无法进行简单的查找。但我想进一步调查这一点。
  • 附加字段,如parent_process - 仅当两者都满足时
  • 查找中的逻辑 - 在查找中存储Sigma逻辑并在SPL搜索中使用它,如’ANY’、‘ALL’
  • 在摄取/实时执行 - 我希望在原始日志进入Splunk时进行简单的模式匹配,有点像IDS。我想看看在摄取时进行这样的查找有多可行。

结论

诚然,可能有一个点,在查找表中执行这些操作比拥有多个规则效率更低。然而,目标是从阅读报告时的"嘿,我们可能可以寻找那个"到实际有一个规则在寻找它,大大减少复杂性和所需时间。

如果有人有任何反馈,请告诉我!(我确实喜欢重新发明完美的轮子,所以如果有更好的方法,请告诉我!)

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计