Colson Wilhoit

利用 Elastic 行为检测击沉 macOS 海盗船

本研究着眼于最近发现的 macOS 恶意软件活动,使用 macOS 端点安全框架与 Elastic Agent 配对,以搜寻并检测此恶意软件表现出的行为。

阅读 11 分钟攻击模式
Sinking macOS Pirate Ships with Elastic Behavior Detections

前言

2024 年 1 月 12 日,Malwrhunterteam(一个通常通过 VirusTotal 发现有趣恶意软件样本的 X 帐户)发布了一条推文,内容是关于一个似乎包含恶意功能的盗版 macOS 应用程序。macOS 安全研究员 Patrick Wardle 迅速发布了一篇文章,详细介绍了该应用程序的恶意功能,其中包括释放第二阶段和第三阶段的有效载荷。不久之后,JAMF Threat Labs 团队发布了一篇博客,其中捕获了 JAMF 在 Malwrhunterteam 推文之前一直在跟踪的几个额外的同类样本,深入研究了此恶意软件提供的内部机制和核心功能。如果您还没有阅读这两篇精彩的文章,这些文章中有许多有用的细节和背景信息,可以为接下来的分析提供背景。

本出版物不会涵盖恶意软件的内部机制或相关样本。相反,我们将着眼于提供实用、可靠的检测和威胁搜寻指南,使您能够对此恶意软件或类似相关的恶意软件采取的操作发出警报。基于签名的检测通常无法满足此类功能;但是,我们将重点介绍我们的行为规则如何处理此问题。

我们将分解恶意软件在每个阶段的操作,并分析如何使用来自 macOS 端点安全框架 (ESF) 和 Elastic Agent 的数据来构建这些检测。让我们深入研究一下。

UltraEdit

UltraEdit 应用程序(一款合法的文本和十六进制编辑器)与其他几个应用程序一起被盗版(被修改,然后被滥用以促进恶意软件传播),并通过磁盘映像文件(.dmg)分发。

执行盗版版本的应用程序后,它会立即加载一个名为 libConfigurer64.dylib 的第三方、未签名的 dylib(macOS 共享库)。此 dylib 充当投放器,其目标是下载和执行后续有效载荷。dylib 下载并执行两个隐藏文件:/private/tmp/.test/Users/Shared/.fseventsd

查看应用程序采取的初始操作,我们可以看到在 Elastic Security Solution 的 Analyzer View 中,在执行后立即发生未签名的第三方 dylib 加载。这是一个重要的事件,需要重点关注,因为它是加载的唯一非系统库。

在 8.11 版本中,Elastic Defend 为 macOS Elastic Agent 引入了首创的 dylib 加载事件,允许我们捕获库加载以及有关这些库的详细信息,例如 dylib 签名数据。凭借这种强大的新可见性,我们可以快速构建一个 事件查询语言 (EQL) 查询,该查询查找来自卷挂载或应用程序目录结构的未签名 dylib 加载。

规则名称:应用程序未签名 Dylib 加载

library where event.action == "load" and dll.path :  
("/Volumes/*.app/Contents/*", "/Applications/*.app/Contents/*") 
and dll.code_signature.exists == false

我们可以而且应该更进一步,以仅识别正在加载未签名库的不可信或未签名进程。这将减少误报的数量,并仍然准确地捕获正在发生的事件。

规则名称:未签名或不可信应用程序未签名 Dylib 加载

library where event.action == "load" and  
(process.code_signature.exists == false or process.code_signature.trusted == false)  
and dll.path : ("/Volumes/*.app/Contents/*", "/Applications/*.app/Contents/*") and  
dll.code_signature.exists == false

现在,我们有了一个基于行为的检测,该检测会在加载未签名 dylib 的未签名进程上触发,并警告我们它的存在。

让我们看看其他的有效载荷及其操作,看看是否可以构建任何其他检测。

.test

