互联网|对红队利器Cobalt Strike一个历史遗留漏洞的研究


0x01 基本信息
这篇文章介绍了Beacons和3.5系列中的Team Server之间Cobalt Strike的一些通信和加密内部结构 。 然后 , 我们探索了从2016年起对Cobalt Strike 3.5中的漏洞的后续利用 , 以在Team Server上实现远程未经身份验证的代码执行 。
我们希望这篇文章将帮助Blue Teams进行防御检测 , 并更好地理解支持Cobalt Strike的加密基础知识 。
对于Red Team , 我们提供了一个示例 , 说明为什么加强你的Command and Control基础结构很重要 。
在Cobalt Strike中 , 修复了多个版本中存在的漏洞:
·Cobalt Strike&lt= 3.5
·Cobalt Strike 3.5-hf1(针对在野漏洞利用链的热补丁程序)
·Cobalt Strike 3.5-hf2
该漏洞由Cobalt Strike的团队于2016年披露 , 并于9月得到了积极利用 。 迅速以3.5.1的版本发布了补丁 。
0x02 从 Beacon 开始
Beacon是下载Beacon(DLL)shellcode blob的过程 , 该过程将通过较小的shellcode下载程序执行-通常是漏洞利用程序或删除程序文档的结果 。 这里的目的是解决受大小限制的漏洞利用 , 例如 , 由于缓冲区溢出或类似情况 , 你只有一定数量的空间来保存你的shellcode 。 就是说 , 从红队作战的角度来看 , 在可能的情况下 , 始终首选全阶段(也称为无阶段)有效载荷 。

默认情况下 , Cobalt Strike支持Meterpreter暂存协议 , 并通过checksum8格式公开其暂存器URL。
互联网|对红队利器Cobalt Strike一个历史遗留漏洞的研究
本文插图

通过Checksum8检索stager
从Cobalt Strike 3.5.1开始 , 你现在还可以使用“ host_stage = false ”设置完全禁用下载 。 在此文章中讨论的漏洞的官方修补程序之后 , 此功能作为一项功能添加 。
下载暂存器shellcode后 , 在执行传递到解码的BeaconDLL之前 , 将使用自定义XOR编码器对其余的shellcode进行解码 。 所用的XOR编码器将不在本文中讨论 , 因为这是Cobalt Strike许可版本的功能 。
从暂存器Blob中提取DLL之后 , 可以使用固定的XOR密钥0x69提取Beacon设置以及公共密钥 。 这是SentinelOne团队最近发布的 , 该团队发布了CobaltStrikeParser工具 。
0x03 Cobalt Strike Beacon 的内部通信
解码并执行后 , Beacon随后需要与Team Server通信 。 在构建漏洞payload之前 , 这涉及我们需要了解的各种Cobalt Strike通信和加密内部 。
Beacon载入
每当Beacon载入时 , 它都会发送一个加密的元数据blob 。 这是使用从下载程序提取的RSA公钥加密的 。 为了帮助调试 , 你可能还希望从Team Server中转储RSA私钥 。

这可以通过在Team Server上运行以下Java代码来实现 。 私钥在名为“ .cobaltstrike.beacon_keys”的文件中序列化 , 该文件与Team Server文件位于同一文件夹中 。
要编译/运行此代码 , 你需要将你的类路径设置为cobaltstrike.jar文件(例如-cp cobaltstrike.jar)
import java.io.File
import java.util.Base64
import common.CommonUtils
import java.security.KeyPair
class DumpKeys
{
public static void main(String[] args)
{
try {
File file = new File(".cobaltstrike.beacon_keys")
if (file.exists()) {
KeyPair keyPair = (KeyPair)CommonUtils.readObject(file, null)
System.out.printf("Private Key: %s", new String(Base64.getEncoder().encode(keyPair.getPrivate().getEncoded())))
System.out.printf("Public Key: %s", new String(Base64.getEncoder().encode(keyPair.getPublic().getEncoded())))


推荐阅读