Joe1sn's Cabin

【免杀】Cobaltstrike Stager Payload分析

cobaltstrike的payload主要分为Stager和Stageless

  • Stager:分阶段式上线,从teamserver下载真正的payload后执行,体积小
  • Stageless:部分阶段上线,真正的payload直接在其中,适合用于红队测试中的免杀制作,体积大

公众号:https://mp.weixin.qq.com/s/UsPTeRZvlLFUG-EjCkVqTQ

或许我们的公众号会有更多你感兴趣的内容

img

Stager Exe Payload分析

软件版本:Teamserver 4.9.1

image-20250528075956842

image-20250528075620725

Payloads->Windows Stager Payload,具体配置如下

image-20250528080113726

IDA 分析

入口点位于:4014C0

image-20250528080513395

sub_401990

image-20250528081509897

利用时间等信息异或获得两个随机数:randomA_4044D0randomB_4044E0,且二者&0xFFFFFFFFFFFF

sub_401180

一些初始化的操作,和主要功能关系不大

sub_403040

image-20250528085711344

真正释放payload的地方

sub_4017F8

image-20250528090021917

image-20250528090705443

这里模仿了windows中的管道的命名方式,并在后续的sub_4016E6创建该管道

sub_4016E6 -> sub_401630

image-20250528090836327

创建了命名管道后写入一些内容后关闭管道

查看调用发现向管道写入 lpBuffer_0x37D字节

image-20250528091202941

image-20250528091151364

image-20250528091456690

shift+e先保存lpBuffer_方便后续分析

sub_4017A6

在创建线程冰箱管道写入过后进入该函数

  • sub_401704

    image-20250528091709972

    从命名管道读取0x37D到申请的lpBuffer

  • sub_401595

    image-20250528092045154

    经典的运行shellcode片段,调用如下sub_401595(lpBuffer, nNumberOfBytesToWrite, &unk_404028);。对刚才从管道中读出的数据进行了异或来还原,异或的key为unk_404028

    image-20250528091952230

编写还原脚本

1
2
3
4
5
6
7
8
9
10
if __name__ == '__main__':
cipher = b""
keys = [0xC2, 0xF0, 0xA1]
with open("lpBuffer_.bin","rb") as srcFile:
cipher=srcFile.read()
with open("decrypted_shellcode.bin","wb") as dstFile:
counter = 0
for c in cipher:
dstFile.write((c ^ keys[counter % 3]).to_bytes(1,'little'))
counter += 1

唯一一个需要注意的地方就是C语言是固定数据类型的,所以使用&可以达到和%一样的效果,只不过**&3等效于%4**。python中的数据是不固定的,所以使用&可能由于数据长度导致数字错误从而index out of range

image-20250528093442739

image-20250528093021815

到这里观察我们还原出来的shellcode

image-20250528093453071

如果我们对于相同的payload和listener生成shellcode

image-20250528093604448

发现惊人的相似,主要不同

image-20250528094308195

得出结论:CobaltStrike 的 Stager Excute生成的artifact.exe是在运行Stager Shellcode

sub_401563

image-20250528094713540

比shellcode好多了的是这种payload会使用exe提供的GetModuleHandleAGetProcAddress,从而避免了从LDR中遍历得到

Stager Shellcode Payload分析

将刚才还原的decrypted_shellcode.bin放到ida中分析汇编(64位)

image-20250528095217268

最开始IDA会将这段识别为数据,可以直接右键

image-20250528095308675

image-20250528095323950

可以创建为一个函数,便于分析

image-20250528095146672

汇编逐行分析的话确实有点冗长

第一阶段:找到相关函数并加载

image-20250528100242402

这里使用循环Ldr和异或比较得到关键值

image-20250528100709289

一般来说对应的C代码长这样

image-20250528100759128

image-20250528101218855

  • 找到loadlib

  • 加载wininet加载相关函数,如果想知道传入的参数,直接按照传参顺序看寄存器即可(一般是stdcall)

    image-20250528101605152

    image-20250528101746701

    image-20250528101801289

    image-20250528101812830

    估计从这里开始准备接收第二阶段payload然后运行

    image-20250528101926813

    image-20250528102238222

    这里每次读取0x2000大小知道读完,传输了一段shellcode

第二阶段:反射式加载payload,这里运行的shellcode就是teamserveer分发过来的了,提取这部分的shellcode