加密的 Cobalt Strike C2 流量可通过可塑性 C2 数据转换进行混淆。我们将展示如何对此类流量进行反混淆。
本系列博客文章介绍了解密 Cobalt Strike 流量的不同方法。在本系列的第 1 部分中,我们揭示了在恶意 Cobalt Strike 软件包中发现的私有加密密钥。在第 2 部分中,我们从私有 RSA 密钥开始解密 Cobalt Strike 流量。在第 3 部分中,我们将解释如果您不知道私有 RSA 密钥但有进程内存转储,如何解密 Cobalt Strike 流量。
在本系列的前三部分中,我们一直在研究包含未更改的加密数据的流量:查询返回的数据和发布的数据只是加密数据。
通过使用可塑性 C2 数据转换,这些加密数据可以转换为看起来更无害的流量。在本篇博文中我们将要介绍的示例中,加密数据隐藏在 JavaScript 代码中。
但是我们如何知道信标是否使用此类指令来混淆流量?这可以在最新版本的工具 1768.py 的分析结果中看到。让我们看一下我们在第 1 部分中开始使用的信标的配置:
图 1:带有默认可塑性 C2 指令的信标
我们看到,对于字段 0x000b(可塑性 C2 指令),只有一条指令:打印。这是默认指令,这意味着信标会按原样接收加密数据:解密前不需要进行任何转换。
而对于字段 0x000d(http post header),我们看到 Build Output 也只有一条指令:Print。这是默认的,意味着加密数据由信标按原样传输:加密后不需要任何转换。
让我们看一个具有自定义可延展 C2 数据转换的示例:
图 2:带有自定义可延展 C2 指令的信标
这里我们看到的不仅仅是一条打印指令:“从末尾删除 1522 个字节”,“从开头删除 84 个字节”,...
这些是转换(反混淆)传入流量的指令,以便可以解密。为了详细了解其工作原理,我们将使用CyberChef手动进行转换。但是,请注意工具cs-parse-http-traffic.py可以自动执行这些转换。
这是信标发出的单个 GET 请求和来自团队服务器(C2)的回复的网络捕获:
图 3:回复经过可塑性 C2 指令转换,看起来像 JavaScript 代码
我们在这里看到的是信标向 C2 发出的 GET 请求(请注意带有加密元数据的 Cookie)以及 C2 的回复。此回复看起来像 JavaScript 代码,因为 C2 使用了可塑的数据转换使其看起来像 JavaScript 代码。
我们将此回复复制到 CyberChef 的输入栏中:
图 4:带有混淆输入的 CyberChef
为了消除这个回复的混淆,我们需要遵循的说明列在工具 1768.py 的输出中:
图5:解码指令
那么让我们开始吧。首先,我们需要从回复末尾删除 1522 个字节。这可以使用 CyberChef 删除字节函数和负长度来完成(负长度表示从末尾删除):
图 6:从末尾删除 1522 个字节
然后,我们需要从答复的开头删除 84 个字节:
图 7:从开头删除 84 个字节
然后从头开始删除 3931 字节:
图 8:从开头删除 3931 个字节
现在我们得到的输出看起来像是 BASE64 编码的数据。实际上,下一个指令是应用 BASE64 解码指令(准确地说:对 URL 进行 BASE64 编码):
图9:解码BASE64 / URL数据
下一个指令是对数据进行异或运算。为此,我们需要异或密钥。可塑性 C2 指令用于异或运算,使用 4 字节长的随机密钥,该密钥附加在异或运算数据前面。因此,要恢复此密钥,我们将二进制输出转换为十六进制:
图 10:转换后的数据的十六进制表示
前 4 个字节是 XOR 密钥:b7 85 71 17
我们将其与 CyberChef 的 XOR 命令一起使用:
图 11:异或后的数据
请注意,前 4 个字节现在是 NULL 字节:这是预期的结果,对字节与其自身进行异或运算会产生 NULL 字节。
最后,我们删除这 4 个 NULL 字节:
图 12:完全转换后的数据
我们最终得到的是包含信标要执行的 C2 命令的加密数据。这是通过遵循可塑的 C2 数据转换对数据进行反混淆的结果。现在我们可以使用进程内存转储继续解密,就像我们在第3 部分中所做的那样。
图 13:从进程内存中提取加密密钥
工具cs-extract-key.py用于从进程内存中提取 AES 和 HMAC 密钥:它失败了,无法在进程内存中找到密钥。https://github.com/DidierStevens/Beta/blob/master/cs-extract-key.py
密钥无法找到的一个可能解释是进程内存被加密了。Cobalt Strike 支持信标的一项功能,称为睡眠掩码。启用此功能后,在信标睡眠期间,包含信标数据(包括密钥)的进程内存将进行 XOR 编码。因此,只有当信标处于活动状态(通信或执行命令)时,其数据才会以明文形式显示。
我们可以尝试解码此进程内存转储。工具cs-analyze-processdump.py是一个尝试解码具有活动睡眠掩码功能的信标的进程内存转储的工具。让我们在进程内存转储上运行它:
图14:分析进程内存转储(截图1)
图15:分析进程内存转储(截图2)
该工具确实找到了一个13字节长的XOR密钥,并将解码后的部分作为扩展名为.bin的文件写入磁盘。
该文件现在可以与 cs-extract-key.py 一起使用,它与之前的命令完全相同,但使用解码部分而不是编码的 .dmp 文件:
图 16:从解码部分中提取密钥
现在我们已经恢复了加密密钥。
请注意,在图 16 中,该工具报告找到字符串 sha256x00,而在第一个命令(图 13)中,未找到此字符串。此字符串的缺失通常表明信标使用了睡眠掩码,并且在提取密钥之前应使用工具 cs-analyze-processdump.py。
现在我们有了密钥,我们可以使用工具cs-parse-http-traffic.py解密网络流量:
图 17:解密流量失败
失败:原因是可塑性 C2 数据转换。工具 cs-parse-http-traffic.py 需要知道在解密之前应用哪些指令来对流量进行反混淆。就像我们手动使用 CyberChef 一样,工具 cs-parse-http-traffic.py 需要自动执行此操作。这可以使用选项 -t 来完成。
请注意,工具 1768.py 的输出包含要执行的指令的简写形式(在方括号之间):
图 18:可塑性 C2 指令的简写形式
对于要执行(输入)的任务,它是:
7:输入,4,1:1522,2:84,2:3931,13,15
要发布(输出)的结果如下:
7:输出,15,13,4
可以把这些指令放在一起(使用分号作为分隔符)并通过选项 -t 提供给工具 cs-parse-http-traffic.py:
图19:解密后的流量
现在我们终于获得了解密的流量。此流量中没有实际的命令,只有“数据抖动”:即随机长度的随机数据,旨在进一步混淆流量。
结论
我们了解了如何使用可塑的 C2 数据转换来混淆网络流量,以及如何按照说明对这些网络流量进行反混淆。
我们使用 CyberChef 手动完成了此操作,但这当然不切实际(我们这样做是为了说明这个概念)。要获取解码的加密命令,我们还可以使用 cs-parse-http-traffic.py。就像我们在第 3 部分中所做的那样,我们从一个未知密钥开始,我们在这里也这样做。唯一的区别是我们还需要提供解码说明:
图20:提取并解码加密数据
然后我们可以采取这3个加密数据中的一个来恢复密钥。
因此,该过程与第 3 部分中说明的完全相同,只是必须使用选项 -t 来包含可调整的 C2 数据转换。
原文始发于微信公众号(Ots安全):Cobalt Strike:解密混淆流量 - 第 4 部
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论