一、背景
近期,我一直专注于macOS持久化领域,特别选择了一些较低级别用户可以修改的文件,而这些文件可能会影响用户交互。我发现,终端用户经常进行交互的一个位置是Dock。
通过研究,我发现有一个plist负责控制Apple Dock应用程序的可视化呈现。在这里没有太多突破性内容,因为终端用户经常会通过图形化界面(GUI)来修改这一plist。在查看了plist中的值之后,我想探究是否可以更改这些值,从而使用运行自定义代码的恶意应用程序来替换合法的应用程序。
这项研究中的一个突破是DockPersist.js,我将其纳入到PersistentJXA项目之中。在我的实现中,将使用恶意应用程序替换Safari或Chrome。我主要研究Safari和Chrome,因为二者很可能会出现在用户的Dock中。但是,这一理论实际上适用于任何应用程序。终端用户在单击Safari或Chrome图标后,就会运行我们的恶意应用程序。这种持久化方式类似于Windows上的快捷方式(.LNK)文件持久化,因为在macOS中,Dock图标通常会作为实际应用程序的快捷方式。
这种持久化方法需要将我们的恶意应用程序上传到目标计算机。我倾向于在Mythic代理中使用上传功能,将应用程序保存到目标上。
在修改plist之后,我们就可以立即重新加载Dock。但是,这会导致终端用户的屏幕出现短暂的闪烁。或者,我们也可以等待用户重新启动后,再让虚假的应用程序出现在Dock中,因为修改后的plist会在重新启动后保持不变。
二、攻击方式
2.1 部署
前面已经说过,这种持久化方式需要将恶意应用程序上传到目标。在此过程中,有多种方法可以绕过Gatekeeper保护,允许我们将恶意应用程序上传到目标。这些方法包括:
1、压缩应用程序包,在Mythic代理(Apfell或Poseidon)中使用上传命令,然后在目标计算机中解压缩。
2、压缩应用程序包,在某个位置托管,使用curl下载到目标,然后在目标计算机中解压缩。
3、压缩应用程序包,进行Base64编码,在进行Base64解码后保存到目标上,然后在目标计算机中解压缩。
作为概念验证(PoC),我仅仅是在“自动操作”(Automator)中创建了一个应用程序。PoC应用程序会打开Safari浏览器,这样就避免了终端用户没有感知的情况。然后,它将运行我们的Apfell Payload。
在PoC应用程序中,JXA打开Safari并执行Apfell Payload:
为了不让终端用户发觉,我将默认的“自动操作”图标替换为Safari浏览器。当然,如果使用Xcode,还可以创建更复杂的应用程序。
带有Safari浏览器图标的PoC应用程序,我们将其命名为Safari:
接下来,我压缩应用程序包,并将其上传到目标。在解压缩到/Users/Shared/之后,我们可以集中精力,在满足前提条件的情况下调用持久化方法。
注意:由于plist的二进制格式,自动实现要求将虚假的应用程序命名为“Google Chrome”或“Safari”,并且位于/Users/Shared/中。我们可以修改Safari64和Chrome64变量,以更改此位置。
2.2 调用持久化
将脚本导入Mythic中的Apfell代理:
调用DockPersist函数。该函数接受三个参数:应用程序名称(Safari或Google Chrome)、Bundle ID、是否立即重新加载Dock的选项。
注意:Bundle ID位于Info.plist中,可以使用以下命令来获取:
- /usr/libexec/PlistBuddy -c 'Print CFBundleIdentifier' ~/FakeApp/Safari.app/Contents/Info.plist
在Apfell代理中调用DockPersist函数,指定Safari、Bundle ID和是否重新加载Dock的选项:
三、检测方法
Crescendo是一个能在主机上迅速捕获事件的绝佳工具。Crescendo可以作为macOS的实时事件查看器,它的一项出色功能就是利用了Apple的终端安全框架(ESF)。ESF可以监视系统事件中是否存在潜在的恶意活动,实际上它是系统扩展框架中的一个API。与Windows相比较,可以将其理解为macOS上一个功能有限的事件追踪(ETW)。
通过Crescendo,我们可以轻松地查看由持久化执行创建的文件和进程事件。
对于不太了解ESF的读者,大家需要了解下面的一些事件会同步到Crescendo:
- ES_EVENT_TYPE_AUTH_EXEC = process::exec
- ES_EVENT_TYPE_NOTIFY_EXIT = process::exit
- ES_EVENT_TYPE_NOTIFY_CREATE = file::create
- ES_EVENT_TYPE_NOTIFY_KEXTLOAD = process:kext::load
- ES_EVENT_TYPE_NOTIFY_MOUNT = file::mount
- ES_EVENT_TYPE_NOTIFY_UNLINK = file::unlink
- ES_EVENT_TYPE_NOTIFY_RENAME = file::rename
- ES_EVENT_TYPE_NOTIFY_UIPC_CONNECT = network::ipcconnect
- ES_EVENT_TYPE_NOTIFY_FORK = process::fork
尽管目前Crescendo不会捕获ES_EVENT_TYPE_NOTIFY_MMAP、ES_EVENT_TYPE_NOTIFY_WRITE和ES_EVENT_TYPE_NOTIFY_EXEC,但它已经捕获到了这种持久化方式对应的足够多的事件。如果要应对其他恶意活动,我强烈建议使用Xorrior的Appmon。
下面重点介绍了持久化方法的执行,根据不同攻击者使用的具体方法,实际的恶意应用程序所对应的事件可能会有所不同。
首先,plutil将Dock plist转换为XML。XML格式更加易于操作。
Plutil将当前com.apple.dock.plist转换为XML格式:
随后,记录了temp9876文件创建和进程创建。
DockPersist.js在/private/tmp/下创建一个随机命名的文件。该脚本会修改plist的XML版本,并将其以随机文件名保存。在这里,temp0wsn4p包含XML格式的恶意plist,因此我们用正确加载Dock所需的二进制格式版本覆盖了此文件。
Plutil将修改后的plist转换回二进制格式:
接下来,DockPersist.js在~/Library/Preferences/com.apple.dock.plist中删除现有的plist。
删除当前的com.apple.dock.plist:
ESF捕获到这一动作,并将新的恶意plist以二进制格式保存到~/Library/Preferences/com.apple.dock.plist。
保存修改后的com.apple.dock.plist:
最后,由于我们在函数调用中制定了重新加载Dock,因此将调用killall。
重新加载Dock:
要建立检测方式,这些事件就是我们的起点。这里的关键是检测到了plutil和killall。此外,文件创建、删除和修改事件也同样可以用于检测。在攻击者进行持久化之前,还可以针对将恶意应用程序上传到目标计算机的这个动作来进行检测。
3.1 正常执行
大家可能会有一个疑问,现在我们了解了ESF是如何捕获已知恶意行为的,那么ESF会如何区分正常执行呢?
在正常执行的情况下,cfprefsd(Core Foundation Preferences Daemon)将会在com.apple.dock.plist上触发file::rename事件(文件覆盖)。当用户通过GUI手动对Dock进行更改时,也会触发这些事件。
com.apple.dock.plist的正常修改:
3.2 尝试逃避检测
攻击者可以在另一台主机上修改plist,然后将修改后的plist上传到目标计算机的对应位置,这样就能减少潜在指标的数量。但是,这样做仍然会触发file::rename事件,而这一事件不会使用在正常执行情况下的cfprefsd进程。由此看来,识别非cfprefsd进程对plist的修改动作,可能是检测恶意行为的一个较好的判断标准。
借助Apfell代理覆盖替换com.apple.dock.plist:
3.3 可视化指标
如果执行PoC应用程序,将会导致Dock中出现两个Safari实例。
恶意Safari应用程序与合法Safari应用程序:
第一个Safari是恶意的应用程序,位于plist的“persistent-apps”部分中,而第二个才是真实的Safari,它位于plist的“recent-apps”部分中。
四、其他指标
在浏览ESF日志之后,我注意到了其中包含了写入SQLite数据库的一些内容。如果攻击者利用了osascript,则需要注意的一点是,osascript在~/Library/Caches/com.apple.osascript/Cache.db的位置有一个缓存数据库。
注:上述缓存数据库的创建仅适用于攻击者使用osascript二进制的情况下。除此之外,我还深入研究了如果使用OSAKit替代osascript的情况。为了进行测试,我使用Sublime Text Plugin加载了JXA dylib。与osascript缓存数据库的位置不同,在这种情况下的C2条目被记录在~/Library/Caches/com.sublimetext.3/Cache.db之中。
使用SQLite对应的数据库浏览器查看该数据库后,我注意到其中的cfurl_cache_response表中包含Mythic服务器的IP地址,以及Mythic中用于命令和控制(C2)通信的GET请求的简短日志。这个缓存内容为应急排查提供了宝贵的来源。
通过数据库浏览器,在SQLite数据库中查看到C2通信的证据:
使用sqlite3命令行工具也可以查看到这些条目:
五、总结
在本文中,我们展示了macOS中类似于Windows .LNK文件的持久化攻击方法。更重要的是,我希望本文中分析的持久化指标可以帮助正在开发检测方式的研究人员。如果大家发现针对这一持久化方式还有其他检测指标,欢迎与我探讨。
六、参考资源
[1] https://posts.specterops.io/detection-engineering-using-apples-endpoint-security-framework-affdbcb18b02
[2] https://medium.com/red-teaming-with-a-blue-team-mentaility/taking-the-macos-endpoint-security-framework-for-a-quick-spin-802a462dba06
[3] https://attack.mitre.org/techniques/T1547/009/
[4] https://developer.apple.com/documentation/endpointsecurity?language=objc
[5] https://github.com/SuprHackerSteve/Crescendo
[6] https://bitbucket.org/xorrior/appmon/src/master/
[7] https://sqlitebrowser.org/
[8] https://eclecticlight.co/2017/07/06/sticky-preferences-why-trashing-or-editing-them-may-not-change-anything/
本文翻译自:https://posts.specterops.io/are-you-docking-kidding-me-9aa79c24bdc1如若转载,请注明原文地址:
【编辑推荐】