NVISO Labs - Cobalt Strike解密系列

【收集翻译】NVISO Labs

Cobalt Strike: Decrypting Obfuscated Traffic – Part 4

加密的 Cobalt Strike C2 流量可以通过可延展的 C2 数据转换进行混淆。我们展示了如何对此类流量进行反混淆。
本系列博文描述了解密 Cobalt Strike 流量的不同方法。在本系列的第 1 部分中,我们揭示了在流氓 Cobalt Strike 软件包中发现的私有加密密钥。在第 2 部分中,我们从一个私有 RSA 密钥开始解密 Cobalt Strike 流量。在第 3 部分中,我们将解释如果您不知道私有 RSA 密钥但确实有进程内存转储,如何解密 Cobalt Strike 流量。
在本系列的前 3 部分中,我们一直关注包含未更改的加密数据的流量:查询返回的数据和发布的数据只是加密数据。
使用可延展的 C2 数据转换,可以将这些加密数据转换为看起来更良性的流量。在我们将在这篇博文中看到的示例中,加密数据隐藏在 JavaScript 代码中。
但是我们如何知道Beacon是否正在使用此类指令来混淆流量?这可以在🛠️最新版工具 1768.py🛠️的分析结果中看到。让我们来看看我们在第 1 部分中开始的Beacon的配置:
image.png
图 1:带有默认可延展 C2 指令的Beacon
我们看到字段 0x000b(可延展的 C2 指令)只有一条指令:“Print”。这是默认设置,这意味着Beacon按原样接收加密数据:在解密之前不需要任何转换。
对于字段 0x000d(http 帖子标头),我们看到构建输出也只是一条指令:“Print”。这是默认设置,这意味着加密数据由Beacon按原样传输:加密后不需要任何转换。
让我们看一个带有自定义可延展 C2 数据转换的示例:
image.png
图 2:带有自定义可延展 C2 指令的Beacon
在这里,我们看到的不仅仅是一条打印指令:“从末尾删除 1522 个字节”、“从开头删除 84 个字节”,……
这些是转换(去混淆)传入流量的指令,以便随后可以对其进行解密。
为了详细了解这是如何工作的,我们将使用CyberChef手动进行转换。但是,要知道🛠️工具cs-parse-http-traffic.py🛠️可以自动执行这些转换。
这是Beacon对单个 GET 请求的网络捕获以及来自团队服务器 (C2) 的回复:
image.png
图 3:使用可延展的 C2 指令转换的回复看起来像 JavaScript 代码
我们在这里看到的是Beacon对 C2 的 GET 请求(注意带有加密元数据的 Cookie)和 C2 的回复。此回复看起来像 JavaScript 代码,因为使用了可延展的 C2 数据转换使其看起来像 JavaScript 代码。
我们将此回复复制到 CyberChef 的输入字段中:
image.png
图 4:具有混淆输入的 CyberChef
🛠️工具 1768.py🛠️的输出中列出了我们需要遵循的说明,以对该回复进行反混淆:
image.png
图5:解码指令
首先,我们需要从回复的末尾删除 1522 个字节。这可以通过 CyberChef 丢弃字节函数和负长度(负长度意味着从末尾丢弃)来完成:
image.png
图 6:从末尾丢弃 1522 个字节
然后,我们需要从回复的开头删除 84 个字节:
image.png
图 7:从头开始丢弃 84 个字节
然后从头开始删除 3931 个字节:
image.png
图 8:从头开始丢弃 3931 个字节
现在我们最终得到看起来像 BASE64 编码数据的输出。实际上,下一条指令是应用 BASE64 解码指令(准确地说:URL 的 BASE64 编码):
image.png
图 9:解码 BASE64/URL 数据
下一条指令是对数据进行异或。为此,我们需要 XOR 密钥。XOR 的可延展 C2 指令使用 4 字节长的随机密钥,该密钥附加到 XOR 数据。所以为了恢复这个密钥,我们将二进制输出转换为十六进制:
image.png
图 10:转换数据的十六进制表示
前 4 个字节是 XOR 密钥:b7 85 71 17
我们将它与 CyberChef 的 XOR 命令一起使用:(怎么不给个链接,链接可以保留输入参数+解码选项的)
image.png
图 11:异或数据
请注意,前 4 个字节现在是 NULL 字节:正如预期的那样,对字节与自身进行异或会给出 NULL 字节。
最后,我们删除这 4 个 NULL 字节:
image.png
图 12:完全转换的数据
我们最终得到的是包含要由Beacon执行的 C2 命令的加密数据。这是通过遵循可延展的 C2 数据转换对数据进行反混淆的结果。现在我们可以使用进程内存转储继续解密,就像我们在第 3 部分中所做的那样。
image.png
图 13:从进程内存中提取加密密钥
🛠️工具cs-extract-key.py🛠️用于从进程内存中提取 AES 和 HMAC 密钥:它失败,无法在进程内存中找到密钥。
无法找到密钥的一种可能解释是进程内存已编码。Cobalt Strike 支持Beacon功能,称为睡眠掩码。启用此功能后,具有Beacon数据(包括密钥)的进程内存在Beacon休眠时进行 XOR 编码。因此,只有当Beacon处于活动状态(通信或执行命令)时,其数据才会以明文形式存在
我们可以尝试解码这个进程内存转储。🛠️工具cs-analyze-processdump.py🛠️是一种尝试解码具有活动睡眠掩码功能的Beacon的进程内存转储的工具。让我们在我们的进程内存转储上运行它:
image.png
图 14:分析进程内存转储(截图 1)
image.png
图 15:分析进程内存转储(截图 2)
该工具确实找到了一个 13 字节长的 XOR 密钥,并将解码后的部分作为扩展名为 .bin 的文件写入磁盘。
此文件现在可以与🛠️cs-extract-key.py🛠️一起使用,它与之前的命令完全相同,但使用解码部分而不是编码的 .dmp 文件:
image.png
图 16:从解码部分提取密钥
现在我们已经恢复了加密密钥。
请注意,在图 16 中,该工具报告了查找字符串 sha256\x00,而在第一个命令(图 13)中,未找到该字符串。缺少此字符串通常表明Beacon使用睡眠掩码,并且在提取密钥之前应使用该工具 cs-analyze-processdump.py。
现在我们有了密钥,我们可以使用🛠️工具cs-parse-http-traffic.py🛠️解密网络流量:
image.png
图17:解密流量失败
这失败了:原因是可延展的 C2 数据转换。🛠️工具 cs-parse-http-traffic.py🛠️需要知道在解密之前应用哪些指令来对流量进行反混淆。就像我们手动使用 CyberChef 所做的一样,工具 cs-parse-http-traffic.py 需要自动执行此操作。这可以通过选项 -t 来完成。
请注意,🛠️工具 1768.py🛠️的输出包含要执行的指令的简写符号(在方括号之间):
image.png
图 18:Malleable C2 指令的简写符号
对于要执行的任务(输入),它是:

  1. 7:Input,4,1:1522,2:84,2:3931,13,15

对于要发布的结果(输出),它是:

  1. 7:Output,15,13,4

这些指令可以放在一起(使用分号作为分隔符)并通过选项 -t 提供给🛠️工具 cs-parse-http-traffic.py🛠️:
image.png
图 19:解密流量
现在我们终于获得了解密流量。在此流量中没有实际命令,只是“数据抖动”:即随机长度的随机数据,旨在更加混淆流量。

结论

我们看到了Malleable C2 数据转换如何用于混淆网络流量,以及我们如何按照说明对这种网络流量进行反混淆。
我们用 CyberChef 手动完成了这项工作,但这当然不切实际(我们这样做是为了说明这个概念)。要获取解码后的加密命令,我们还可以使用🛠️cs-parse-http-traffic.py🛠️。就像我们在第 3 部分中所做的那样,我们从一个未知的密钥开始,我们也在这里这样做。唯一不同的是,我们还需要提供解码指令:
image.png
图 20:提取和解码加密数据
然后我们可以使用这 3 个加密数据之一来恢复密钥。
因此,该过程与第 3 部分中解释的完全相同,只是必须使用选项 -t 来包含可延展的 C2 数据转换。