.test 二进制文件被放置在下载后的临时目录中(/private/tmp/.test),并使用包含 SSH 二进制文件路径的进程参数执行。正如 JAMF Threat Labs 指出的那样,此 SSH 二进制文件不在 macOS 上 SSH 二进制文件的默认位置,该位置实际上位于 /usr/bin/ssh。此命令行与任何预期的功能都不相关,而是一种尝试融入的方式。

正如 Patrick Wardle 和 JAMF 所述,此二进制文件是开源、跨平台后利用代理 Khepri 的 macOS 构建版本,并提供对目标系统的完全后门访问。

从检测的角度来看,我们可以在此处创建一个非常具体的查询,该查询查找从可疑位置执行的隐藏二进制文件(文件前缀为句点,在 GUI 和 CLI 中对用户隐藏),这些二进制文件包含包含 SSH 二进制文件路径的进程参数。

创建这样一个查询的问题在于,正如 JAMF 指出的那样

恶意软件使用的一种特别有趣的技术是替换其命令行参数,以进一步融入操作系统。

恶意软件会在样本之间更新这些进程参数,因此,虽然此查询可能会检测到一个样本,但它们可以轻松地更改它并绕过此检测。

我们可以专注于从诸如 /tmp 之类的可疑目录执行的未签名、隐藏二进制文件,而不是进程参数。

规则名称:从临时目录执行的不可信或未签名的隐藏二进制文件

process where event.type == "start" and event.action == "exec" and  
process.executable : ("/private/tmp/*", "/tmp/*") and  
process.name : ".*" and (process.code_signature.exists == false or  
process.code_signature.trusted == false)

通过上述规则,如果任何隐藏的未签名或不可信的二进制文件尝试从临时目录执行,无论我们的签名还是我们的机器学习模型是否检测到它,我们都会收到警报。

(关于误报的说明:即使在 macOS 上从临时目录执行隐藏二进制文件的情况应该极其罕见,但这种情况也会发生。macOS 上有许多开发人员采用了不良的软件开发实践。误报应逐个案例进行审查,并且只有在软件获得业务批准和验证后才应通过规则或 Elastic 排除列表排除。)

除了此规则之外,由于隐藏的有效载荷建立出站命令和控制网络连接,我们还可以查找来自隐藏可执行文件的任何出站网络连接,因为这在 macOS 上是非常可疑的活动,并且至少应该发出警报。如果要减少误报的可能性,请指定特定的进程可执行目录,如 /Users/Shared//tmp/ 等,或包括指定未签名或不可信隐藏可执行文件的进程代码签名数据。

规则名称:隐藏可执行文件的出站网络连接

network where event.type == "start" and 
event.action == “connection_attempted” and process.name : ".*"

由于这是一个提供各种功能(上传、下载等)的后门有效载荷,因此创建额外的规则来查找来自未签名或不可信的隐藏二进制文件的其中一些操作是明智的。由于我们已经有一个可以检测隐藏二进制文件初始执行的规则,因此我们将继续处理下一个有效载荷。

.fseventsd

.fseventsd 是恶意动态链接库在 (/Users/Shared/.fseventsd) 释放的第二个有效载荷。该有效载荷的目的是利用伪装的启动代理在受害者机器上提供持久的立足点,并充当另一个尚未找到的有效载荷的下载器。尽管如此,我们通过对 .fseventsd 的逆向工程得知,它被命名为 (.fseventsds)。

通过 Elastic 分析器视图,我们可以看到第一个值得注意的事件是伪装启动代理的持久安装。

可以从两个不同的角度解决此活动。我们可以首先通过查找使用文件事件和进程代码签名数据的伪装 .plist 文件来检测此行为。在下面的行为规则中,我们查找文件名以 com.apple… 开头,并且文件路径是 Library/LaunchAgentLibrary/LaunchDaemon,并且负责的进程是未签名或不受信任的文件。

规则名称:通过伪装的 Plist 文件名实现的持久化

file where event.type != "deletion" and 
 file.name : "*com.apple*.plist" and
 file.path :
       ("/System/Library/LaunchAgents/*", 
        "/Library/LaunchAgents/*",
        "/Users/*/Library/LaunchAgents/*",
        "/System/Library/LaunchDaemons/*",
        "/Library/LaunchDaemons/*") and
