最近在编写针对红队基础设施扫描的时候,研究针对红队C2识别一些方案特征,这里我们以Cobalt Strike作为特征举例。

image-20250114112144146

0.1 思路

众所周知,Cobalt Strike端口可以分为监听端口和Team Server连接端口。

监听端口:Cobalt Strike的Listeners。

连接端口:从客户端连接服务端的端口,由Team Server启动。

由于在攻防中,常见的Cobalt Strike监听端口是HTTP/HTTPS,所有这里我们主要去研究HTTP/STeam Server端口特征方法。

配置【Cobalt Strike 4.7】:

image-20250115153543076

0.2 HTTP/S 监听端口

特征一 JARM【弱特征】

JARM 是一种用于识别和分类 TLS(传输层安全)服务器的指纹识别工具。它通过向目标服务器发送特定构造的 TLS Client Hello 数据包,分析服务器返回的 Server Hello 响应,提取特定属性,生成独特的指纹。这些指纹可用于:

  • 验证服务器组的 TLS 配置一致性:快速检查一组服务器是否具有相同的 TLS 配置。
  • 服务器分组:根据 TLS 配置,将互联网上的服务器进行分组,例如,识别可能属于特定组织(如 Google、Salesforce、Apple)的服务器。
  • 应用程序或基础设施识别:识别默认的应用程序或基础设施。
  • 恶意服务器检测:识别互联网上的恶意软件命令和控制基础设施以及其他恶意服务器。

JARM 的工作原理包括:

  1. 发送特定的 TLS Client Hello 数据包:主动向目标 TLS 服务器发送 10 个特定构造的 Client Hello 数据包。
  2. 捕获服务器响应:记录服务器返回的 Server Hello 响应,提取其中的特定属性。
  3. 生成指纹:对收集的服务器响应进行处理,生成一个 62 字符的指纹,其中前 30 个字符表示服务器对每个 Client Hello 的密码套件和 TLS 版本选择,后 32 个字符是服务器发送的累积扩展名的截断 SHA256 哈希。

projectdiscovery/tlsx: Fast and configurable TLS grabber focused on TLS based data collection.

image-20250115161408010

特征2ad2ad16d2ad2ad00042d42d00042ddb04deffa1705e2edc44cae1ed24a4da,但是由于可以自己生成SSL证书,所有JARM只能算是弱特征。

特征二 响应头【弱特征】

默认访问

image-20250115153952058

当我们使用OPTIONS去请求就会出现Allow: OPTIONS,GET,HEAD,POST

image-20250115154022000

特征:发送OPTIONS得到Allow: OPTIONS,GET,HEAD,POST

特征三 checksum8算法【强特征】

Cobalt Strike 中的 checksum8。在 Cobalt Strike 中,checksum8 是一种用于确定请求 URI 的算法。当用户向 Team Server 发送 HTTP 请求时,服务器会将请求的 URI 传递给 checksum8 函数,并将结果与整数值 92L 或 93L 进行比较。如果结果匹配,服务器将返回相应的 Beacon 二进制负载。具体而言,checksum8 用于区分 32 位和 64 位的 Beacon 负载。

以下是 checksum8函数的 Java 实现:

1
2
3
4
5
6
7
8
9
10
11
public static long checksum8(String text) {
if (text.length() < 4) {
return 0L;
}
text = text.replace("/", "");
long sum = 0L;
for (int x = 0; x < text.length(); x++) {
sum += text.charAt(x);
}
return sum % 256L;
}

也就是说checksum8实现之后的URL是固定的不是随机的,下面我们通过python代码实现这个算法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import requests
import string
from itertools import product
import warnings

warnings.filterwarnings("ignore")


def checksum8(uri):
"""
计算 URI 的 checksum8 值。
"""
if len(uri) < 4:
return 0
uri = uri.replace("/", "")
total = sum(ord(char) for char in uri)
return total % 256


def generate_uris():
"""
生成满足 checksum8 为 92(32 位)和 93(64 位)的 URI 列表。
"""
chars = string.ascii_letters + string.digits
for combo in product(chars, repeat=4):
uri = ''.join(combo)
cs8 = checksum8(uri)
if cs8 == 92:
yield uri, '32-bit'
elif cs8 == 93:
yield uri, '64-bit'


