【知识回顾】Cobalt Strike 4.0 认证及修补过程
字数 1975 2025-08-19 12:42:14
Cobalt Strike 4.0 认证机制及破解方法详解
0x00 前言
本文详细解析Cobalt Strike 4.0的认证机制,包括完整的认证流程、关键代码分析以及可行的破解方法。4.0版本相比3.X版本增加了更复杂的验证机制,特别是引入了Sleeved模块的认证key,这使得"破解"变得更加困难。
0x01 基础知识准备
1.1 RSA算法
加密与签名的区别:
- 加密:防止信息泄露
- 签名:防止信息篡改
核心原则:
- 公钥加密,私钥解密
- 私钥签名,公钥验签
1.2 HMAC消息摘要算法
MAC(Message Authentication Code)是带密钥的Hash函数,用于验证消息完整性。发送方使用共享密钥计算摘要,接收方用相同密钥验证。
1.3 AES加密安全性
AES-128破解需要尝试约2^127≈1.710^38个密钥,即使以比特币网络的算力(2.564410^19次/秒)也需要约2104亿年。
0x02 认证流程分析
2.1 主要验证文件
cobaltstrike.auth:授权文件authkey.pub:RSA公钥文件
2.2 核心验证类
License:许可证检查入口Authorization:授权文件解析AuthCrypto:RSA解密和解压SleevedResource:4.0新增的深层验证SleeveSecurity:处理Sleeved模块的加密验证
2.3 认证流程
-
初始验证:
- 检查
cobaltstrike.auth文件是否存在 - 使用
AuthCrypto解密文件内容 - 验证文件头和数据格式
- 检查
-
授权文件解析:
- 读取有效期标志(29999999表示永久)
- 获取水印值(影响生成的shellcode)
- 提取16字节的Sleeved解密key
-
Sleeved模块验证:
- 使用授权文件中的key派生AES和HMAC密钥
- 验证内置DLL/EXE文件的HMAC
- 解密并加载这些资源文件
0x03 关键代码分析
3.1 License.checkLicenseGUI()
public static void checkLicenseGUI(Authorization var0) {
if (!var0.isValid()) { // 检查授权文件有效性
CommonUtils.print_error("Your authorization file is not valid: " + var0.getError());
System.exit(0);
}
if (!var0.isPerpetual()) { // 检查是否永久授权
if (var0.isExpired()) { // 检查是否过期
CommonUtils.print_error("Your Cobalt Strike license is expired...");
System.exit(0);
}
if (var0.isAlmostExpired()) { // 检查是否即将过期
CommonUtils.print_warn("Your Cobalt Strike license expires in " + var0.whenExpires());
}
}
}
3.2 Authorization类核心逻辑
public Authorization() {
// 读取cobaltstrike.auth文件
byte[] arrayOfByte1 = CommonUtils.readFile(str);
AuthCrypto authCrypto = new AuthCrypto();
byte[] arrayOfByte2 = authCrypto.decrypt(arrayOfByte1); // RSA解密
DataParser dataParser = new DataParser(arrayOfByte2);
int i = dataParser.readInt(); // 读取有效期标志
this.watermark = dataParser.readInt(); // 读取水印值
byte j = dataParser.readByte(); // 版本标识(必须≥40)
byte k = dataParser.readByte(); // key长度(必须=16)
byte[] arrayOfByte3 = dataParser.readBytes(k); // 读取16字节key
SleevedResource.Setup(arrayOfByte3); // 初始化Sleeved验证
}
3.3 AuthCrypto解密过程
public byte[] decrypt(byte[] paramArrayOfByte) {
byte[] arrayOfByte1 = this._decrypt(paramArrayOfByte); // RSA解密
DataParser localDataParser = new DataParser(arrayOfByte1);
localDataParser.big();
int i = localDataParser.readInt(); // 验证文件头
if (i != -889274157) { // 正确文件头值
this.error = "bad header";
return new byte[0];
}
int j = localDataParser.readShort();
byte[] arrayOfByte2 = localDataParser.readBytes(j); // 返回有效载荷
return arrayOfByte2;
}
3.4 SleevedResource验证机制
public void registerKey(byte[] paramArrayOfByte) {
MessageDigest localMessageDigest = MessageDigest.getInstance("SHA-256");
byte[] arrayOfByte1 = localMessageDigest.digest(paramArrayOfByte);
byte[] arrayOfByte2 = Arrays.copyOfRange(arrayOfByte1, 0, 16); // AES密钥
byte[] arrayOfByte3 = Arrays.copyOfRange(arrayOfByte1, 16, 32); // HMAC密钥
this.key = new SecretKeySpec(arrayOfByte2, "AES");
this.hash_key = new SecretKeySpec(arrayOfByte3, "HmacSHA256");
}
0x04 破解方法
4.1 授权文件结构
有效的.auth文件解密后应包含以下结构:
| 偏移 | 长度 | 说明 | 示例值 |
|---|---|---|---|
| 0-3 | 4字节 | 文件头 | 0xCAFEC0D3 |
| 4-5 | 2字节 | 数据长度 | 0x002B |
| 6-9 | 4字节 | 有效期标志 | 0x01C9C37F (29999999) |
| 10-13 | 4字节 | 水印值 | 0x0022907F |
| 14 | 1字节 | 版本标识 | 0x10 (必须≥40) |
| 15 | 1字节 | key长度 | 0x10 (必须=16) |
| 16-31 | 16字节 | Sleeved key | 随机16字节 |
4.2 完整破解步骤
-
生成RSA密钥对:
openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -pubout -out public.pem -
构造授权数据:
- 使用以下16字节key(4.0版本):
{27, -27, -66, 82, -58, 37, 92, 51, 85, -114, -118, 28, -74, 103, -53, 6}
- 使用以下16字节key(4.0版本):
-
计算authkey.pub的MD5:
- 替换
AuthCrypto.load()中的MD5值:if (!"8bb4df00c120881a1945a43e2bb2379e".equals(CommonUtils.toHex(arrayOfByte2)))
- 替换
-
加密授权数据:
- 使用私钥加密构造好的数据
-
替换文件:
- 将加密后的数据保存为
cobaltstrike.auth - 替换
authkey.pub为你生成的公钥文件
- 将加密后的数据保存为
4.3 替代破解方法
方法一:硬编码key
直接修改Authorization类,跳过文件读取和RSA解密,硬编码有效数据:
byte[] arrayOfByte2 = {1, -55, -61, 127, 0, 0, 34, -112, 127, 16, 27, -27, -66, 82, -58, 37, 92, 51, 85, -114, -118, 28, -74, 103, -53, 6};
方法二:使用CSHook.jar
通过Java Agent机制在运行时替换Authorization类,无需修改原始jar包:
public class Transformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className,
Class classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) {
if (className.equals("common/Authorization")) {
// 替换为Base64编码的修改后类文件
return Base64.getDecoder().decode("...");
}
return classfileBuffer;
}
}
0x05 注意事项
-
4.1版本使用不同的key:
{1, -55, -61, 127, 0, 0, 34, -112, 127, 16, -128, -29, 42, 116, 32, 96, -72, -124, 65, -101, -96, -63, 113, -55, -86, 118} -
Sleeved模块验证失败会导致功能受限,错误信息:
[Sleeve] Bad HMAC on xxxxx byte message from resource -
完全破解需要同时满足:
- 通过初始授权验证
- 提供正确的Sleeved解密key
-
从安全角度考虑,建议购买正版授权而非使用破解版本。