在2022年2月,卡巴斯基实验室的研究人员首次观察到将shellcode放入Windows事件日志的技术。该技术允许在文件系统中隐藏“无文件”最后stager的木马。这种对活动中事件日志的关注不仅限于存储 shellcode。 Dropper 模块还修复了与事件跟踪 (ETW) 和反恶意软件扫描接口 (AMSI) 相关的 Windows 原生 API 函数,以使感染过程更加隐蔽。
除了事件日志之外,攻击者的工具集中还有许多其他技术。其中,开发者在功能中增加了侦察,可以模仿合法域名的 C2 Web 域名,以及受害者使用的现有和软件的名称。为了使攻击更加隐蔽,攻击者使用 Linode、Namecheap、DreamVPS 上的虚拟专用服务器。
一种更常见的方法是使用大量的反检测解密器。攻击者使用不同的编译器,从微软的 cl.exe 或 MinGW 下的 GCC 到最新版本的 Go。此外,为避免被检测到,某些模块使用数字证书进行签名。研究人员认为它是由攻击者发布的,因为遥测数据没有显示任何与之签名的合法软件,只有这次活动中使用的恶意代码。
关于最后stager的特洛伊木马,攻击者决定使用多个基于 HTTP 和命名管道。显然,除了事件日志之外,攻击者还痴迷于内存注入,许多 RAT 命令与它相关并且被大量使用。除了上述自定义模块和技术外,攻击者还使用了一些商业渗透测试工具,如 Cobalt Strike 和 SilentBreak 的工具集。
感染链
研究人员从内存中的最后一个stager开始研究,然后使用遥测技术,重建了几个感染链,该活动的针对性很强,且使用的大量工具还包括商业工具。
该活动包括各种技术和模块,让我们把它分成几类来从技术上描述这个活动,比如商业渗透测试套件、围绕它们的自定义反检测包装器和最后stager的木马。
商业工具集有:
反检测包装器——大量使用系统调用库的Go 解密器,这可以使Cobalt Strike 模块多次编码,并使用 AES256 CBC 加密 blob,这是首次观察到 拥有Cobalt Strike 的Go的使用情况。
反检测包装器——一个库启动器,在 MinGW 环境下使用 GCC 编译。这个stager唯一可能的原因是反检测。
反检测包装器——AES 解密器,使用 Visual Studio 编译器编译;
最后stager RAT—— 基于 HTTP 的木马,可能的原始名称是 ThrowbackDLL.dll 和 drxDLL.dll,但代码比 SilentBreak 的 Throwback 的旧版本更复杂。
最后stager RAT—— 基于管道的命名木马,可能的原始名称是 monolithDLL.dll 和 SlingshotDLL.dll。根据文件名,最后stager模块可能是商业 Slingshot 版本的一部分。
同样,我们认为定制的一些模块(如包装器和最后stager)可能是商业产品的一部分。分类之后,我们准备一个一个地分析模块。
初始感染
我们观察到的最早攻击stager发生在 2021 年 9 月。Cobalt Strike 模块的传播是通过说服目标下载合法站点 file.io 上的 .rar 链接并自行运行来实现的。内部 Cobalt Strike 模块的数字证书如下(在使用相同的活动期间,从 wrapper 到 last stagers 签署了 15 个不同的 stager):
由于所有目标主机的感染情况不同,我们将仅描述观察到的一种情况。由于能够使用木马将代码注入任何进程,攻击者可以自由地广泛使用此功能将下一个模块注入 Windows 系统进程或受信任的应用程序(如 DLP)。
记住截断的进程注入,甚至模仿 Web 域注册,我们可以将攻击过程描述为非常迭代(quite iterative):对一些模块进行初始侦察,然后准备额外的攻击。
商业工具集
关于商业工具,这次活动中使用 SilentBreak 和 Cobalt Strike 工具集的痕迹非常明显。名为 ThrowbackDLL.dll 和 SlingshotDLL.dll 的木马让我们想起 Throwback 和 Slingshot,它们都是 SilentBreak 框架中的工具,而与 dropper (sb.dll) 关联的“sb”可能是供应商名称的缩写。
这里我们要提一下,二进制文件中的几个 .pdb 路径包含项目的目录 C:\Users\admin\source\repos\drx\ 以及其他未以 Throwback 或 Slingshot 命名的模块,例如 drxDLL.dll。但是,加密函数与公开可用的 Throwback 代码中的相同。
反检测设计
对于反检测包装器,使用了不同的编译器。除了 MSVC,Go 编译器 1.17.2 和 MinGW 下的 GCC 都在使用。解密器差异很大,它们包含的功能如下表所示:
几个编译器——可以使用 Go 和 C++ 模块完成相同的 AES256 CBC 解密;
列入白名单的启动器——WerFault.exe 的自动运行副本将启动器映射到进程地址空间;
数字证书 ——15 个文件使用“Fast Invest” 证书签名,我们没有观察到任何用它签名的合法文件
修复 ntdll.dll 的日志记录导出——为了更加隐蔽,Go dropper 将与日志记录相关的 API 函数(如 EtwEventWriteFull)修复到具有空功能的自地址空间中;
在事件日志中保留 shellcode——这是攻击者的主要创新,使用 next stager 加密的 shellcode 被分成 8 KB 的block并保存在事件日志的二进制部分中;
C2 网络域名模仿——攻击者在使用标题中,注册了一个ERP网络域名;
这层感染链解密、映射到内存并启动代码。本文我们将仅介绍 Cobalt Strike 的 Go 解密启动器。
主包中的函数名称被混淆了,Main.init 从与事件日志创建相关的 kernel32.dll 和 ntdll.dll 库(WriteProcessMemory 和其他函数)中解码 Windows API 函数名称。二进制文件中的每个名称都连续四次使用 base64 编码。使用 WriteProcessMemory,拥有“xor rax, rax; ret”的dropper在内存中编码以下函数:EtwNotificationRegister、EtwEventRegister、EtwEventWriteFull、EtwEventWriteFull、EtwEventWrite。
在 Main.start 中,恶意软件会检查主机是否在域中,并且只有在它为真时才起作用。然后动态解析上述函数的地址。下一个stager使用 AES256(CBC 模式)加密,密钥和 IV 使用 base64 编码。
使用这种方法,研究人员需要编写一些脚本来收集下一个模块的加密部分。解密后,要获得最终的可移植可执行文件,还需进一步转换数据。
最后stager类型
Last stager 有两种通信机制——使用RC4加密的HTTP通信机制和使用命名管道的非加密通信机制。后一种方式在技术上能够与任何网络可见的外部主机通信,但在Windows环境中,命名管道是建立在SMB协议之上的,它几乎不会对外部网络开放。所以这些模块很可能用于横向移动。
在对恶意软件集进行了介绍之后,我们现在将描述感染链,研究人员使用 Cobalt Strike 渗透测试套件进行Dropper注入。
用DLL中的Dropper实现order劫持
研究人员从 wrapper-dropper 动态库开始自定义模块分析。此代码被注入到诸如 explorer.exe 之类的 Windows 进程中。在加载到启动程序进程的虚拟地址空间后,在其单个入口点,dropper 删除由先前stager或执行创建的文件。
首先,该模块将原始合法的操作系统错误处理程序 WerFault.exe 复制到 C:\Windows\Tasks。然后,它将一个加密的二进制资源放置到同一目录中的wer.dll文件中,以进行典型的DLL order劫持。为了持久化,该模块将新创建的WerFault.exe设置为自动运行,在Software Microsoft\Windows\CurrentVersion\Run Windows系统注册分支中创建一个Windows问题报告值。
dropper 不仅将启动器放在磁盘上进行侧载,而且还会将带有 shellcode 的信息消息写入现有的 Windows KMS 事件日志。
被删除的wer.dll是一个加载器,如果没有隐藏在Windows事件日志中的shellcode,它不会造成任何伤害。dropper在事件日志中搜索类别为 0x4142(ASCII 中的“AB”)并以密钥管理服务作为源的记录。如果没有找到,则通过 ReportEvent() Windows API 函数(lpRawData 参数)将 8KB 的 shellcode 块写入信息记录消息。从 1423 开始,创建的事件 ID 会自动递增。
wer.dll 中的启动器
这个启动器,被第一个stager放到 Tasks 目录中,它代理所有对wer.dll的调用,并将其导出到原始合法库。在入口点,一个单独的线程将所有上述 8KB 片段组合成一个完整的 shellcode 并运行它。由合法 WerFault.exe 的副本创建的相同虚拟地址空间用于所有这些代码。
为了防止 WerFault 继续其错误处理过程,DLL 使用典型的 Blackbone trampoline修复启动器的入口点
阻止合法启动器执行的方法很新颖。在主线程中,wer.dll 找到它的入口点并用一个简单的函数对其进行修复。上面屏幕截图中的 WaitAndExit() 只会使用日志收集线程 ID 调用 WaitForSingleObject() ,然后退出,这意味着永远不会执行真正的 WerFault.exe 错误处理代码:映射到其地址空间的欺骗性 DLL 会阻止它。
Windows 事件日志中的Shellcode
启动器将控制传输到收集的 shellcode 的第一个字节。在本文中,研究人员为下一个函数准备了三个参数:
下一个stager木马的地址,它也包含在从事件日志中提取的数据中;
导出函数名称的标准 ROR13 哈希在此木马中加载 (0xE124D840);
字符串“dave”和常量“4”的地址,它们成为导出函数的参数,可以通过哈希找到;
解析下一个 Windows 可移植可执行文件以定位其入口点的做法是非常典型的。为了让下一个stager的木马不那么显眼,攻击者清除了标题中的“MZ”魔法。在木马的入口点调用代码后,shellcode 还会搜索请求导出并调用它。
除了搜索入口点并调用它,shellcode 还通过硬编码哈希搜索木马导出,并使用参数“dave”和“4”运行找到的函数
HTTP木马
相比之前的辅助模块,对于最后一个stager,我们会介绍的更详细一些。 C++ 模块显然使用了 SilentBreak(现为 NetSPI)的 Throwback 公共存储库中的代码:基于 XOR 的加密函数,一些示例的原始文件名,例如 ThrowbackDLL.dll 等。让我们从前面提到的Load()导出函数开始。这就像上面的WerFault补丁(函数在主木马线程上等待),但是它忽略了任何参数,所以“dave”和“4”没有被使用。这个启动器可能支持比这个更多的模块。
目标搜索
该模块使用单字节 XOR 密钥解密 C2 域,在此示例中,只有一个域 eleed[.]online。该木马能够处理其中的许多,以“|”字符分隔并加密。为了进一步通过普通HTTP进行通信,木马从用户代理“Mozilla 5.0”的集合中随机选择一个C2。
该恶意软件通过收集以下信息生成一个追踪字符串,也用“|”分隔:
1.SOFTWARE\Microsoft\Cryptography 中 MachineGUID 的值;
2.计算机名称;
3.使用 GetAdaptersInfo 获取的本地 IP 地址;
4.架构(x86 或 x64);
5.操作系统版本;
6.当前进程是否有SeDebugPrivilege;
追踪识别器还将“1.1”附加到字符串(可能是恶意软件版本)和当前配置的睡眠时间。
与C2进行加密的HTTP通信
在HTTP通信之前,该模块使用硬编码的32字节长的RC4密钥发送空(但仍然加密)的ICMP数据包来检查连接。与任何其他字符串一样,此密钥使用基于Throwback xor的算法加密。
如果ping端口为80的控制服务器成功,则将上述追踪数据发送到该控制服务器。作为回应,C2共享木马主循环的加密命令。
木马命令
代码的命令功能
0——再次对目标进行追踪识别;
1——执行命令,木马在新进程中执行接收到的命令并将结果发送回C2;
2——从 URL 下载并保存到给定路径;
3——设置新的睡眠时间,如果 C2 尚未响应要执行的命令,则将此时间(以分钟为单位)用作超时。随机化公式为(0,9 - 1,1之间的随机数)*睡眠时间;
4——在不改变配置的情况下休眠指定的分钟数。
5——列出具有 PID、路径、所有者、名称和父数据的进程;
6——将 shellcode 注入并运行到目标进程的地址空间。要注入同一个进程,命令参数应该是“local”。与事件日志中的 shellcode 一样,该代码将运行提供的 PE 的入口点以及通过哈希找到的特定导出。
99——终止木马和C2之间的会话。
本次活动中使用的另一个木马是基于管道命名的,这样命令系统更有意义,包括特权升级、截图、非活动时间测量等。继续使用另一种最后stager的木马类型,发现它被注入到了像edge.exe这样的进程中。
基于管道命名的木马
木马的位置是 C:\Windows\apds.dll,具有相同名称的原始合法 Microsoft 帮助数据服务模块库位于 C:\Windows\System32 中。木马的主要工作周期是在一个单独的线程。该恶意软件还导出一个Load()函数,其唯一目的是等待一个工作线程,这是该活动的模块的典型。
首先,木马主线程获取原始apds.dll并导出,并将其保存到内存中木马映像之后的一个已分配的新堆缓冲区中。然后,木马会编辑自己导出的函数数据,这样它就可以通过如下精心制作的存根调用原始的apds.dll导出,其中的地址就是从真正的apds.dll解析出来的地址:
这个trampoline代码取自Blackbone Windows内存黑客库(remotemmemory::BuildTrampoline函数)。DLL劫持并不是什么新鲜事,我们已经多次看到这种技术被用于代理合法函数,但仅用短存根重新创建自导出来调用原始合法函数却很不寻常。然后,该模块创建一个双工命名的管道“MonolithPipe”,并进入它的主循环。
工作周期
在对导出函数进行上述操作后,该模块会轻微地使用架构和 Windows 版本信息对主机进行追踪识别。木马还使用提到的稀有常量初始化一个随机的 11 字节 ASCII 字符串,例如这里的 init_keys 函数。结果用作唯一的会话 ID。
恶意软件连接到端口 443 上的硬编码域(在本例中为 https://opswat[.]info:443),并向 C2 端的 submit.php 发送 POST 请求。 HTTPS 连接选项设置为接受服务器端的自签名证书。在本例中,C2通信使用Dhga(81K1!392-!(43<KakjaiPA8$#ja密钥的RC4算法加密。对于基于管道命名的木马,常用的命令有:
0——将“continue”标志设置为 False 并停止工作;
1—— N/A,保留至今;
2——获取自上次用户输入以来的时间(以分钟为单位);
3——获取当前进程信息:PID、架构、用户、路径等;
4——获取主机域和用户帐户;
5——使用提供的凭据模拟用户;
6——获取当前进程的可用权限;
7——使用 cmd.exe 解释器执行命令;
8——使用与给定主机(地址和端口)的原始 TCP 套接字测试的连接;
9——获取正在运行的进程信息:路径、所有者、名称、父进程、PID等;
10——使用提供的 ID 的进程令牌模拟用户;
11——列出目录中的文件;
12——截取屏幕截图;
13——将内容写入文件;
14——读取文件内容;
15——删除文件;
16——将提供的代码注入到具有给定名称的进程中。
17——在C2上运行shellcode;
研究人员现在已经介绍了该活动的三个层面,有趣的是,研究人员观察到一个木马具有如上表所示的完整命令集,但仍然使用rc4加密的HTTP与C2通信,而不是指定管道。最后一个stager的示例看起来像一个模块化的平台,攻击者能够根据他们当前的需要组合其功能。
基础设施
研究人员认为这些代码是自定义的(木马、包装器),与以前已知的活动或以前注册的SilentBreak工具集模块没有相似之处。现在研究人员不愿意给这个活动命名,而是坚持只用“SilentBreak”。
本文翻译自:https://securelist.com/a-new-secret-stash-for-fileless-malware/106393/如若转载,请注明原文地址