Cobalt Strike:解密 DNS 流量 – 第 5 部分

admin 2024年8月5日09:08:57评论40 views字数 5589阅读18分37秒阅读模式

Cobalt Strike 信标可以通过 DNS 进行通信。我们将在这篇博文中展示如何解码和解密 DNS 流量。

本系列博客文章介绍了解密 Cobalt Strike 流量的不同方法。在本系列的第 1 部分中,我们揭示了在恶意 Cobalt Strike 软件包中发现的私有加密密钥。在第 2 部分中,我们从私有 RSA 密钥开始解密 Cobalt Strike 流量。在第 3 部分中,我们将解释如果您不知道私有 RSA 密钥但有进程内存转储,如何解密 Cobalt Strike 流量。在第 4 部分中,我们将处理使用可塑性 C2 数据转换进行混淆的流量。

在本系列的前 4 部分中,我们一直在研究 HTTP(或 HTTPS)上的流量。还可以将信标配置为通过 DNS 进行通信,方法是执行 A、AAAA 和/或 TXT 记录的 DNS 请求。从信标流向团队服务器的数据使用十六进制数字进行编码,这些数字构成了查询名称的标签,而从团队服务器流向信标的数据包含在 A、AAAA 和/或 TXT 记录的答案中。

需要从 DNS 查询中提取数据,然后对其进行解密(使用与 HTTP 上的流量相同的加密方法)。

DNS C2 协议

我们使用 2021 年版网络安全隆隆声中的挑战来说明 Cobalt Strike DNS 流量的样子。

首先我们需要使用工具1768.py查看一下信标配置:https://blog.didierstevens.com/2021/11/21/update-1768-py-version-0-0-10/

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 1:DNS 信标的配置

字段“payload type”确认这是一个 DNS 信标,字段“server”告诉我们用于 DNS 查询的域:wallet[.]thedarkestside[.]org。

然后,图 1 中突出显示了第三块 DNS 配置参数:maxdns、DNS_idle、...当它们出现在我们要分析的 DNS 流量中时,我们将解释它们。

在 Wireshark 中看到,DNS 流量如下所示:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 2:Wireshark 显示的 Cobalt Strike DNS 流量

我们将此信息(字段 Info)浓缩为 DNS 查询和答复的文本表示:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 3:Cobalt Strike DNS 流量的文本表示

让我们从第一组查询开始:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 4:DNS_beacon 查询和回复

信标会定期(由睡眠设置决定)发出名称为 19997cf2[.]wallet[.]thedarkestside[.]org 的 A 记录 DNS 查询。wallet[.]thedarkestside[.]org 是此信标将发出的每个查询的根标签,这在配置中设置。19997cf2 是此特定信标实例的信标 ID(出价)的十六进制表示。每个正在运行的信标都会生成一个 32 位数字,用于通过团队服务器识别信标。每个正在运行的信标都是不同的,即使同一个信标可执行文件启动多次也是如此。对此特定信标的所有 DNS 请求都将具有根标签 19997cf2[.]wallet[.]thedarkestside[.]org。

为了确定上述一组 DNS 查询的目的,我们需要查阅信标的配置:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 5:放大此信标配置的 DNS 设置(图 1)

以下设置定义每种查询类型的顶部标签:

  • DNS_beacon

  • DNS_A

  • DNS_AAAA

  • DNS_TXT

  • DNS_元数据

  • DNS_输出

请注意,图 5 中显示的这些设置的值是 Cobalt Strike 配置文件的默认设置。

例如,如果此信标发出的 DNS 查询的名称以http://www.开头,那么我们就知道这些是将元数据发送到团队服务器的查询。

在我们的信标配置中,DNS_beacon 的值为 (NULL ...):这是一个空字符串,表示在根标签前面没有放置标签。因此,有了这个,我们知道名称为 19997cf2[.]wallet[.]thedarkestside[.]org 的查询是 DNS_beacon 查询。信标使用 DNS_beacon 查询来查询团队服务器是否在其队列中有信标的任务。对此 A 记录 DNS 查询的回复是一个 IPv4 地址,该地址指示信标做什么。要了解指令是什么,我们首先需要将这个回复的地址与设置 DNS_Idle 的值进行异或运算。在我们的信标中,该 DNS_Idle 值为 8.8.4.4(默认 DNS_Idle 值为 0.0.0.0)。

从图 4 中我们可以看到,对第一个请求的回复是 8.8.4.4。这些必须与 DNS_Idle 值 8.8.4.4 进行异或:因此结果为 0.0.0.0。回复等于 0.0.0.0 表示团队服务器队列中没有针对此信标的任务,并且它应该休眠并稍后再次检查。因此,对于图 4 中的前 5 个查询,信标无需执行任何操作。

