简介
在之前的出版物中,我们介绍了 Detonate:我们如何构建它以及如何在 Elastic 中使用它进行恶意软件分析。本出版物深入探讨了如何使用 Detonate 进行大规模动态恶意软件分析。
从高层次来看,Detonate 在受控(即沙箱)环境中运行恶意软件和其他潜在的恶意软件,其中启用了全套 Elastic Security 功能。有关 Detonate 的更多信息,请查看 点击,点击……砰!使用 Detonate 自动化保护测试。
执行期间生成的大部分数据由良性和重复信息组成。当进行大规模动态恶意软件分析时,管理大量低价值数据是一个相当大的挑战。为了解决这个问题,我们利用了几个 Elastic 摄取管道,我们利用这些管道有效地过滤掉我们数据集中的噪音。这种摄取管道的应用使我们能够方便地分析大量恶意软件数据,并识别出我们已经感兴趣的几种恶意行为。
本研究考察了摄取管道的概念,探讨了它们的不同类型和应用,以及如何实现它们。然后,我们将逐步介绍一个包含这些摄取管道的综合工作流程。我们将讨论我们的脚本以及我们创建的用于自动化整个过程的方法。最后,我们将展示我们的结果,并讨论其他人如何利用本出版物中分享的工作流程来获得类似的结果。
概述
为了实现我们的大规模恶意软件分析目标,我们需要有效的数据管理。下面显示了我们构建的链式摄取管道和处理器的概述
总而言之,我们对已知的良好二进制文件进行指纹识别,并将这些指纹存储在充实索引中。当检测恶意软件或未知二进制文件时,我们会执行相同的操作,使用这些指纹的比较来快速过滤掉低价值数据。
摄取管道
摄取管道是一项强大的功能,允许你在将数据索引到 Elasticsearch 之前对其进行预处理和转换。它们提供了一种对传入文档执行各种操作的方法,例如丰富数据、修改字段、提取信息或应用数据标准化。可以自定义摄取管道以满足特定的数据处理要求。我们的目标是创建一个管道,将已知良性文档与包含良性和恶意记录的数据集区分开来。我们将大型良性和恶意数据集摄取到单独的命名空间中,并构建管道来规范化数据、计算指纹并根据某些条件添加特定标签。此标签有助于区分已知良性和未知数据。
规范化
规范化是将数据组织和转换为一致且标准化格式的过程。当处理大量不同的数据时,规范化对于确保一致性、改进搜索和分析功能以及实现高效的数据处理变得非常重要。
目标是确保具有唯一标识符的文档不再唯一。例如,我们删除安装后“ /opt/Elastic/Agent/data/
”目录中 Elastic Agent 的唯一 6 字符文件名。这确保了来自不同 Elastic Agent 的数据可以完全比较,从而在后续的管道阶段提供更多的过滤机会。
为了实现这一目标,我们利用了 gsub 管道。它允许我们对数据管道中的字段应用基于正则表达式的转换。我们执行模式匹配和替换操作来规范化事件数据,例如删除特殊字符、将文本转换为小写或将某些模式替换为标准化值。
通过分析我们的数据集,我们发现了一组需要规范化的候选项,并创建了一个简单的 Python 脚本,根据匹配值和替换值生成一个 gsub 处理器列表。我们利用的脚本可以在 GitHub 上找到。使用脚本的输出,我们可以利用开发工具创建一个包含生成的 gsub 处理器的管道。
在使用规范化管道之前,每个 Elastic 代理的文档都包含随机的 6 个字符的字符串。示例如下所示。
通过规范化管道摄取和操作文档后,结果如下所示。
当所有文档都规范化后,我们可以继续进行指纹计算过程。
指纹计算
指纹计算通常用于基于文档内容生成唯一标识符。指纹摄取管道提供了一种通过计算基于指定字段和选项的哈希值来生成此类标识符的便捷方法,从而可以高效地进行文档重复数据删除和比较。该管道提供各种选项,包括算法(例如 MD5 或 SHA-1)、用于存储生成的指纹的目标字段,以及在计算中包含或排除特定字段的功能。
我们需要计算从多个来源和集成(例如端点、auditd 管理器、packetbeat、文件完整性监视等)摄取到 Elasticsearch 的文档的指纹。要计算指纹,我们首先需要指定要为其计算指纹的字段。由于不同的数据源使用不同的字段,因此为每种数据类型创建单独的处理器非常重要。对于我们的用例,我们最终为以下事件类别创建了不同的指纹处理器
通过指定条件,我们确保每个处理器仅在其相应的数据集上运行。
这些处理器中包含的字段至关重要,因为它们可以指示某个字段是否不如预期那样静态,或者空字段是否会导致管道无法正常工作。例如,当处理网络数据时,最初可能需要包括协议、目标 IP、目标端口、源 IP 和源端口。但这会在管道中导致过多噪音,因为在系统上打开的套接字将在临时源端口上打开,这将导致在其他情况下相同的网络流量产生许多唯一的指纹。一些可能发生变化的字段与文件大小、版本号或未解析的特定文本字段有关。规范化有时会保留对指纹识别无用的字段,指纹越具体,它的用处就越小。按文件哈希进行指纹识别说明了这一点,虽然向文件中添加一个空格会导致计算新的哈希,但这会破坏该文件的基于哈希的现有指纹。
字段选择是一个繁琐的过程,但对于获得良好的结果至关重要。对于特定的集成(如 auditd 管理器),我们可以在 GitHub 上的 导出的字段,并选择似乎对我们有用的字段。我们用于 auditd_manager
的处理器的示例如下图所示。
充实过程
富集摄取管道 用于使用来自外部数据源的额外信息来丰富传入的文档。它允许您根据特定条件对索引或数据集执行查找,从而丰富您的数据。富集摄取管道的常见用例包括使用来自参考数据集(如地理位置或客户信息)的数据来扩充文档,以及使用上下文信息(如威胁情报标签)来丰富日志。
在此项目中,我们利用富集管道在摄入的文档符合富集策略中描述的某些条件时,向其添加唯一标识符。为了实现这一点,我们首先使用规范化和指纹计算管道组合摄入了一大批具有代表性的良性数据。摄入完成后,我们通过执行富集策略 API 设置了几个 富集策略 。这些富集策略的执行将创建一组新的 .enrich-* 系统索引。存储在这些索引中的结果稍后将由用于摄入混合(良性和恶意)数据的管道使用。
通过一个示例工作流可以更好地理解这一点。要利用富集摄取管道,我们首先需要创建富集策略。由于我们正在处理不同的数据源(意味着网络数据与 auditd 管理器数据看起来非常不同),因此我们必须为每种数据类型创建一个富集策略。在我们的富集策略中,我们可以使用查询来指定我们想要包含在富集索引中的文档,以及我们想要排除的文档。下面显示了一个示例富集策略,该策略应将所有 auditd 管理器数据添加到富集索引中,但与三个特定匹配短语匹配的数据除外。
我们正在利用在指纹处理器中计算的“指纹”字段作为我们的匹配字段。这将创建一个填充有良性指纹的索引,用作富集管道中的富集索引。
创建此策略后,我们必须执行它,以便它读取匹配索引,读取匹配字段,查询包含和排除项,并创建新的 .enrich-* 系统索引。我们通过向 _execute API 发送 POST 请求来执行此操作。
我们设置 wait_for_completion=false 以确保策略不会超时。如果数据集太大,则可能会发生这种情况。当我们导航到索引管理并包含隐藏索引时,我们可以看到索引已成功创建。
我们现在有了一个已知的良性指纹列表,我们将在富集管道中使用它来过滤我们的混合数据集。我们的富集管道将再次使用条件来区分数据源。下面显示了我们的富集处理器的概述。
专注于 auditd 管理器,我们使用条件字段构建了一个富集处理器,以检查文档的数据集是否为 auditd_manager.auditd。如果匹配,我们引用我们为该数据集创建的富集策略。使用指纹字段,我们匹配并丰富传入的文档。如果指纹在我们创建的富集索引中已知,我们将带有指纹的“enrich_label”字段添加到文档中。请参阅下面的处理器。
一旦来自 auditd_manager.auditd 数据集的文档通过,就会执行富集处理器,最后执行一个 脚本处理器 。脚本处理器允许我们在传入的文档上运行内联或存储的脚本。我们利用此功能读取管道中的每个文档,检查是否添加了“enrich_label”字段;如果是这种情况,我们将名为“known_benign”的新布尔字段设置为 true,并删除“enrich_label”和“enriched_fingerprint”字段。如果文档不包含“enrich_label”字段,我们将“known_benign”设置为 false。这使我们能够轻松地在 Kibana 中过滤我们的混合数据集。
当使用“测试管道”功能并添加包含“enrich_label”的文档时,我们可以看到设置了“fingerprint”和“known_benign”字段。
对于不包含“enrich_label”的文档,仅设置指纹。
使用这些富集策略需要进行一些设置,但一旦它们结构良好,它们确实可以过滤掉很多噪音。由于手动执行此操作需要大量工作,因此我们创建了一些简单的 Python 脚本来在一定程度上自动化此过程。我们将在稍后详细介绍如何自动化这些富集策略的创建、执行、富集管道的创建等等。
摄取管道链接
管道摄取管道 提供了一种链接多个摄取管道的方法。通过链接管道,我们创建了一系列操作,这些操作共同以我们想要的形式塑造传入的数据,从而满足我们对数据规范化、指纹计算和数据富集的需求。
在我们与 Detonate 的合作中,我们最终创建了两个摄取管道。第一个将处理良性数据,其中包括规范化管道和指纹计算管道。下一个将处理恶意数据,其中包括规范化、指纹计算和富集管道。一个例子如下
管道到位后,我们需要确保它们在摄入数据时实际被使用。为了实现这一点,我们利用组件模板。
组件模板
组件模板 是可重用的配置,用于定义特定类型的 Elasticsearch 组件的设置和映射。它们提供了一种方便的方法来定义和管理多个组件之间的一致配置,从而简化了资源的管理和维护。
当您首次开始使用任何 Fleet 集成时,您会注意到默认情况下会创建许多组件模板。这些也被标记为“受管理”,这意味着您无法更改配置。
为了适应想要对通过 Fleet 管理的代理摄入的事件进行后处理的用户,所有索引模板都会调用一个名称以 @custom
结尾的最终组件模板。
您放入这些组件的设置永远不会因更新而更改。在我们的用例中,我们使用这些模板来添加富集字段的映射。通过 Fleet 及其集成摄入的大部分数据都将通过摄取管道。这些管道将遵循相同的模式,以便适应用户自定义。例如,请看以下摄取管道
我们可以看到它由 Fleet 管理,并且与集成的特定版本(例如 8.8.0)相关联。处理器将以调用 @custom
管道结束,如果它不存在,则忽略它。
我们想要使用我们在上一节中描述的富集管道将我们的富集数据添加到文档中。现在可以通过创建 @custom
管道并让它调用富集管道来简单地完成此操作。
自动化流程
为了创建 gsub 处理器、摄取管道和富集策略,我们必须使用三个 Python 脚本。在下一节中,我们将展示这些脚本。如果您选择集成这些脚本,请记住您需要调整它们以匹配您自己的环境才能使其工作。
创建 gsub 摄取管道
为了创建 gsub 管道,该管道将给定的随机路径替换为静态路径,我们使用了一个 Python 脚本 ,该脚本以多个字段和模式作为输入,并打印出一个 json 对象,该对象可由管道创建 API 使用。
创建自定义管道
设置 gsub 管道后,我们利用 第二个 Python 脚本 ,该脚本搜索所有调用 @custom 摄取管道的 Fleet 管理的配置。然后它将创建适当的管道,之后所有自定义管道都将指向 process_local_events
管道。
生成富集处理器
最后,我们创建了一个 第三个 Python 脚本,它将分四个步骤处理富集处理器的创建。
清理过程
:当在摄取管道中使用富集处理器时,无法删除它。在测试和开发期间,我们只是删除并重新创建摄取管道。当然,不建议在生产环境中使用此方法。创建富集策略
:该脚本将创建每个单独的策略。执行策略
:这将开始创建隐藏的富集系统索引的过程。请注意,策略的执行将比脚本的执行花费更长的时间,因为它不会等待命令完成。Elastic 将在后台创建富集索引。重新创建摄取管道
:更新富集策略后,我们现在可以重新创建使用富集的摄取管道。
执行这三个脚本后,整个设置就完成了,恶意数据可以摄入到正确的命名空间中。
结果和限制
我们的良性数据集包括 53,267,892 个文档,这些文档是通过在各种操作系统上执行受信任的二进制文件并从高价值数据源收集事件而生成的。使用此规范化的良性数据集,我们计算了指纹并为每种数据类型创建了富集策略。
在此设置到位后,我们引爆了 332 个样本。从数据集中删除 Elastic 代理指标和端点警报后,我们最终得到了一个包含总共 41,710,279 个文档的混合数据集。
将“known_benign”设置为 false 后,我们最终得到 1,321,949 个文档。这使文档计数减少了 96.83%。
下表概述了每个数据源及其在根据我们的“known_benign”字段进行过滤之前和之后的相应文档数。
我们可以看到,我们设法以相当不错的百分比成功地过滤了大多数数据源。此外,“之后”列中显示的数据包括我们确实想要捕获的恶意数据。例如,在不同的恶意软件样本中,有几个包括勒索软件,它往往会创建大量文件事件。此外,所有 http 流量都源自恶意软件样本试图连接到其 C2 的情况。auditd_manager 和 fim.event 数据集包括样本执行的许多系统调用和文件更改。
在构建此管道的过程中,我们吸取了一些教训。首先,正如之前提到的,如果你在指纹计算中添加了一个错误的字段,整个数据集可能会产生大量的噪声。例如,将源端口 (source.port) 添加到 Packetbeat 指纹计算中,会导致 endpoint.events.network 和所有 network_traffic-* 数据集大幅增加。
我们学到的第二个教训:拥有一个具有代表性的数据集很重要,同时拥有一个大型数据集也很重要。这两者是相辅相成的,但我们了解到,如果数据集太小,或者数据集产生的行为与之后要摄取的数据集不相似,会导致管道的效率降低一半以上。
最后,某些数据源比其他数据源更适合这种过滤方法。例如,在处理 system.syslog
和 system.auth
事件时,文档中的大多数字段(消息字段除外)始终相同。由于我们不能将此方法用于非结构化数据(例如纯文本字段),因此当仅查看其余字段时,我们的过滤器将过滤掉 99% 的事件。
可视化结果
Kibana 提供了许多出色的选项来可视化大型数据集。我们选择利用 Kibana 中的 Lens 功能来搜索我们的恶意数据集。通过将 known_benign
设置为 false,将 指纹计数
作为指标,并按升序排序,我们可以立即看到不同的恶意软件样本执行不同的任务。下面显示了文件事件的示例。
在此表中,我们可以看到:- 在 /dev/shm/
目录中创建了可疑文件 - 创建了 “HOW_TO_DECRYPT.txt
” 文件,表明勒索信息的创建 - 文件被更改为包含新的随机文件扩展名,表明勒索软件加密过程。
当查看文件完整性监视事件时,我们也可以通过应用相同的过滤器来轻松区分良性事件和恶意事件。
我们立即注意到为 linux.service
和 bot.service
创建了符号链接,以及一些运行控制符号链接,以在系统上建立持久性。
查看网络连接,我们可以看到恶意样本尝试与几个不常见端口上的潜在 C2 服务器建立 connection_attempted
事件。
最后,查看 auditd manager 系统调用事件,我们可以看到恶意软件打开 cmdline 和 maps 等文件,并尝试更改多个文件的权限。
总的来说,我们认为数据清理结果非常令人鼓舞,使我们能够更有效地进行大规模动态恶意软件分析。该过程始终可以进一步优化,因此请随意利用我们的方法,并根据您的特定需求进行微调。
超越动态恶意软件分析
在前几节中,我们描述了利用指纹和丰富摄取管道的具体用例。除了恶意软件分析之外,还有许多其他领域可以从类似于上述概述的工作流程中获益。下面描述了其中的一些应用程序和用例
- 取证和安全:指纹识别可用于数字取证和安全调查,以识别和链接相关工件或事件。它有助于追溯数据来源、分析模式以及识别日志文件、网络流量或系统事件中潜在的威胁或异常。微软的研究人员在 之前的研究 中利用模糊哈希来检测恶意 Web Shell 流量。
- 身份解析:指纹识别可用于跨不同数据源唯一标识个人或实体。这在欺诈检测、客户关系管理和数据集成等应用中非常有用,在这些应用中,基于唯一标识符匹配和合并记录至关重要。
- 数据去重:指纹识别可以帮助识别和消除数据集中的重复记录或文档。通过比较指纹,您可以有效地检测和删除重复条目,确保数据完整性并提高存储效率。对数据去重用例感兴趣的读者可能会发现诸如 Logslash 等预构建工具在实现此目标方面具有巨大的价值。
- 内容管理:指纹识别可用于内容管理系统,以检测重复或相似的文档、图像或媒体文件。它通过提高搜索准确性和增强整体用户体验,帮助进行内容去重、相似性匹配和基于内容搜索。
- 媒体识别:指纹识别技术广泛应用于媒体识别系统。通过为音频或视频内容生成唯一的指纹,可以识别受版权保护的材料、检测抄袭或启用基于媒体相似性的内容推荐系统。
结论
动态恶意软件分析有很多不同的方法。这篇博文通过利用 Elastic 提供的强大功能探索了其中一些选项。我们的目标是提出一种新的动态恶意软件分析方法,同时拓宽您对 Elastic 内置功能的理解和知识。
Elastic Security Labs 是 Elastic Security 的威胁情报部门,致力于在威胁环境中创造积极的改变。Elastic Security Labs 提供有关新兴威胁的公开研究,分析战略、运营和战术对手目标,然后将该研究与 Elastic Security 的内置检测和响应功能集成。
在 Twitter 上关注 Elastic Security Labs @elasticseclabs,并在 www.elastic.co/security-labs/ 查看我们的研究。