def check_cs_server(base_url):
"""
检查目标服务器是否为 Cobalt Strike 服务器。
"""
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
}
for uri, arch in generate_uris():
url = f"{base_url}/{uri}"
try:
response = requests.get(url, headers=headers, verify=False, timeout=5)
if response.status_code == 200 and response.headers.get('Content-Type') == 'application/octet-stream':
print(f"可能的 Cobalt Strike 服务器,架构:{arch},URI:{url}")
# return
except requests.RequestException as e:
print(f"请求 {url} 时出错:{e}")
print("未检测到 Cobalt Strike 服务器。")


if __name__ == "__main__":
target_url = "https://192.168.65.170:3344"
check_cs_server(target_url)

结果:

image-20250115160407422

image-20250115160422655

特征:发送/aaa9如果HTTP/S是Cobalt Strike,会返回Content-Type: application/octet-stream,而且会返回响应体,其中我们可以判断Content-Type: application/octet-stream以及是否存在响应体,以及响应体长度是否大于2000

0.3 Team Server 连接端口

特征一 JARM【弱特征】

Team Server用于Cobalt Strike客户端连接到服务器的端口,其中Team Server也使用到了SSL,所有我们可以使用在上文中的JARM去检测。

特征二 TCP流量【强特征】

在通过客户端连接到Team Server的时候会产生一系列TLS数据包,其中我们需要使用Wireshark进行抓包解密流量查看特征。

1
2
/usr/lib/jvm/java-11-openjdk-amd64/bin/java -javaagent:jSSLKeyLog.jar=ssss.txt -XX:ParallelGCThreads=4 -XX:+AggressiveHeap -XX:+UseParallelGC -javaagent:CSAgent.jar=CSAgent.properties -Duser.language=en -jar cobaltstrike-client.jar
java -javaagent:<jar包的路径>=<sslkey的存放目录> <正常的jar包路径及参数>

jSSLKeyLog 是一个与 Java 应用程序中的 SSL/TLS 加密通信相关的工具或机制,主要用于调试和分析 SSL/TLS 连接。它的核心作用是记录 SSL/TLS 会话的密钥材料(key material),这些密钥材料可以用于解密加密的网络流量。

下载:jSSLKeyLog-1.3.zip

java8-11运行

我们需要在客户端开启抓包,同时启动jSSLKeyLog.jar。【此处使用的Cobalt Strike需要是破解版本

image-20250115163738664

Edit->Prefernces…->Protocols->TLS

导入我们刚刚使用jSSLKeyLog 抓取到的TLS证书密钥。

image-20250115164153730

筛选TCP流量,选择追踪流,追踪TLS

image-20250115164253312

如果抓取密码成功则是下图片,如果失败则为空。

image-20250115164341464

我们可以看到,我们从客户端输入的密码。

image-20250115164547179

当我们输入成功的密码时,原始数据显示:

image-20250115164638158

当我们输入错误密码时,原始数据显示:

image-20250115164732525

而且密码组成是:

1
b'\x00\x00\xbe\xef\tadmin123aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'

也就是我们可以通过发送,接收返回值探针是否连接成功:发送请求登录请求数据,判断数据是否是00000000或者是0000cafe。

0.4 总结

结合上面两个思路我们可以通过构造特定的数据包去请求Cobalt Strike端口以及特征,需要注意的是这些请求都是有感知的,也就是说在服务端那边是有感知数据的,如下图:

image-20250115165427049

我们可以看到在Web Log以及Team Server存在响应。

  1. JARM
  2. 响应头,响应体
  3. checksum8算法
  4. TCP流量

我们可以通过上面四种方式去探针服务器是否部署了Cobalt Strike

0.5 关于 DarKnuclei

关于 DarKnuclei,DarKnuclei专注于红蓝对抗一款工具,不仅可以扫描漏洞,快速打点,还可以扫描红队基础设施与服务,拥有高扩展的yaml格式指纹文件,方便自己编写红队基础设施指纹。如下图,探针Cobalt Strike端口,判断是否为部署了Cobalt Strike

image-20250115174557745

html报告

image-20250115174622901

项目地址

RuoJi6/DarKnuclei