第 6 次查询时情况发生了变化:答复是 IPv4 地址 8.8.4.246,当我们将该值与 8.8.4.4 进行异或时,我们得到 0.0.0.242。值 0.0.0.242 指示信标使用 TXT 记录查询检查任务。

以下是确定信标如何与团队服务器交互的可能值:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 6:可能的 DNS_Beacon 回复

如果设置了最低有效位,则信标应该进行检查(使用 DNS_metadata 查询)。

如果清除了位 4 至位 2,则应使用 A 记录进行通信。

如果设置了位 2,则应使用 TXT 记录进行通信。

如果设置了位 3,则应使用 AAAA 记录进行通信。

值 242 是 11110010,因此无需执行签到,但应通过 TXT 记录检索任务。

下一组 DNS 查询由信标执行,因为它收到了指令 (0.0.0.242):

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图7:DNS_TXT查询

请注意,这些查询中的名称以 api. 开头,因此根据配置,它们是 DNS_TXT 查询(参见图 5)。这是根据团队服务器 (0.0.0.242) 的指示。

尽管 DNS_TXT 查询应该使用 TXT 记录,但 DNS_TXT 查询的第一个 DNS 查询是 A 记录查询。答复(IPv4 地址)必须与 DNS_Idle 值进行异或运算。因此,在我们的示例中,8.8.4.68 与 8.8.4.4 进行异或运算后得到 0.0.0.64。这指定了将通过 TXT 记录传输的加密数据的长度(64 字节)。请注意,对于 DNS_A 和 DNS_AAAA 查询,第一个查询也将是 A 记录查询。它还会对要接收的加密数据的长度进行编码。

接下来,信标会根据需要发出尽可能多的 TXT 记录查询。每个 TXT 记录的值都是一个 BASE64 字符串,必须在解码之前将它们连接在一起。一旦解码的数据达到 A 记录回复中指定的长度(在我们的示例中为 64 字节),信标就会停止发出 TXT 记录请求。

由于信标可以非常快速地发出这些 TXT 记录查询(取决于休眠设置),因此引入了一种机制来避免缓存的 DNS 结果干扰通信。这是通过使 DNS 查询中的每个名称都唯一来实现的。这是通过额外的十六进制标签来实现的。

请注意,顶部标签(在我们的示例中为 api)和根标签(在我们的示例中为 19997cf2[.]wallet[.]thedarkestside[.]org)之间有一个十六进制标签。对于第一个 DNS 查询,该十六进制标签为 07311917,对于第二个 DNS 查询,该十六进制标签为 17311917。该十六进制标签由一个计数器和一个随机数组成:COUNTER + RANDOMNUMBER。

在我们的示例中,随机数是 7311917,计数器始终从 0 开始并以 1 递增。这就是使每个查询都唯一的方式,并且它还有助于以正确的顺序处理答复,以防 DNS 回复无序到达。

因此,当收到所有 DNS TXT 回复时(在我们的示例中只有一个),将对 base 64 字符串(在我们的示例中为 ZUZBozZmBi10KvISBcqS0nxp32b7h6WxUBw4n70cOLP13eN7PgcnUVOWdO+tDCbeElzdrp0b0N5DIEhB7eQ9Yg==)进行解码和解密(我们将在本博文末尾使用工具来完成此操作)。

这就是 DNS 信标从团队服务器接收指令(任务)的方式。加密字节通过 DNS A、DNS AAAA 或 DNS TXT 记录回复进行传输。

当通信必须通过 DNS A 记录(0.0.0.240 回复)进行时,流量如下所示:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 8:DNS_A查询

cdn. 是 DNS_A 请求的顶部标签(参见配置图 5)。

第一个回复是 8.8.4.116,与 8.8.4.4 进行异或后得到 0.0.0.112。因此必须接收 112 字节的加密数据。即 112 / 4 = 28 个 DNS A 记录回复。

加密数据仅取自 DNS A 记录回复中的 IPv4 地址。在我们的示例中,即:19、64、240、89、241、225……

对于 DNS_AAAA 查询,方法完全相同,只是在我们的示例中顶部标签是 www6.(参见配置图 5),并且每个 IPv6 地址包含 16 个字节的加密数据。

通过 DNS 记录从团队服务器传输到信标(例如任务)的加密数据与通过 http 或 https 传输的加密任务具有完全相同的格式。因此解密过程完全相同。

当信标必须将其结果(任务的输出)传输到团队服务器时,它会使用 DNS_output 查询。在我们的示例中,这些查询以 top 标签 post 开头。以下是示例:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 9:Beacon 使用 DNS_output 查询将结果发送到团队服务器

