Unit 42 科学研究相关人员检查了几个包含 Cobalt Strike 模块的蓄意程序样品,并发现透过预测进程中关键继续执行钻孔能捕捉那些样品。
cobalt strike ( 简称 CS ) 是这款项目组作战渗入试验宝物 , 分为应用程序及服务器端,两个服务器端能对应数个应用程序,两个应用程序能相连数个服务器端。它不仅在蓝队中流行,而且也被用于蓄意目的。
尽管该应用软件包只出售给受信赖的组织机构进行安全可靠试验,但虽然源码泄露,它的各种模块无可避免地进入了普通用户的催泪剂,从敲诈应用软件组织机构到国家支持的反击组织机构。误用 Cobalt Strike 的蓄意程序甚至在 2020 年恶名昭彰的 SolarWinds 物流配送反击事件发挥了作用。
为什么是 Cobalt Strike?
Cobalt Strike 之所以被如此广泛的利用,主要就是因为 Cobalt Strike 应用软件系统了路由器转贴、扫描器多模式路由器 Listener、Window的避免出现技术。
Cobalt Strike 的主要就缺点之一是,一旦如上所述读取流程被继续执行,它主要就在缓存中运转。当有效率阻抗是动态防雷的、仅存有于缓存中并且拒绝继续执行时,这种情况会给检验带来问题。这对很多安全可靠应用软件产品来说都是两个挑战,因为扫描器缓存Satna。
在很多情况下,Cobalt Strike 是在目标网络中获得如上所述足印的天择。普通用户能使用具有大量部署和混为一谈快捷键的构筑器,根据可订制的模版建立最终有效率阻抗。
该有效率阻抗一般来说以身份验证或代码的方式内嵌到文档读取流程中。当被害者继续执行文档读取流程时,它将有效率阻抗NSA / 音频到缓存中并运转它。虽然有效率阻抗以其原始方式存有于缓存中,因而虽然某些某一功能,能很容易地检验到它。
作为蓄意程序科学研究相关人员,他们经常看到潜在性的有意思的蓄意样品,结果只是 Cobalt Strike 的读取流程。一般来说也不清楚读取流程是由蓝队建立的还是真正的普通用户建立的,因而使卡日丹极具诱惑力。
接下来他们将深入探讨四种相同的 Cobalt Strike 读取流程,它们是由他们设计的两个捷伊基于管理流程的沙盒检验到的,该沙盒允许他们预测缓存中的钻孔。每个实例读取相同的置入类型,即 SMB、HTTPS 和 stager 吊舱。他们将那些 Cobalt Strike 运载流程称为 KoboldLoader, MagnetLoader 和 LithiumLoader。他们还将讨论能用来检验那些有效率阻抗的一些方法。
KoboldLoader SMB 吊舱
以以下样品为例
SHA256: 7ccf0bbd0350e7dbe91706279d1a7704fe72dcec74257d4dc35852fcc65ba292
这个 64 位 KoboldLoader 可继续执行文档使用各种已知的技巧来绕过沙盒,并使预测过程更加耗时。
为了绕过只挂钩高级用户模式函数的沙盒,它只调用内置 API 函数。为了使预测相关人员的工作更加困难,它透过哈希而不是使用纯文本字符串来动态解析函数。蓄意程序包含调用以下函数的代码:
该蓄意程序建立了两个单独的函数哈希 / 地址对表。两个表包含所有内置函数的一对,而第二个表只包含 Nt* 个函数对。
对于所使用的 Rtl* 函数,它循环遍历第两个表并搜索函数哈希以获得函数地址。对于使用的 Nt* 函数,它遍历第二个表并同时增加两个计数器变量。
系统调用号,并输入自定义系统调用存根。这有效率地绕过了很多沙盒,即使挂接了较低级别的内置函数而不是高级函数。
读取流程的整体功能相对简单,并使用映射注入来运转阻抗。它生成 Windows 工具 sethc.exe 的子进程,建立两个新部分,并将NSA的 Cobalt Strike 吊舱读取流程映射到其中。Cobalt Strike 读取流程的最终继续执行是透过调用 RtlCreateUserThread 来读取 SMB 吊舱的。
缓存中的避免出现功能
透过捷伊基于管理流程的沙盒,他们能够在缓存中检验到NSA的 Cobalt Strike SMB 吊舱。这个吊舱读取流程甚至使用了一些缓存中的避免出现功能,建立了一种奇怪的嵌合体文档。虽然它实际上是两个 DLL,但 “MZ” 神奇的 PE 字节和随后的 DOS 标头被两个小的读取流程 shellcode 覆盖,如下图所示。
NSA的 Cobalt Strike SMB 信标 shellcode
shellcode 读取流程跳转到导出的函数 DllCanUnloadNow,该函数在缓存中准备 SMB 吊舱模块。为此,它首先读取 Windows pla.dll 库,并清空代码段 ( .text ) 中的一大块字节。然后,它将吊舱文档写入该 blob 并修复导入地址表,从而建立两个可继续执行缓存模块。
在预测该文档的过程中,他们能找出所使用的一些缓存内避免出现功能,如下表所示。
内存内避免出现功能
总之,吊舱读取流程和吊舱本身是同两个文档。PE 标头的部分用于跳转到导出函数的 shellcode,该函数反过来在 Windows DLL 中建立自己的模块。最后,shellcode 跳转到吊舱模块的入口点,在缓存中继续执行它。
如上所述,他们没有办法成功检验他们的 KoboldLoader 实例的吊舱,除非他们能在继续执行过程中查看缓存内部。
MagnetLoader
他们将科学研究的第二个读取流程是两个模仿合法库的 64 位 DLL。
SHA256:6c328aa7e903702358de31a388026652e82920109e7d34bb25acdc88f07a5e0
这个 MagnetLoader 实例试图在一些方面看起来像 Windows 文档 mscms.dll,透过使用以下类似的功能:
相同的文档描述;
两个具有很多相同函数名的导出表;
几乎相同的资源;
两个非常相似的互斥锁;
那些功能也显示在下图中,其中蓄意程序文档与有效率的 mscml.dll 进行了对比。
MagnetLoader ( 左 ) 和 mscml.dll ( 右 ) 的文档描述、导出表和资源的比较
MagnetLoader 不仅尝试动态地模拟合法的 Windows 库,而且在运转时也如此。
MagnetLoader 的所有导出函数内部调用相同的主要就蓄意程序例程。当调用其中两个时,首先运转 DLL 入口点。在入口点,蓄意软件读取原始的 mscms.dll,并解析它所伪造的所有函数。
那些原始函数的地址在继续执行伪方法后被存储和调用。因而,每当调用 MagnetLoader 的导出函数时,它都会运转主蓄意程序例程,然后调用 mscms.dll 中的原始函数。
主要就的蓄意程序例程相对简单。它首先建立了两个名为 SM0:220:304:WilStaging_02_p1h 的互斥体,看起来与 mscms.dll 建立的原始互斥体非常相似。
Cobalt Strike 吊舱读取流程被NSA到缓存缓冲区中,并在两个已知的技巧的帮助下继续执行。读取流程没有直接调用吊舱读取流程,而是使用 Windows API 函数 EnumChildWindows 来运转它。
该函数包含三个参数,其中两个是回调函数。蓄意程序可能误用此参数,透过回调函数间接调用地址,从而隐藏继续执行流程。
LithiumLoader
最后两个 Cobalt Strike 实例是 DLL 侧读取链的一部分,其中使用了一种安全可靠应用软件的自定义安装流程。DLL 侧读取是一种劫持合法应用流程以运转独立的蓄意 DLL 的技术。
SHA256: 8129 bd45466c2676b248c08bb0efcd9ccc8b684abf3435e290fcf4739c0a439f
这个 32 位的 LithiumLoader DLL 是由普通用户自定义建立的 Fortinet VPN 安装包的一部分,该安装包以 FortiClientVPN_windows.exe ( SHA256: a1239c93d43d657056e60f6694a73d9ae0fb304cb6c1b47ee2b38376ec21c786 ) 的方式提交给 VirusTotal。
FortiClientVPN_windows.exe 文档不是蓄意的或被破坏的。虽然该文档是签名的,普通用户利用它来逃避反病毒检验。
安装流程是一个自解压缩 RAR 存档,包含以下文档:
FortiClientVPN_windows.exe 文档内容
自解压脚本命令如下:
自解压脚本命令列表
当安装流程运转时,所有文档都会被无声地放到本地 %AppData% 文档夹中,两个可继续执行文档都会启动。当 FortiClient VPN 安装流程继续执行时,WinGup 工具侧读取 libcurl.dll LithiumLoader 蓄意程序。蓄意程序之所以这样做,是因为它从 libcurl 库的合法副本中导入了以下函数,如下图所示:
导入 WinGup.exe 的地址表
此威胁还试图透过 PowerShell 将 %AppData% 文档夹路径添加到 Windows 防御器中的排除列表中。
在启动 GUP.exe 时,蓄意的 libcurl.dll 文档被读取到进程空间中,因为它动态地导入上图所示的函数。虽然所有四个 libcurl 函数都在运转,但只有 curl_easy_cleanup 包含在编译库的新版本时注入的蓄意例程。因而,他们不是在处理合法 DLL 的打了补丁的版本。这是一种更干净的解决方案,不会像在其他蓄意程序中经常看到的那样,在插入蓄意程序后破坏代码。
这个 curl_easy_cleanup 函数一般来说只包含两个子例程 ( Curl_close ) ,并且没有返回值 ( 如其在 GitHub 上的源码所示 ) 。修改后的函数如下图所示。
修改了 libcurl.dll 的 curl_easy_cleanup 导出函数
load_shellcode 函数透过 XOR 和密钥 0xA NSA shellcode,如下图所示。
Shellcode 读取流程函数 load_shellcode ( )
这个函数透过 EnumSystemGeoID 间接运转 Cobalt Strike 阶段 shellcode,而不是直接跳转到它。这个 Windows API 函数有三个参数,最后两个参数是两个被 LithiumLoader 误用的回调函数。
Cobalt Strike stager shellcode 是从 Metasploit 借来的,是反向的 HTTP 外壳阻抗,它使用以下 API 函数:
shellcode 相连到以下 URL,其中包含泰国一所大学的 IP 地址
LithiumLoader 检验问题
在本文发布时,Cobalt Strike 吊舱的有效率阻抗已不再可用。如果 API 调用的继续执行报告中没有有效率阻抗或任何可操作的信息,沙盒一般来说很难确定样品是否蓄意。这个实例本身没有任何能被归类为蓄意的功能。
透过缓存预测寻找 Cobalt Strike
在这三个例子中都存有一些常见的检验挑战。那些实例不能在正常的沙盒环境中继续执行。但是正如他们所讨论的,如果他们在继续执行期间查看缓存内部,就能使用大量的信息进行检验,比如函数指针、已音频的读取程序阶段和其他钻孔。
为了准确地检验,科学研究相关人员发现解决高度避免出现蓄意程序的两个关键功能是,除了使用系统 API 更好地理解所发生的事情外,还需要在继续执行样品时查看缓存。
科学研究相关人员发现,在蓄意程序检验中,查看继续执行关键点的缓存增量,以提取有意义的信息和钻孔是很有用的。当他们的系统处理大量的样品时,要实现大规模的工作有很多挑战。接下去,他们将详细介绍目前从缓存中收集的一些主要就类型的数据,以帮助检验。尽管他们在本文介绍的是透过缓存方法,但他们绝不是说检验和记录 API 调用对检验没有用。
自动有效率阻抗提取
如上所述,蓄意程序开发者混为一谈其有效率阻抗越来越普遍。虽然使用可继续执行打包器能压缩和模糊文档来实现这一点并不新鲜,但当它与逃避策略结合使用时就会出现问题,因为没有对准确检验有用的动态或动态数据。
代码、压缩、身份验证或下载额外的继续执行阶段的策略有无限的组合。为那些有效率阻抗制作签名的能力显然是预测师能够从 Cobalt Strike 等框架中捕捉大量相同蓄意程序模块的重要方式。如果他们能在缓存中捕捉到它们,那么蓄意程序最终决定不继续执行也无所谓。
下面简化图显示了他们可能在两个阶段中看到的实例,那些阶段在如上所述可继续执行文档中从未出现过。
能在打包的蓄意程序可继续执行文档中看到的典型阶段
在图的左侧,他们看到了两个 shellcode 阶段的实例。尽管 “shellcode” 一词最初是为利用漏洞在目标系统上弹出外壳而手工制作的流程集而创造的,但该词已演变为包含任何为蓄意目的编写的自定义流程集。一些蓄意程序阶段是没有可识别的可继续执行结构的自定义流程集。蓄意程序开发者采用这种方法的常见模式是将所有函数指针动态解析到两个表中,以便于访问。
在图的右侧,他们看到后期是两个格式良好的可继续执行文档的实例。一些蓄意程序阶段或有效率阻抗是格式良好的可继续执行文档。那些能由 OS 透过系统 API 读取,或者蓄意程序开发者可能会使用他们自己的 PE 读取流程,如果他们试图隐蔽地避免调用任何 API 来为他们读取。
函数指针数据
他们能从缓存中提取的另一组用于检验的丰富数据是动态解析函数指针,如下图所示。蓄意程序的开发者很久以前就知道,如果他们显式地调用他们计划在导入表中使用的所有 WINAPI 函数,它就会被用来对付他们。现在的标准做法是隐藏蓄意程序或其任何阶段将使用的功能。
Shellcode 哈希是另一种常见的隐蔽策略,用于解析函数的指针而不需要它们的字符串。
可能在缓存段中看到的动态解析 WINAPI 指针实例
在 Advanced WildFire 中,他们已经开始有选择地搜索和使用在他们的检验逻辑中解析了哪些 WINAPI 函数指针的信息。
操作系统结构修改
了哪些库、读取了可继续执行映像的位置以及 OS 稍后可能需要了解的进程的其他各种特征。考虑到那些字段中的很多都不应该被修改,跟踪蓄意程序样品何时以及如何操作它们一般来说很有用。
下图显示了实例如何从 LDR 模块列表中卸载它读取的模块。取消查找模块意味着不再存有该模块存有的记录。例如,这样做之后,Windows 中的任务管理器将不再列出它。
此图仅是科学研究相关人员所看到的很多相同的 OS 结构修改中的一种,但它表明有很多相同类型的 OS 结构更改对蓄意程序检验问题有用。
如何将模块从 LDR 模块列表中解关联的实例
页面权限
需要更改缓存权限,以便正确读取和继续执行进一步的阶段。了解哪些缓存页的权限发生了更改,一般来说能提供有关代码读取和继续执行位置的重要见解,这对检验非常有用。
总结
尽管 Cobalt Strike 已经存有多年,但检验它对很多安全可靠应用软件提供商来说仍然是两个挑战。这是因为该工具主要就在缓存中工作,不太接触磁盘。
本文介绍了四种捷伊读取流程,并展示了如何使用各种技术检验它们,那些检验技术在捷伊基于管理流程的沙盒中可用。
查看原文