1.网络测绘
从网络测绘角度发现cs,也是对cs服务端的探测与识别
1.默认端口50050
弱特征,默认端口为50050,可以在teamserver启动的时候更改
2.默认证书
自带证书,规避方式:自定义一个,或者用自己去申请,自定义的也只是假装伪装而已
默认证书
修改证书后
3.profile文件
默认和常见的profile文件
Beacon执行命令的结果默认是通过post请求/submit.php?id=发回给服务器。
Index | URIs | Index | URIs | Index | URIs |
---|---|---|---|---|---|
1 | /ca | 8 | /fwlink | 15 | /push |
2 | /dpixel | 9 | /cm | 16 | /ptj |
3 | /__utm.gif | 10 | /cx | 17 | /j.ad |
4 | /pixel.gif | 11 | /pixel | 18 | /ga.js |
5 | /g.pixel | 12 | /match | 19 | /en_US/all.js |
6 | /dot.gif | 13 | /visit.js | 20 | /activity |
7 | /updates.rss | 14 | /load | 21 | /IE9CompatViewList.xml |
github上开源profile
例如:
https://github.com/rsmudge/Malleable-C2-Profiles/blob/master/normal/amazon.profile
useragent被标记,可以成为辅助判断因素
profile 编写规则
https://unit42.paloaltonetworks.com/cobalt-strike-metadata-encoding-decoding/
4.jar指纹
JA3|JA3S/JARM
本来 ja3/ja3s 指纹不算是什么很强的特征,因为它只是一个tls握手包的hash值,ja3s是被动流量,jarm是主动探测,这个指纹取决于你的tls所使用的参数,也就是说完全有可能别人写的https服务也和cs的listener撞上了,但是我们不能不修改,因为放着这样一个特征不去管也会成为可能突破口,修改的办法也很简单,在nanohttpd服务中,修改SSL相关的任意参数就能达到效果。
JA3|JA3S
*总的来说:*ja3 和 ja3s 分别代表 tls 握手阶段的 client-hello、server-hello 的数据集合计算出的哈希值(md5),相同版本相同系统下指纹相同,该特征与操作系统、cobaltstrike 版本有关,profile 文件无法对其修改。
作用:
配合 suricata规则检测CS流量
常见JA3的:
win10-https-beacon-ja3 指纹:72a589da586844d7f0818ce684948eea
Debian-cs4.5-ja3s 指纹:ae4edc6faf64d08308082ad26be60767
JARM
总的来说是一个主动TLS服务端指纹工具,主要用途如下:
- 快速验证一组TLS服务器是否使用相同的TLS配置;
- 通过TLS配置划分TLS服务器,并识别可能归属的公司;
- 识别网站默认的应用或基础架构;
- 识别恶意软件C&C控制节点,以及其他恶意服务器。
作者测试的c2指纹:
Malicious Server C2 JARM Fingerprint Overlap with Alexa Top 1M Trickbot 22b22b09b22b22b22b22b22b22b22b352842cd5d6b0278445702035e06875c 0 AsyncRAT 1dd40d40d00040d1dc1dd40d1dd40d3df2d6a0c2caaa0dc59908f0d3602943 0 Metasploit 07d14d16d21d21d00042d43d000000aa99ce74e2c6d013c745aa52b5cc042d 0 Cobalt Strike 07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1 0 Merlin C2 29d21b20d29d29d21c41d21b21b41d494e0df9532e75299f15ba73156cee38 303
实际测试结果:
发现准确率很低
更换CobaltStrike团队服务器以下指纹测试:
07d14d16d21d21d00042d41d00041d47e4e0ae17960b2a5b4fd6107fbb0926
2ad2ad16d2ad2ad00042d42d00042ddb04deffa1705e2edc44cae1ed24a4da
07d14d16d21d21d00042d43d00041de5fb3038104f457d92ba02e9311512c2
搜索截图:
可以发现相比于作者的指纹,能精准不少。
或者用不同的jdk版本去启动,指纹也会变
5.checksum8
如果使用stager上线,即使用分阶段加载,在第二阶段加载beacon.dll时,会请求cs服务端,算法生成的特征默认为checksum8
checksum8算法:路径的 ascii 十进制之和与 256 取余计算值等于 92(x86)或者93(x64)
使用checksum8校验
nmap脚本https://github.com/whickey-r7/grab_beacon_config
2.流量层面
1.默认证书
keytool -list -v -keystore cobaltstrike.store -storepass 123456
规避方式:用keytool伪造新的证书,推荐使用真实的证书,这里只列举keytool
keytool -keystore cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias google.com -dname "CN=US, OU=google.com, O=Sofaware, L=Somewhere, ST=Cyberspace, C=CN"
2.流量特征
有些特征是弱特征,但是弱特征组合起来就是强特征了
1.下载stage
-
访问路径符合checksum8算法
-
使用已知的Cobalt Strike user-agent
2.心跳包
- 请求的uri是cs的默认心跳uri
- Cookies是一个base64编码的内容
- 响应头里面的Content-Length字段为0
- 响应头的Content-Type字段是一个可执行type (application/octet-stream)
3.解密流量
1. 后门区别
Windows Executable (Stage)
生成的 Payload 包含两部分:Stager 和 Stage。Stager 在运行时会向攻击者指定的 IP 和 port 发送 HTTP 请求,以便下载后面的 Stage,然后执行 Stage 中的 Payload 代码。
Windows Executable (s) (Stageless)
生成的 Payload 不再使用 Stage 和 Stager,而是一次性发送所有的 Payload 代码,相当于直接生成一个 stage。
2.已知私钥解密HTTP流量
1. 提取下载stage流量中的公钥
问:团队服务器怎么判断请求是下载stage呢?下载x86还是x64类型的stage?
答:使用checksum8校验访问路径, 92(x86)或者93(x64)
具体通讯截图:
发现强特征
/t5En
符合checksum8算法发现弱特征user-agent
- 将wireshark中抓到的数据包导出
2. 提取元数据
-
提取团队服务器中的私钥
当 TeamServer 启动并加载配置文件时,它会生成一个公钥/私钥对,存储在 TeamServer 根目录下的 .cobaltstrike.beacon_keys 文件中。
-
在TeamServer目录下新建DumpKeys.java
https://gist.github.com/olliencc/af056560e943bafa145120103a0947a3#file-dump-java
# 写入以下代码
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\n\n", new String(Base64.getEncoder().encode(keyPair.getPrivate().getEncoded())));
System.out.printf("Public Key: %s\n\n", new String(Base64.getEncoder().encode(keyPair.getPublic().getEncoded())));
}
else {
System.out.println("Could not find .cobaltstrike.beacon_keys file");
}
}
catch (Exception exception) {
System.out.println("Could not read asymmetric keys");
}
}
}
java -cp "cobaltstrike.jar" DumpKeys.java
- 将得到的公钥与stage流量中的公钥进行对比是否一致
-
解密数据包,提取会话密钥(会话密钥为AES的对称密钥)
https://github.com/minhangxiaohui/CSthing/tree/master/cs-decrypt-metadata_V0_0_1
把Cookie值提取出来(实测任意一个心跳包都可以)
python cs-decrypt-metadata.py -p 密钥 待解密内容
3. 解密任务和执行结果
-
心跳包
默认的Cosbalt Strike 的心跳包中会使用GET请求特定的路径
作用:
1.存活反馈
2.查询是否有任务
可以发现第二个心跳包返回值长度明显大于其他心跳包,后续又用POST方式提交数据包;明显第二个心跳包返回包中存在任务
-
使用Raw key 解密
https://github.com/minhangxiaohui/CSthing/tree/master/cs-parse-http-traffic
3.未知私钥解密流量
1. 使用公开的密钥对尝试解密
目前公开的有6对密钥对
https://github.com/minhangxiaohui/CSthing/blob/master/1768_v0_0_8/
对于某主机的测试
2.内存抓取会话密钥
此处使用Cobalt Strike 4.5 版本,Cobalt Strike第4版Beacon,可以从进程内存中恢复未加密的元数据的情况非常罕见。对于这些Beacon,可以采用另一种方法。在可写的进程内存中可以找到AES和HMAC密钥,但没有明确标识这些密钥的标题。它们只是16字节长的序列,没有任何可区分的特征。为了提取这些密钥,该方法包括执行一种字典攻击。在进程内存中发现的所有可能的16字节长的非空序列,将被用来尝试解密一段加密的C2通信。如果解密成功,就说明已经找到了一个有效的密钥。
- 从wireshark捕获得流量包中提取内容
python3 cs-parse-http-traffic.py -k unknown dump-name
- 使用procdump导出指定程序内存数据
https://learn.microsoft.com/en-us/sysinternals/downloads/procdump
定期抓取:for /L %x in (1, 1, 1000) do procdump.exe name.exe
- 尝试解密
python3 cs-extract-key.py -t 上面提取到得加密内容 dump文件
此处并未解密成功
4.分析DNS流量
1. DNS Beacon
在CS4.0版本之前,有两种Beacon:
windows/beacon_dns/reverse_dns_txt
windows/beacon_dns/reverse_http
在CS4.0及以后的版本中,只剩下了一种:
windows/beacon_dns/reverse_dns_txt
2. DNS流量截图:
以下使用的payload:windows/beacon_dns/reverse_dns_txt;生成的beacon为stageless
3.逐条分析
1.
- Beacon发起A查询
465075be
表示的Beacon ID(bid)的十六进制表示,每个运行中的Beacon都会产生一个32位的数字,用于在团队服务器中识别Beacon。它对每个运行中的Beacon都是不同的,即使同一个Beacon可执行文件被启动了几次。通过查询Beacon ID+域名表示这是一个心跳包
- Team-server返回IPv4 0.0.0.0
表示团队服务器端收到(也就是出现黑窗口,还未激活状态)
2.
- Beacon再次发起A查询
- Team-server回复返回IPv4 0.0.0.243
DNS_Beacon回复规则:
- 如果最后一位为1,意味着beacon要做一个checkin(DNS_metadata查询)。
- 如果第4到2位均设置为0,则通过一个A查询来进行通信
- 如果第2位为1,则是要通过TXT查询来进行通讯。
- 如果第3位为1,则是要通过AAAA查询来进行通讯。
查看DNS_Beacon请求规则
https://github.com/Sentinel-One/CobaltStrikeParser.git
python3 parse_beacon_config.py beacon_name
可以看到最大请求长度是255,进行XOR(异或)操作的值为0.0.0.0(0和任意数xor值不变)
此处
0.0.0.243
中的243的为二进制11110011
和0.0.0.0的二进制进行xor操作后不变即采用0011
,符合规则1和规则3,因此客户端应该在后续返回元数据以及任务下发,所以请求的URL为www和api开头问:为什么运行Beacon时第一个返回的是0.0.0.0,第二个是0.0.0.243
答:DNS beacon上线后需要使用checkin或者其他命令激活,所以第二个为0.0.0.243
3.
-
Beacon发起A查询
域名以
www
开头,表示这是将把元数据发送到服务器,180
为16进制表示长度,03c1225a2
中包含了一个计数器和一个随机数字,随机数字为3c1225a2, 计数器是以0开始,增量为1,可以看到此处计数器从0到3,共发送3次数据;位于www和计数器之间的就是加密数据,按照计数器顺序拼接数据:33b5f264032cdeead9673be9e57cdba9265a29c39f399e3012ad7623e.438ec8e98fac4410ae0e3b8a75fd419b139a61d2bbdcc8ab0c44b929.e0c0a1ef48be67ae1f9d0e5a433a376d2eaad7b4242225eedd3ee4332b969130cf9ffb3f277158cba4179accacb9c59d0.7d21a925ce77185afa2e2dd0f2ed1a964f47e4dd
-
Team-server回复0.0.0.0 表示收到
4.
-
Beacon发起A请求且以api开头
告知服务端可以发送任务,并且下次查询将采用TXT方式
计数器+随机数:07d992def
-
Team-server回复0.0.0.48
表示这个任务长度为48字节,一旦解密后的数据达到这个长度,就会停止发送TXT查询
-
Beacon发起TXT请求
计数器+随机数:17d992def,表示这是第一个数据包
-
Team-server以TXT方式回复数据
-
Beacon再次发起A请求(即心跳包)
-
Team-server回复0.0.0.242
根据上面的规则即0010,所以下次需要发送TXT查询,此次不需要checkin
5.
-
Beacon发起A查询以post开头
post:表示发送命令执行结果
140:被解码成1和40,40为16进制数据对应10进制为64,1为计数器,所以一个长度为64字节的数据
042632934:计算器+随机数
465075be:Beacon ID
-
Team-server回复0.0.0.0表示收到
-
Beacon开始发送加密数据
发起以下请求数据如下:
20736b4c0c8f977522e0ca89653e3d39d9d0f22c137a57ea5e5c5ebf0.02a4592f3f01839010c5ddce052e952c2c10f3260ca0931b0170e643.142632934.465075be
第一个2表示此处有两个加密标签即:
0736b4c0c8f977522e0ca89653e3d39d9d0f22c137a57ea5e5c5ebf0
02a4592f3f01839010c5ddce052e952c2c10f3260ca0931b0170e643
142632934:计算器+随机数
465075be:Beacon ID
-
Team-sever回复0.0.0.0表示收到(此处由于数据太长无法显示)
-
Beacon再次发送加密数据
13ea8c3632874d913.242632934
第一个1表示只有以一个加密标签即:
3ea8c3632874d913
242632934:计数器+随机数
-
所以拼接的加密数据为
0736b4c0c8f977522e0ca89653e3d39d9d0f22c137a57ea5e5c5ebf002a4592f3f01839010c5ddce052e952c2c10f3260ca0931b0170e6433ea8c3632874d913
长度为128的16进制数据,即64字节(一个16进制位等于0.5个字节)
-
Team-sever回复0.0.0.0表示收到
4. 流量分析与解密参考文章链接
- https://blog.nviso.eu/2021/11/03/cobalt-strike-using-process-memory-to-decrypt-traffic-part-3/
- https://blog.nviso.eu/2021/11/29/cobalt-strike-decrypting-dns-traffic-part-5/
- https://www.freebuf.com/articles/system/326750.html
- https://alex-null.github.io/2022/Cobaltstrike%E5%A8%81%E8%83%81%E7%8B%A9%E7%8C%8E%E6%80%BB%E7%BB%93/
- https://mp.weixin.qq.com/s/CjsqWrm70HVEnolZrRD8oA
- https://bbs.kanxue.com/thread-274676.htm