DNS_output 查询的每个 DNS 查询名称都有一个唯一的十六进制计数器,就像 DNS_A、DNS_AAAA 和 DNS_TXT 查询一样。要传输的数据使用添加到名称的标签中的十六进制数字进行编码。

让我们进行第一个 DNS 查询(图 9):post.140.09842910.19997cf2[.]wallet[.]thedarkestside.org。

该名称可分解为以下标签:

  • post: DNS_output query
  • 140: transmitted data
  • 09842910: counter + random number
  • 19997cf2: beacon ID
  • wallet[.]thedarkestside.org: domain chosen by the operator

第一个查询的传输数据实际上是要传输的加密数据的长度。它必须按如下方式解码:140 -> 1 40。

第一个十六进制数字(在我们的示例中为 1)是一个计数器,它指定用于包含十六进制数据的标签数量。由于 DNS 标签限制为 63 个字符,因此当需要编码 32 个或更多字节时,需要使用多个标签。这解释了计数器的用途。40 是十六进制数据,因此加密数据的长度为 64 字节。

第二个DNS查询(图9)是:

post.2942880f933a45cf2d048b0c14917493df0cd10a0de26ea103d0eb1b3.4adf28c63a97deb5cbe4e20b26902d1ef427957323967835f7d18a42.19842910.19997cf2[.]wallet[.]thedarkestside[.]org。

此查询中的名称包含标签内用十六进制数字编码的加密数据(部分)。

这些是传输的数据标签:

2942880f933a45cf2d048b0c14917493df0cd10a0de26ea103d0eb1b3.4adf28c63a97deb5cbe4e20b26902d1ef427957323967835f7d18a42

第一位数字 2 表示使用了 2 个标签来对加密数据进行编码:

942880f933a45cf2d048b0c14917493df0cd10a0de26ea103d0eb1b3

4adf28c63a97deb5cbe4e20b26902d1ef427957323967835f7d18a42

第三个 DNS 查询(图 9)是:

post.1debfa06ab4786477.29842910.19997cf2[.]wallet[.]thedarkestside[.]org

标签的计数器为 1,传输的数据为 debfa06ab4786477。

将所有这些标签按正确的顺序放在一起,得到以下十六进制数据:

942880f933a45cf2d048b0c14917493df0cd10a0de26ea103d0eb1b34adf28c63a97deb5cbe4e20b26902d1ef427957323967835f7d18a42debfa06ab4786477

其长度为 128 个十六进制数字,或者说 64 个字节,与第一个查询中的长度(40 个十六进制)指定的长度完全相同。

上面的十六进制数据是通过 DNS 记录从信标传输到团队服务器的加密数据(例如,任务结果或输出),其格式与通过 http 或 https 传输的加密输出几乎相同。不同之处在于:对于 http 或 https 流量,格式以未加密的大小字段(加密数据的大小)开头。该大小字段不存在于 DNS_output 数据的格式中。

解密

我们开发了一个工具cs-parse-traffic,它可以解密和解析 DNS 流量和 HTTP(S)。与我们对加密 HTTP 流量所做的操作类似,我们将解码来自 DNS 查询的加密数据,使用它在信标的进程内存中查找加密密钥,然后解密 DNS 流量。

首先,我们使用未知密钥(-k unknown)运行该工具,从捕获文件内的 DNS 查询和答复中提取加密数据:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 10:从 DNS 查询中提取加密数据

选项 -f dns 是处理 DNS 流量所必需的,选项 -i 8.8.4.4. 用于提供 DNS_Idle 值。此值是正确解码 DNS 回复所必需的(DNS 查询不需要此值)。

然后可以使用加密数据(红色矩形)在正在运行的信标的进程内存转储中找到 AES 和 HMAC 密钥:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 11:从进程内存中提取加密密钥

然后可以使用该密钥解密 DNS 流量:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 12:解密 DNS 流量

此流量曾用于Cyber Security Rumble 2021的 CTF 挑战。要找到标志,请在解密的流量中 grep CSR:

Cobalt Strike:解密 DNS 流量 – 第 5 部分

图 13:在解密的流量中找到标志

结论

DNS Cobalt Strike 流量和 HTTP Cobalt Strike 流量之间的主要区别在于加密数据的编码方式。一旦恢复加密数据,DNS 和 HTTP 的解密过程非常相似。

原文始发于微信公众号(Ots安全):Cobalt Strike:解密 DNS 流量 – 第 5 部分

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月5日09:08:57
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Cobalt Strike:解密 DNS 流量 – 第 5 部分https://cn-sec.com/archives/3030924.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息