前言
2024年1月12日,Malwrhunterteam(一个X账号,用于发布有趣的恶意软件样本,通常通过VirusTotal发现)发布了一条推文,内容关于一个似乎包含恶意功能的盗版macOS应用程序。macOS安全研究员Patrick Wardle很快发布了一篇文章,详细介绍了该应用程序的恶意功能,包括投放第二阶段和第三阶段有效载荷。此后不久,JAMF Threat Labs团队发布了一篇博客,其中捕获了在Malwrhunterteam发布推文之前JAMF一直在追踪的几个额外的同类样本,深入探讨了此恶意软件提供的内部结构和核心功能。如果您还没有阅读这两篇精彩的文章,那么这些资料中有很多有用的细节和背景信息,可以为后续分析提供更多上下文。
本报告不会涵盖恶意软件内部结构或相关样本。相反,我们将着重提供实用、可靠的检测和威胁狩猎指导,使您能够对这种或类似的恶意软件采取的行动发出警报。基于签名的检测通常无法达到这种能力;但是,我们将重点介绍我们的行为规则是如何处理这个问题的。
我们将分解恶意软件在每个阶段的行为,并分析如何使用来自macOS 端点安全框架 (ESF) 和Elastic Agent 的数据来构建这些检测。让我们开始吧。
UltraEdit
UltraEdit 应用程序(一个合法的文本和十六进制编辑器)被盗版(被修改然后被滥用以促进恶意软件分发),以及其他几个应用程序,并通过磁盘映像文件(.dmg
)分发。
执行盗版版本的应用程序后,它会立即加载一个第三方未签名的 dylib(macOS 共享库),名为 libConfigurer64.dylib
。此 dylib 充当投放程序,其目标是下载并执行后续有效载荷。该 dylib 下载并执行两个隐藏文件:/private/tmp/.test
和 /Users/Shared/.fseventsd
。
查看应用程序采取的初始操作,我们可以看到未签名的第三方 dylib 加载在 Elastic Security Solution 的分析器视图中立即发生。这是一个重要的事件,因为它是唯一加载的非系统库。
在 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
是恶意 dylib 在 (/Users/Shared/.fseventsd
) 中投放的第二个有效载荷。此有效载荷的目的是利用伪装的启动代理在受害者的计算机上提供持久立足点,并充当尚未找到的另一个有效载荷的下载器。尽管如此,我们从.fseventsd
的反向工程中知道它被命名为(.fseventsds
)。
通过 Elastic 分析器视图,我们可以看到第一个值得注意的事件是伪装启动代理的持久性安装。
这项活动可以从两个不同的角度来处理。首先,我们可以利用文件事件和进程代码签名数据来查找伪装的.plist
文件来检测它。在下面的行为规则中,我们查找文件名以com.apple…
开头且文件路径为Library/LaunchAgent
或Library/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
值设置为true
或keepalive
值设置为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 的许多活动。我们关于 DPRK 恶意软件 KANDYKORN 的报告显示,这些活动是模块化的,包含多个阶段的有效负载,其功能分布在这些有效负载之间以避免检测。您可以看到,使用 UltraEdit,一个有效负载充当交互式后门,另一个有效负载充当持久性机制。像这样的恶意软件通常可以轻松更新以避免签名。但是,正如我们所展示的,行为规则是不可避免的,并且使我们能够弥合静态签名和机器学习模型之间的差距。
如果您拥有正确的数据以及关联这些数据的能力,基于行为的规则非常强大。我们的端点行为规则可以检测和阻止恶意软件,无论其是否更新。仅在 macOS 上,我们就拥有 200 多条端点行为规则,包括本出版物中显示的规则版本,这些规则使我们能够通过实时观察其行为来检测和阻止以前“未检测到”的恶意软件。如果您想查看我们的生产端点行为规则,可以点击此处。要了解有关我们的查询语言的更多信息,可以查看此处(EQL 和 ES|QL)。我们很自豪成为一家开源公司,并希望让我们的软件和功能自己说话。如果您想自己测试和探索这些功能,可以轻松创建一个具有 30 天试用许可证的Elastic Cloud帐户,或者对于本地测试,您可以下载“Elastic Container 项目”,并在.env
文件中将许可证值设置为试用版。