利用弹性安全自动检测调整请求
在 Elastic,Infosec 团队是"Customer Zero"。我们广泛使用最新版本的 Elastic 产品来保护我们组织的安全,这让我们对如何解决现实世界中的安全挑战有了独到的见解。我们提高安全运营中心 (SOC) 效率的方法之一是创建一个无缝、自动化的工作流程,让我们的分析师只需单击一下,就能直接从Kibana 案例中打开检测调整请求。
在任何 SOC 中,安全分析师和检测工程师之间的反馈回路对于保持健康有效的安全态势至关重要。第一线的分析师最先看到检测规则在现实世界中的表现。他们知道哪些警报是有价值的,哪些是嘈杂的,哪些是稍加调整就能改进的。嘈杂警报造成的警报疲劳会增加错过真正的阳性警报的风险。快速调整误报对于应对真报至关重要。高效地捕捉这种警报反馈可能是一项挑战--发送电子邮件、开票或直接消息等人工流程可能不一致、耗时且难以跟踪。
有了 Elastic Security,分析师可以 将警报附加到 Kibana 中的 新案例或现有案例 ,进行调查,并通过一些自定义和自动化操作,直接从 Kibana 案例 中单击即可启动调整请求。本文将向您介绍我们是如何构建这一自动化系统的,以及您可以如何实施类似的系统来关闭反馈回路并优化您的检测和响应程序。
Kibana 案例中的自定义字段
自定义字段是Kibana 案例自动化的关键组成部分。利用这些自定义字段,我们可以直接从分析人员已经在使用的工具中获取必要的信息。这些自定义字段将出现在所有新的和现有的案件中,为分析人员提供了一种清晰一致的方式来标记检测以进行审查。
注:在 8.15 版中引入了为个案添加自定义字段的功能。更多详情,请参阅官方案例文档。
每个 Kibana Case 都是存储在专用 Elasticsearch 索引中的文档:.kibana_alerting_cases.这意味着您的所有案例数据都可用于查询、聚合和自动化,就像 Elastic 中的其他数据源一样。每个案例文档都包含大量信息,但有几个字段对度量和自动化特别有用。cases.status 字段跟踪案件是未结、进行中还是已结,而cases.created_at 和cases.updated_at 则提供对计算平均解决时间(MTTR)等指标至关重要的时间戳。通过cases.severity 和cases.owner 等字段,您可以对指标进行切分,以了解团队的表现。对于本博客来说,最重要的是cases.custom_fields 对象包含一个数组,其中包含您配置的自定义字段。运行时字段可用于解析自定义字段阵列,使您能够构建查询、仪表盘、可视化和触发工作流的检测规则。
除了调整请求外,自定义字段在跟踪指标和丰富案例方面的用途也非常广泛。例如,我们有一个"复杂案件" 自定义字段,用于标记解决时间超过一小时的案件,帮助我们确定可能需要更好的调查指南或自动化的规则,以帮助缩短调查时间。我们还使用"Detection rule valid"和"True Positive Alert"等自定义字段来收集有关规则性能和保真度的细粒度反馈,从而在 Kibana 中构建功能强大的仪表盘,直观显示 SOC 的运行效果。
如果您还没有为案例信息创建数据视图,那么如果您想在案例中使用运行时字段和数据可视化,就需要创建数据视图。
导航至索引模式:在 Kibana 中,转到堆栈管理> 数据视图,然后单击 "创建新数据视图"。
配置数据视图以映射.kibana_alerting_cases 系统索引。您需要单击 "允许隐藏和系统索引"按钮来允许这样做。对于时间戳字段,我建议使用cases.updated_at 字段,以便按最近的活动显示案例。
创建自定义字段
自定义字段有两种类型:Text 字段用于自由格式输入,或Toggle 字段用于简单的是/否反馈。在我们的调试请求自动化中,我们每种请求都使用一个。文本字段是一个可选字段,用于获取分析师的任何其他反馈,切换字段用于触发自动操作。
在 Kibana 中,转到安全> 案例,然后点击右上角的设置。在设置页面中,您将看到自定义字段部分,您可以在此添加您想要的新字段。在案例用户界面中,字段是按字母顺序显示的,因此我们在字段前加上数字,使其保持我们想要的顺序。
您可以创建新的自定义字段,在用户界面中添加的标签仅供分析员使用,不会存储在案例索引中。这些值可以是您想要的任何值。
添加自定义字段:我们需要为该工作流程添加两个字段。
- 字段 1:所需调谐切换
-
分析员点击该按钮即可启动调谐请求。
- 标签
Open tuning request? - 类型拨动
- 默认值:关闭
- 标签
-
字段 2:调校申请详细信息
- 该字段允许分析人员提供需要更改的具体细节,如添加异常、降低严重性或调整查询逻辑。
- Name:
Tuning request detail - 类型文本
-
默认值:关闭
-
使用运行时字段映射自定义字段
在 Kibana 案例中处理自定义字段时面临的一个挑战是,cases.custom_fields 字段被映射为一个对象数组,其中每个对象代表一个自定义字段及其名称和值。这种结构导致很难直接在 KQL 中查询特定的自定义字段。例如,您不能简单地使用cases.custom_fields.open_tuning_request : "true" 这样的查询。为了解决这个问题,我们可以使用运行时字段来解析和查询自定义字段。
运行时字段是在查询时评估的字段。它们可以让你即时创建新字段,而无需重新索引数据。我们可以在.kibana_alerting_cases 索引上定义运行时字段,使用一个简单的脚本来解析cases.custom_fields 数组,并将我们需要的值提取到新的、易于查询的字段中。
在此工作流程中,我们将创建两个运行时字段,它们将映射到上面创建的自定义字段:
*TuningRequired :一个布尔字段,如果"Open tuning request" (打开调整请求)处于打开状态,则true 。
*TuningDetail :文本字段,将包含"调整请求详情" 字段中分析员的注释。
在创建运行时字段之前,我们首先需要确定 Kibana 为每个自定义字段分配的唯一 ID (key)。目前,在用户界面中还没有直接查看此 ID 的方法。为了找到它,我们采用了以下变通方法:
- 创建字段。如果使用其他自定义字段,则应一次创建一个自定义字段,以便于识别新字段键。如果只有上述两个字段,则可以使用
type值将它们区分开来,该值可以是文本或切换。 - 创建一个新案例。添加字段后,我们在 Kibana 中创建了一个测试用例,在描述字段中添加了一些数据,并将调整必填字段切换为 true,同时将所有其他自定义字段设置为 false 或空白。
- 检查案件文件。然后,我们导航到 Discover,查询
.kibana_alerting_cases索引,找到新案件的文件。通过检查文档源代码中的cases.customFields数组,我们可以找到与新自定义字段相关的key。保存key字段的值,以便在运行时脚本中使用。
cases.customFields 数据的格式如下:
[
{
"key": "4537b921-3ca4-4ff0-aa39-02dd6a3177bd",
"type": "text",
"value": "This alert is too noisy"
},
{
"key": "cdf28896-c793-43d2-9384-99562e23a646",
"type": "toggle",
"value": true
}
]
创建运行时字段
您可以通过 Kibana UI 或使用开发工具控制台中的 Elasticsearch API 添加运行时字段。如果您还没有为案例信息创建数据视图,则需要先创建该视图。
查看新的 Kibana 案例数据视图时,单击 "添加字段 "按钮打开快捷菜单,创建新的运行时字段。
输入字段名称,在本例中,我们将TuningRequired 配置为新的布尔字段类型。单击 "设置值 "切换按钮,将其配置为通过简便脚本配置的新运行时字段。更新此无障碍脚本,将TUNING_REQUIRED_FIELD_KEY_UUID 替换为 "需要调整 "自定义字段中的key 值,并将其粘贴到值字段中,然后保存新的运行时字段。
...
if (params._source.containsKey('cases') &&
params._source.cases != null &&
params._source.cases.containsKey('customFields') &&
params._source.cases.customFields != null)
{
for (def cf : params._source.cases.customFields) {
if (cf != null &&
cf.containsKey('key') &&
cf.key != null &&
cf.key.contains('TUNING_REQUIRED_FIELD_KEY_UUID') &&
cf.containsKey('value') &&
cf.value != null) {
emit(cf.value);
break;
}
}
}
对TuningDetail 字段重复此过程,记住在该字段的无痛脚本中使用文本字段中的key 值。如果您的案例中有任何其他自定义字段,而您又想将其用于仪表盘或指标,您也可以通过相同的流程映射这些字段。
如果您 "以代码形式 "控制集群设置和数据视图,还可以使用 Kibana Dev Tools 控制台的 更新 映射 API 向索引 映射 添加运行时字段。
自动创建调整请求
我们可以通过两种方式触发这种自动化:通过自定义检测规则(该规则将创建一个新警报,并在案例更新为调整请求时将其发送到连接器),或通过查询 API 的预定外部自动化。
该自动化可使用任何自动化平台(如 Tines、Github Actions 或自定义脚本)创建。这就是我们用于自动化的逻辑:
步骤 1:查找最近被标记为 TuningRequired
您可以使用此 elasticsearch 查询查找过去一小时内更新过的任何案例,其中TuningRequired 字段已设置为true 。该查询使用cases.updated_at 字段作为时间范围。要查询自定义字段,必须在 API 请求中包含运行时字段映射。
该查询将返回.kibana_alerting_cases 索引中在过去一小时内更新过的所有案例文档,且TuningRequired 字段已设置为true
POST /.kibana_alerting_cases/_search
{
"query": {
"bool": {
"must": [],
"filter": [
{
"bool": {
"should": [
{
"match": {
"TuningRequired": true
}
}
],
"minimum_should_match": 1
}
},
{
"range": {
"cases.updated_at": {
"format": "strict_date_optional_time",
"gte": "now-1h",
"lte": "now"
}
}
}
],
"should": [],
"must_not": []
}
},
"runtime_mappings": {
"TuningDetail": {
"type": "keyword",
"script": {
"source": "if (\nparams._source.containsKey('cases') &&\nparams._source.cases != null &&\nparams._source.cases.containsKey('customFields') &&\nparams._source.cases.customFields != null\n) {\nfor (def cf : params._source.cases.customFields) {\nif (\ncf != null &&\ncf.containsKey('key') &&\ncf.key != null &&\ncf.key.contains('6cadc70a-7d68-4531-9861-7d5bc24c4c1c') &&\ncf.containsKey('value') &&\ncf.value != null\n) {\nemit(cf.value);\nbreak;\n}\n}\n}"
}
},
"TuningRequired": {
"type": "boolean",
"script": {
"source": "if (\nparams._source.containsKey('cases') &&\nparams._source.cases != null &&\nparams._source.cases.containsKey('customFields') &&\nparams._source.cases.customFields != null\n) {\nfor (def cf : params._source.cases.customFields) {\nif (\ncf != null &&\ncf.containsKey('key') &&\ncf.key != null &&\ncf.key.contains('496e71f2-2bce-47a2-93a8-00db0de2d1b4') &&\ncf.containsKey('value') &&\ncf.value != null\n) {\nemit(cf.value);\nbreak;\n}\n}\n}"
}
}
},
"fields": [
"TuningDetail",
"TuningRequired"
]
}
任何时候更改字段或对案例进行注释,都会将updated_at 字段更新为当前时间。由于添加到案例中的任何更新或注释都会更新该时间戳,因此如果在案例更新时定期运行该自动化,就有可能通过该自动化多次返回单个案例。为此利用的任何自动化流程都应具有重复数据删除流程,以防止在这种情况下多次处理同一案例。
步骤 2:解析每个案例
循环处理上一个查询返回的每个案例,每次处理一个。返回的每个文档都将包含fields 数组,其中包含自定义字段以及其他有用字段的值。解析以下每个字段并将其存储起来,以备将来使用:
_id字段的格式如cases:{{case_ID}}.案例 ID 将用于自动化中未来的 API 请求,以便为案例添加注释或检索案例附加的所有警报。cases.title是案件的标题cases.assignees是指案件分配给谁cases.updated_by是最后一个更新案件的人,这通常是提交调整请求的人,可以帮助了解更多信息的联系人。cases.tags在使用标签对案例进行分类或识别时非常有用。
步骤 3:检索案件所附警报
对于每个病例,您都想知道该病例附加了哪些警报,以便知道哪些警报需要调整。这可以使用病例 API 和病例的_id 字段来实现。
/api/cases/{caseId}/alerts
此查询将返回一个数组,其中包含与案件相关的所有警报id 值。使用此 ID 值,您可以查询.siem-signals* elasticsearch 索引,找到需要调整的案例所附的每个警报的完整信息。
POST /.siem-signals-*/_search
{
"size": 1,
"query": {
"bool": {
"must": [],
"filter": [
{
"bool": {
"should": [
{
"match": {
"_id": "{{alert_id}}"
}
}
],
"minimum_should_match": 1
}
},
{
"range": {
"@timestamp": {
"format": "strict_date_optional_time",
"gte": "now-30d",
"lte": "now"
}
}
}
],
"should": [],
"must_not": []
}
}
}
您可以从查询结果中提取有关警报的信息,如名称和创建日期,以及其他有助于调整的信息,如user.name 或process.name 字段。因为一个案例可能会有很多警报,您需要按signal.rule.name 值重复警报。
步骤 4:开启调整请求。
这一步骤取决于您在环境中使用的票务系统。我们的团队使用 github issues 跟踪调整请求,使用 slack 发送通知,但也可以使用任何支持自动化的票单或项目管理系统。
这是我们使用 Github 和 Slack 跟踪调整请求的自动化逻辑流程:
- 通过警报名称,我们可以搜索到任何现有的开放式调整请求。
- 如果存在现有的调谐请求,我们将使用案例中的详细信息和新请求更新该请求
- 如果没有现成的申请,我们将打开一个新的调整申请问题,并附上信息
- 然后,我们会向检测工程团队的松弛频道发送松弛通知,其中包含调优请求链接、案例链接以及请求和警报的详细信息。
- 然后,我们使用案例 API在原始案例中添加注释,并链接到调整请求问题
- 可选的人工智能代理:我们开始尝试使用人工智能代理来分析警报和案例信息,然后根据调整请求提供更好的上下文,甚至有可能建议对检测规则进行更改。
这种自动化的最终结果是,我们的 SOC 分析师只需点击一下,就能从他们的案例中创建详细的检测调整请求单。由于实现了自动化,我们发现误报率大大降低,检测规则的整体效率也大幅提高。
结论
通过使用带有自定义字段的 Kibana 案例并与自动化平台集成,您可以优化许多手动流程。这一自动化工作流程减少了与收集分析师反馈相关的人工开销,确保将分析师的宝贵见解迅速转化为对检测规则的可行改进。其结果是一个更高效、更准确、更有弹性的 SOC,能够快速适应新出现的威胁并减少警报疲劳。
准备好优化您的 SOC 效率并改善您的检测态势了吗?了解 Elastic Security,立即开始构建您自己的自动调整请求工作流程!
