CobaltStrike beacons 中的挖矿数据
英文原文:https://research.nccgroup.com/2022/03/25/mining-data-from-cobalt-strike-beacons/自从我们在三年前发布了关于在野外识别 Cobalt Strike 团队服务器的信息以来,已经从超过 24,000 个活跃的团队服务器中收集了超过 128,000 个 beacons。今天,RIFT 将这个广泛的 beacon 数据集与 dissect.cobaltstrike 的开源版本一起公开发布,dissect.cobaltstrike 是我们用于研究和解析 Cobalt Strike 相关数据的 Python 库。
发布的数据集包含从 2018 年到 2022 年的历史 beacon 元数据。本篇文章将重点介绍一些有趣的发现,你可以从这个广泛的数据集中提取和查询。我们鼓励其他研究人员也探索数据集并与社区分享令人兴奋的结果。
CobaltStrike 数据集
beacons.jsonl.gz 数据集是一个 GZIP 压缩文件,其中包含 128,340 行作为 JSON 行的 beacon 元数据。可以从以下存储库下载它,并随附 Jupyter notebook:
[*]https://github.com/fox-it/cobaltstrike-beacon-data
该数据集涵盖了从 2018 年 7 月到 2022 年 2 月近四年的 CobaltStrike beacon 历史元数据。不幸的是,由于存档问题,我们在 2019 年丢失了五个月的数据。此外,该数据集主要关注从 HTTP 80、443 端口和 DNS 上的活动 Team Server 收集的 x86 beacon;因此,它不包含来自其他来源的任何 beacon,例如 VirusTotal。
由于大小,beacon payload 本身不在数据集中。相反,会存储不同的 beacon 配置设置,包括其他元数据,例如:
[*]收集 beacon 的日期以及来自哪个 IP 地址和端口
[*]GeoIP + ASN 元数据
[*]DER 格式的 TLS 证书
[*]PE 信息 (timestamps、magic_mz、magic_pe、stage_prepend、stage_append)
[*]如果 payload 是 XOR 编码的,以及哪个 XOR 密钥用于配置混淆
[*]原始 beacon 配置字节;如果想手动解析 beacon 配置,则很方便 (例如,使用 dissect.cobaltstrike 或其他选择的解析器)
虽然有一些简单的方法可以从 beacon payload 中识别破解/盗版的 Cobalt Strike Team 服务器,但很难分辨出那些不同寻常的方法。因此,数据集是未经过滤的、完全公开的,并且包含我们收集的所有 beacon。
当然,正确隐藏或禁用 payload 分段的 Cobalt Strike 团队服务器不包括在内。这意味着拥有良好 OPSEC 的红队无需担心出现在此数据集中。
去哪找 beacons
CobaltStrike beacons 是通过首先识别 Internet 上的团队服务器,然后使用 checksum8 HTTP 请求下载 beacon 来获取的。这种方法类似于 CobaltStrike 的公司在 2019 年进行自己的 Cobalt Strike Team Server Population Study。
虽然我们用于识别的 anomalous space 指纹已经修复,但我们找到了其他可靠的方法来识别团队服务器。此外,我们确信 CobaltStrike 的原作者故意在其中留下了一些指标来帮助蓝队。为此,我们心存感激,并希望这在未来不会改变。
通过蜜罐,可以看出 RIFT 在 beacon 挖矿方面并不是孤立的。现在每个人都在这样做。关于如何找到 CobaltStrike 的博客文章和示例脚本的增加可能归因于这一点,当然,除了 CobaltStrike 本身的日益普及。
CobaltStrike 增强扫描的发展令人着迷,包括用于识别团队服务器和检索 beacon 的不同技术方法。有些甚至跳过了识别部分,直接去请求 beacon!正如你可以想象的那样,这可能很嘈杂,对于某些攻击者来说肯定不会被忽视。
如果你运行面向公众的 Web 服务器,可以通过检查 HTTP 访问日志中的常见 checksum8 等请求轻松验证这种增加的扫描,例如,使用以下 grep 命令:
$ zgrep -hE "GET /{4} HTTP" /var/log/nginx/*.gz
172.x.x.x - - "GET /0bef HTTP/1.0” 404 162 "-" "-"
172.x.x.x - - "GET /0bef HTTP/1.0” 404 162 "-" "-"
139.x.x.x - - "GET /bag2 HTTP/1.1” 404 193 "-" "-"
134.x.x.x - - "GET /ab2g HTTP/1.1” 400 166 "-" "-"
134.x.x.x - - "GET /ab2h HTTP/1.1” 400 166 "-" "-"
上面显示的请求是 checksum8 请求 (用于 x86 和 x64 beacon),在 2021 年 2 月访问托管真实网站的普通网络服务器。
你还可以使用我们的 checksum8-accesslogs.py 脚本,它在一个脚本中完成所有这些事情,并且通过验证 checksum8 值更准确。还可以输出统计信息。这是一个输出 x86 和 x64 beacon HTTP 请求命中我们的一个蜜罐并生成统计信息的示例:
在输出中,你还可以看到正在使用的不同 beacon 扫描技术,我们将把它作为练习留给读者来了解。
通过绘制统计数据,我们可以看到我们的一个蜜罐上的 beacon 扫描明显增加:
因此,如果想知道为什么人们在你的 Web 服务器上请求这些奇怪的四字符 URL (或其他看起来很奇怪的 URL),请检查请求的 checksum8 值,你可能会得到答案。
我们试图更加隐秘一点,并且不会透露我们的指纹识别技术,因为我们也知道攻击者很警惕,从长远来看,这将使每个人都更难处理威胁情报。
使用的 CobaltStrike 版本
因为我们拥有多年的 beacon 元数据,我们可以很好地描绘 Internet 上活跃的 CobaltStrike 服务器以及它们当时使用的版本。
为了提取 CobaltStrike 版本数据,我们使用了以下两种方法:
[*]使用 beacon 设置常量
[*]当引入新的 CobaltStrike beacon 配置设置时,设置常量会增加然后分配。可以根据提取的 beacon 配置中的最高可用常量来推断版本。
[*]使用 PE 中的导出时间戳
[*]黑莓在他们的《在黑暗中寻找 beacon:网络威胁情报指南》一书中也记录了这一点,这是确定确切版本的更准确方法。
我们的 Python 库 dissect.cobaltstrike 支持两种推导版本号的方法,并在可用时支持 PE 导出时间戳。
为方便起见,数据集已经包含 beacon_version 字段,并且基于 PE 导出时间戳。使用此字段,我们可以生成以下图表,显示 Internet 上使用的不同 CobaltStrike 版本随时间的变化:
我们可以看到,在 2021 年 4 月,在线 CobaltStrike 服务器和独特的 beacon 出现了相当显着的高峰,但我们不确定是什么原因造成的,除了当月修改过的 (可能是恶意的) beacon 增加了 3%。
以下百分比图表更清晰地显示了不同版本之间的采用和流行度:
可以看到,CobaltStrike 4.0 (2019 年 12 月发布) 在 2020 年 1 月至 2021 年 1 月期间仍然很受欢迎。
beacon 标记统计
自 Cobalt Strike 3.10 (2017 年 12 月发布) 以来,beacon 包含一个名为 SETTING_WATERMARK 的设置。这个标记值在每个 CobaltStrike 安装中应该是唯一的,因为许可证服务器会发布它。
但是,破解/盗版版本通常会将其修补为固定值,从而可以轻松识别哪些 beacon 更有可能是恶意的 (即不是渗透测试人员)。这种可能性与我们迄今为止的事件响应活动相一致,其中与妥协相关的 beacon 使用了已知的不良标记。
请注意,恶意行为者很难申请试用或购买 CobaltStrike 的合法副本,因为每个用户都经过审查和筛选。由于这些措施,在暗网上购买 CobaltStrike 副本的要价很高。例如,Conti 投资 60.000 美元购买了一份 CobaltStrike 的有效副本。
如果你在这前 50 个中发现带有特殊标志的 beacon,那么它很可能是恶意的!
自定义 beacon
在解析收集到的 beacon 时,我们发现一些 beacon 被修改了,例如,使用自定义 shellcode stub、非默认 XOR 键或重新分配的 beacon 设置。
因此,具有大量自定义的 beacon 无法正确转储并且不包含在数据集中。
beacon payload 中的配置块通常使用单字节 XOR 密钥进行混淆。根据 CobaltStrike 版本,默认键是 0x2e 或 0x69。
使用非默认 XOR 键需要用户修改 beacon 和/或团队服务器,因为默认情况下不可配置。 以下是在唯一 beacon 数据集上看到的 XOR 键的概述:
虽然使用自定义 XOR 密钥会使其成为异常值,但它确实可以保护其免受一些现有的 CobaltStrike 配置转储程序的影响。我们的 Python 库 dissect.cobaltstrike 支持在默认 XOR 键不起作用时尝试所有 XOR 键。例如,可以将命令行标志 --all-xor-keys 传递给 beacon-dump 命令。
PE
虽然大多数现有的 CobaltStrike 转储程序都专注于 beacon 设置,但 Malleable C2 配置文件中的一些设置不会最终出现在 payload 的嵌入式 beacon 配置中。 例如,Malleable C2 配置文件中的一些可移植可执行文件 (PE) 设置直接应用于 beacon payload。我们的 Python 库 dissect.cobaltstrike 支持提取此信息,我们的数据集包括以下提取的 PE 标头元数据:
[*]magic_mz — MZ header
[*]magic_pe — PE header
[*]pe_compile_stamp — PE compilation stamp
[*]pe_export_stamp — timestamp of the export section
[*]stage_prepend – (shellcode) bytes prepended to the start of the beacon payload
[*]stage_append — bytes appended to the end of the beacon payload
我们对最常见的 stage_prepend 字节进行了概述,这些字节都是 ASCII 字节。 这些字节位于 MZ 标头前面,并且必须是有效的汇编代码,但在作为 shellcode 执行时会导致无操作。 有些很有创意:
如果我们反汇编示例 stage_prepend shellcode JFIFJFIF,可以看到它增加了 ESI 并减少了 EDX 寄存器并因此对其进行了修改;所以它不完全是一个无操作的 shellcode,但它很可能也不会影响暂存过程。
$ echo -n JFIFJFIF | ndisasm -b 32 /dev/stdin
000000004A dec edx
0000000146 inc esi
0000000249 dec ecx
0000000346 inc esi
000000044A dec edx
0000000546 inc esi
0000000649 dec ecx
0000000746 inc esi
可以查看我们的 Jupyter notepad,了解其他 PE 工件的概述,例如 magic_mz 和 magic_pe。
使用空格标记 releasenotes.txt
CobaltStrike 的作者一定很喜欢空格,在 HTTP 服务器标头中的错误空格之后,现在还有一个名为 SETTING_SPAWNTO 的 (重新调整用途的) beacon 设置,现在填充了 releasenotes.txt 的 MD5 哈希 (或意外地另一个如果匹配相同的 checksum8 值 152 和文件名长度,则在同一目录中的文件)。
当激活或更新 CobaltStrike 服务器时,releasenotes.txt 会自动从许可证服务器下载。令我们惊讶的是,我们发现这个文件很可能是使用空白字符标记的,从而使这个文件和 MD5 散列在每次安装时都是唯一的。许可证服务器可能会跟踪所有这些唯一生成的文件,以帮助打击盗版和 CobaltStrike 的泄漏。
虽然这非常聪明,但我们发现在一些盗版 beacon 中,该字段全为零,或者不可用。这意味着他们知道这个文件,并决定不在盗版版本中发布它,否则字段值已被修补。尽管如此,当可用时,该字段仍可用于搜索或关联 beacon。
用 dissect.cobaltstrike 分析 beacon payload
我们也很自豪地开源了用于剖析 CobaltStrike 的 Python 库,命名为 dissect.cobaltstrike。 该库在 PyPI 上可用,需要 Python 3.6 或更高版本。 你可以使用 pip 来安装它:
$ pip install dissect.cobaltstrike
项目的 GitHub 存储库:https://github.com/fox-it/dissect.cobaltstrike
为了方便,它目前安装了三个命令行工具:
[*]beacon-dump – 用于从 beacon payload 转储配置 (也适用于内存转储)
[*]beacon-xordecode – 用于解码异编码 payload 的独立工具
[*]c2profile-dump – 使用它来读取和解析 Malleable C2 配置文件
beacon 转储的一个简洁功能是将 beacon 配置转储回来,因为它是与可扩展 C2 配置文件兼容的等效项:
虽然这些命令行工具提供了使用 Beacon payload 的大部分样板,但也可以将库导入脚本或 notebook 中以用于更高级的用例。有关一些示例,请参阅我们的 notebook 和文档。
思考
beacon 数据集已被证明对我们非常有用,尤其是数据集的历史方面在事件响应参与期间很有洞察力。我们每天使用数据集,范围从 C2 基础设施映射、参与者跟踪、威胁追踪、高质量指标、检测工程等等。
我们希望这个数据集和 Python 库能像对我们一样对社区有所帮助,并渴望看到人们使用这些数据和工具会想出或发现什么样的令人兴奋的事情。我们在本篇文章中展示的内容只是你可以从 beacon 数据中发现的冰山一角。
给读者的一些想法:
[*]使用 DBSCAN 等聚类算法对 beacon 和 C2 配置文件特征进行聚类
[*]改进恶意 beacon 的分类。 可以在我们的 notebook 中找到当前的分类方法
[*]使用 GeoIP ASN 数据确定最恶意 beacon 的托管位置
[*]分析 x509 证书数据,例如是否自签名
[*]确定 beacon 是否使用域前端以及哪个 CDN
这篇文章中显示的所有统计信息也可以在我们随附的 Jupyter notebook 中找到,包括本篇文章中未显示的更多统计信息和概述。
我们还要感谢 Rapid7 提供的开放数据集,如果没有这些数据,beacon 数据集的完整性就会大大降低!
为方便起见,最终链接:
[*]Beacon dataset and notebook – https://github.com/fox-it/cobaltstrike-beacon-data
[*]dissect.cobaltstrike Python library – https://github.com/fox-it/dissect.cobaltstrike
[*]dissect.cobaltstrike Documentation – https://dissect-cobaltstrike.readthedocs.io
页:
[1]