(process.code_signature.trusted == false or  
process.code_signature.exists == false)

我们可以检测此持久安装技术的第二种方法是利用 Elastic Agent 独有的另一个新数据源,我的同事 Ricardo Ungureanu 和我将其添加到 Elastic Defend 的 8.6 版本中。我们创建了一个恰如其名的持久性事件,该事件监视启动服务目录并收集 plist 详细信息,然后以结构化事件的形式将其发送回来,该事件可用于围绕可疑或恶意的启动代理或守护程序创建规则。

在以下规则中,我们查找 runatload 值设置为 truekeepalive 值设置为 true 的启动事件。plist 参数包含 /Users/Shared 目录中隐藏的可执行文件的路径。此规则可以扩展为包括其他可疑或恶意的参数,这些参数会警告您恶意或可疑二进制文件安装了持久性。

规则名称:通过可疑的启动代理或启动守护程序实现的持久性

file where event.action == "launch_daemon" and  
(Persistence.runatload == true or Persistence.keepalive == true) and 
  Persistence.args : "/Users/Shared/.*"

也可以使用以下查询,使用此持久性事件检测伪装的 plist。

file where event.action == "launch_daemon" and  
Persistence.name : "com.apple.*" and  
(process.code_signature.exists == false or 
process.code_signature.trusted == false)

这里的最后一部分是下载丢失的第三阶段有效载荷。位于 /Users/Shared 文件夹中的隐藏 .fseventsd 会访问网络以下载此新的隐藏有效载荷到 /tmp/ 目录。您可能还记得我们已经创建了两个规则(“从临时目录执行的隐藏二进制文件”和“隐藏的可执行文件出站网络连接”),它们将检测此活动。

我们可以添加另一个规则来捕获在可疑目录中创建隐藏的可执行文件时的情况。我们可以查找任何文件事件,其中事件操作不是删除文件,文件名表示隐藏文件,该文件包含 Mach-O 标头字节,并且文件路径是不常执行隐藏文件的路径。如果文件是可执行文件,我们将收集文件标头字节,使我们能够将可执行文件与其他类型的文件区分开,而不仅仅基于文件扩展名。

规则名称:在不寻常的目录中创建隐藏的可执行文件

file where event.action != "deletion" and file.name : ".*" and 
file.Ext.header_bytes : ("cffaedfe*", "cafebabe*") and 
file.path : ("/Users/Shared/*", "/private/tmp/*", "/tmp/*")

总结

此恶意软件代表了当今许多针对 macOS 的活动。我们关于朝鲜恶意软件 KANDYKORN 的报告表明,这些活动是模块化的,包含多个阶段的有效载荷,这些有效载荷之间分配了功能,以避免被检测到。您可以看到,对于 UltraEdit,一个有效载荷充当交互式后门,另一个充当持久性机制。像这样的恶意软件通常可以轻松更新以避免签名。但是,正如我们所展示的那样,行为规则是不可避免的,并且使我们能够弥合静态签名和机器学习模型之间的差距。

如果您拥有正确的数据和关联这些数据的能力,则基于行为的规则非常强大。我们的端点行为规则可以检测和阻止恶意软件,无论它是否更新。仅在 macOS 上,我们就有 200 多个端点行为规则,包括本出版物中显示的版本,这些规则使我们能够通过实时观察其行为来检测和阻止以前“未检测到”的恶意软件。如果您想查看我们的生产端点行为规则,可以在这里找到它们。要了解有关我们的查询语言的更多信息,您可以在此处查看 (EQLES|QL)。我们很自豪能成为一家开源公司,并希望让我们的软件和功能自己说话。如果您想自己测试和探索这些功能,可以轻松创建一个包含 30 天试用许可证的 Elastic Cloud 帐户,或者对于本地测试,您可以下载“Elastic Container 项目”并将 .env 文件中的许可证值设置为试用版。

参考