剖析Cobalt Strike的DLL Stager
字数 2528 2025-08-24 07:48:22
Cobalt Strike DLL Stager 深度分析与教学文档
1. 概述
Cobalt Strike 是一种广泛使用的渗透测试框架,其 DLL Stager 是一种常见的载荷投递方式。本文档将详细剖析 Cobalt Strike DLL Stager 的工作原理、执行流程、技术特点以及防御检测方法。
2. 样本背景
- 攻击目标:金融部门客户
- 初始向量:伪装成工作申请的恶意邮件
- 载荷特点:利用 COM 组件对象模型劫持 (Component Object Model Hijacking) 维持 Cobalt Strike Stager
- 检测指标:包含
MSSE-%d-server格式的命名管道
3. 执行流程分析
3.1 整体执行流程
- DllMain 初始化:DLL 入口点
- WriteBufferToPipe:将加密 shellcode 发送到命名管道
- PipeDecryptExec:从管道读取、解密并执行 shellcode
3.2 详细执行流程
3.2.1 DllMain 入口点
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
CreateThread(NULL, 0, DllMainThread, NULL, 0, NULL);
}
return TRUE;
}
- 创建新线程执行
DllMainThread - 线程函数
DllMainThread是对DecryptBufferAndExec的包装
3.2.2 DllMainThread 函数
- 获取 tick 计数 (
GetTickCount) 并除以0x26AA作为随机数 - 使用
sprintf格式化管道名称:\\.\pipe\MSSE-%d-server - 创建新线程执行
WriteBufferToPipeThread - 跳转到
PipeDecryptExec例程
3.2.3 WriteBufferToPipe 线程
- 从全局
Payload变量获取:- Shellcode 大小(偏移 0x4)
- 加密 shellcode 指针(偏移 0x14)
- 创建命名管道 (
CreateNamedPipeA) - 连接管道 (
ConnectNamedPipe) - 循环写入 shellcode (
WriteFile) - 关闭管道句柄 (
CloseHandle)
3.2.4 PipeDecryptExec 流程
- 分配内存接收 shellcode (
malloc) - 休眠 1024 毫秒 (
Sleep(0x400)) - 从管道填充缓冲区 (
FillBufferFromPipe)- 打开管道 (
CreateFileA) - 读取 shellcode (
ReadFile) - 关闭管道 (
CloseHandle)
- 打开管道 (
- 解密并执行 shellcode (
XorDecodeAndCreateThread)- 分配新内存 (
VirtualAlloc) - XOR 解密 shellcode
- 尝试获取
GetModuleHandleA和GetProcAddress指针 - 修改内存权限为可执行 (
VirtualProtect) - 创建线程执行 shellcode (
CreateThread)
- 分配新内存 (
4. 关键技术点
4.1 命名管道技术
- 管道格式:
\\.\pipe\MSSE-%d-server(Cobalt Strike 已知 IOC) - 目的:将加密 shellcode 从 DLL 移动到另一个缓冲区
- 防御规避:部分 AV 沙箱不模拟命名管道,可能无法检测 shellcode
4.2 加密与解密
- 加密方式:简单 XOR 加密
- 密钥位置:全局
Payload变量偏移 0x8 处 - 解密流程:
for (i = 0; i < shellcode_size; i++) { decrypted_shellcode[i] = encrypted_shellcode[i] ^ xor_key; }
4.3 内存管理
- 分配策略:
- 初始分配:
malloc(不可执行) - 解密分配:
VirtualAlloc(PAGE_READWRITE) - 执行前修改:
VirtualProtect(PAGE_EXECUTE_READ)
- 初始分配:
- 安全考虑:避免同时具有可写和可执行权限(PAGE_EXECUTE_READWRITE)
5. 防御规避技术分析
5.1 Artifact Kit 技术
- 来源:Cobalt Strike 的 Artifact Kit 框架
- 目的:生成可绕过部分 AV 的可执行文件和 DLL
- 命名管道技术:
src-common/bypass-pipe.c中的实现
5.2 检测规避效果
- 原始版本检测率:17/70(VirusTotal)
- 修补版本检测率:16/70(移除管道相关代码)
- 定制管道名版本:18/70(修改为
NVISO-RULES-%d)
6. 实战改进与检测
6.1 流程优化方案
-
移除管道相关代码:
- 直接调用
PipeDecryptExec - 跳过
malloc和管道读取 - 直接提供加密 shellcode 给
XorDecodeAndCreateThread
- 直接调用
-
修改后的执行流程:
DllMain → DllMainThread → PipeDecryptExec → XorDecodeAndCreateThread
6.2 蓝队检测建议
-
检测规则:
- 命名管道模式:
MSSE-\d+-server - XOR 解密循环特征
- 内存权限修改序列(PAGE_READWRITE → PAGE_EXECUTE_READ)
- 命名管道模式:
-
增强检测:
- 监控
CreateNamedPipeA和ConnectNamedPipe调用 - 分析 DLL 的导出函数行为
- 监控
6.3 红队改进建议
-
定制化修改:
- 修改默认管道名称格式
- 实现更复杂的加密算法
- 减少不必要的内存操作
-
规避策略:
- 避免使用文档记录的已知特征
- 实现真正的进程间通信而非简单 memcpy
7. 总结与结论
- Cobalt Strike DLL Stager 使用命名管道作为中间传输机制,但实际功能可以简化
- 命名管道技术 在某些情况下确实能规避检测,但已成为已知 IOC
- 执行流程优化 可以减少检测面,提高载荷效率
- 防御方 应关注内存操作序列和管道创建模式
- 攻击方 应定制化载荷,避免使用默认配置和已知特征
附录:关键函数伪代码
DllMainThread 伪代码
void DllMainThread() {
DWORD ticks = GetTickCount() / 0x26AA;
sprintf(PipeName, "\\\\.\\pipe\\MSSE-%d-server", ticks);
CreateThread(NULL, 0, WriteBufferToPipeThread, NULL, 0, NULL);
PipeDecryptExec();
}
XorDecodeAndCreateThread 伪代码
void XorDecodeAndCreateThread(LPVOID buffer, DWORD size, BYTE xor_key) {
LPVOID exec_mem = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
for (DWORD i = 0; i < size; i++) {
((BYTE*)exec_mem)[i] = ((BYTE*)buffer)[i] ^ xor_key;
}
VirtualProtect(exec_mem, size, PAGE_EXECUTE_READ, &old_protect);
CreateThread(NULL, 0, JumpToParameter, exec_mem, 0, NULL);
}
JumpToParameter 伪代码
DWORD WINAPI JumpToParameter(LPVOID lpParameter) {
((void(*)())lpParameter)();
return 0;
}