剖析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 整体执行流程

  1. DllMain 初始化:DLL 入口点
  2. WriteBufferToPipe:将加密 shellcode 发送到命名管道
  3. 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 函数

  1. 获取 tick 计数 (GetTickCount) 并除以 0x26AA 作为随机数
  2. 使用 sprintf 格式化管道名称:\\.\pipe\MSSE-%d-server
  3. 创建新线程执行 WriteBufferToPipeThread
  4. 跳转到 PipeDecryptExec 例程

3.2.3 WriteBufferToPipe 线程

  1. 从全局 Payload 变量获取:
    • Shellcode 大小(偏移 0x4)
    • 加密 shellcode 指针(偏移 0x14)
  2. 创建命名管道 (CreateNamedPipeA)
  3. 连接管道 (ConnectNamedPipe)
  4. 循环写入 shellcode (WriteFile)
  5. 关闭管道句柄 (CloseHandle)

3.2.4 PipeDecryptExec 流程

  1. 分配内存接收 shellcode (malloc)
  2. 休眠 1024 毫秒 (Sleep(0x400))
  3. 从管道填充缓冲区 (FillBufferFromPipe)
    • 打开管道 (CreateFileA)
    • 读取 shellcode (ReadFile)
    • 关闭管道 (CloseHandle)
  4. 解密并执行 shellcode (XorDecodeAndCreateThread)
    • 分配新内存 (VirtualAlloc)
    • XOR 解密 shellcode
    • 尝试获取 GetModuleHandleAGetProcAddress 指针
    • 修改内存权限为可执行 (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 流程优化方案

  1. 移除管道相关代码

    • 直接调用 PipeDecryptExec
    • 跳过 malloc 和管道读取
    • 直接提供加密 shellcode 给 XorDecodeAndCreateThread
  2. 修改后的执行流程

    DllMain → DllMainThread → PipeDecryptExec → XorDecodeAndCreateThread
    

6.2 蓝队检测建议

  • 检测规则

    • 命名管道模式:MSSE-\d+-server
    • XOR 解密循环特征
    • 内存权限修改序列(PAGE_READWRITE → PAGE_EXECUTE_READ)
  • 增强检测

    • 监控 CreateNamedPipeAConnectNamedPipe 调用
    • 分析 DLL 的导出函数行为

6.3 红队改进建议

  • 定制化修改

    • 修改默认管道名称格式
    • 实现更复杂的加密算法
    • 减少不必要的内存操作
  • 规避策略

    • 避免使用文档记录的已知特征
    • 实现真正的进程间通信而非简单 memcpy

7. 总结与结论

  1. Cobalt Strike DLL Stager 使用命名管道作为中间传输机制,但实际功能可以简化
  2. 命名管道技术 在某些情况下确实能规避检测,但已成为已知 IOC
  3. 执行流程优化 可以减少检测面,提高载荷效率
  4. 防御方 应关注内存操作序列和管道创建模式
  5. 攻击方 应定制化载荷,避免使用默认配置和已知特征

附录:关键函数伪代码

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;
}
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 入口点 创建新线程执行 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 处 解密流程 : 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 修改后的执行流程 : 6.2 蓝队检测建议 检测规则 : 命名管道模式: MSSE-\d+-server XOR 解密循环特征 内存权限修改序列(PAGE_ READWRITE → PAGE_ EXECUTE_ READ) 增强检测 : 监控 CreateNamedPipeA 和 ConnectNamedPipe 调用 分析 DLL 的导出函数行为 6.3 红队改进建议 定制化修改 : 修改默认管道名称格式 实现更复杂的加密算法 减少不必要的内存操作 规避策略 : 避免使用文档记录的已知特征 实现真正的进程间通信而非简单 memcpy 7. 总结与结论 Cobalt Strike DLL Stager 使用命名管道作为中间传输机制,但实际功能可以简化 命名管道技术 在某些情况下确实能规避检测,但已成为已知 IOC 执行流程优化 可以减少检测面,提高载荷效率 防御方 应关注内存操作序列和管道创建模式 攻击方 应定制化载荷,避免使用默认配置和已知特征 附录:关键函数伪代码 DllMainThread 伪代码 XorDecodeAndCreateThread 伪代码 JumpToParameter 伪代码