使⽤内存签名检测 Cobalt Strike

——————————————————————————————————————————————————
基于签名的检测 — 尤其是内存中扫描 ——是⼀种极具价值的威胁检测策略。在这篇文章中,
了解如何在有效误报率为零的情况下检测 Cobalt Strike,而不管它的配置或隐蔽功能如何。
——————————————————————————————————————————————————

在 Elastic 安全中,我们会借助多种⽅法来应对威胁检测⽅⾯的挑战。在传统上,我们专注于研究 Machine Learning 模型和⾏为。这两种⽅法⾮常强⼤,因为它们可以检测到前所未⻅的恶意软件。从历史数据看,我们认为签名太容易被规避,但我们也认识到,规避的难易只是需要考虑的众多因素之⼀。性能和误报率也是衡量检测技术有效性的关键。

签名虽然⽆法检测到未知的恶意软件,但其误报率接近于零,并且有相关联的标签,这对确定告警优先级会有所帮助。例如,与不受欢迎的潜在⼴告软件变体相⽐,针对 TrickBot 或 REvil 勒索软件的告警更需要⽴即采取⾏动。即使我们假设通过签名只能捕获⼀半的已知恶意软件,但考虑到其他⽅⾯的益处,再配以其他保护措施,这仍然是⼀个巨⼤的胜利。实际上,我们还可以做得更好。

在创建具有⻓期价值的签名⽅⾯,⼀⼤障碍就是加壳程序和⼀次性恶意软件加载程序的⼴泛使⽤。这些组件会迅速进化以规避签名检测;但是,最终的恶意软件有效负载终究会在内存中解密并执⾏。

为了解决加壳程序和加载程序的问题,我们可以将签名检测策略集中在内存中的内容上。这会有效地将签名的有效期限从⼏天延⻓到⼏个⽉。

Cobalt Strike 是⼀种流⾏的框架,⽤于进⾏红队操作和对⼿模拟。⼤概是由于它的易⽤性、稳定性和隐蔽功能,它也
成为了有着更多不轨意图的不法者最爱的⼯具。现在有多种技术可以检测 Cobalt Strike 的终端有效负载 Beacon。

这包括查找⽆⽀持线程 ,以及最近的内置命名管道 。然⽽,由于 Beacon 具有很⾼的可配置性 ,因此通常有⼀些⽅
法可以避开公共检测策略。下⾯,将尝试使⽤内存签名作为替代检测策略。

Beacon 通常是反射加载到内存中,并且从不以可直接签名的形式接触磁盘。此外,Beacon 可以配置各种内存中混淆
选项以隐藏其有效负载。例如, obfuscate-and-sleep 选项会试图在回调之间屏蔽部分 Beacon 有效负载,以专⻔避
开基于签名的内存扫描。我们在开发签名时需要考虑这个选项,但即使有这些先进的隐蔽功能,对 Beacon 进⾏签名仍
然很容易。
我们将⾸先获取⼀些 Beacon 有效负载,并在最新版本中启⽤和禁⽤ sleep_mask 选项(参考部分中的哈希)。从禁
⽤ sleep_mask 的示例开始,在引爆后,我们可以通过 Process Hacker 查找从⽆⽀持区域调⽤ SleepEx 的线程来定位
内存中的 Beacon:
1645531309-753560-1.png
然后,可以将关联的内存区域保存到磁盘以供分析:
1645531340-225218-2.png
最简单的做法是,从这个区域挑选⼀些独特的字符串并将它们⽤作我们的签名。出于演示⽬的,我们将使⽤ yara 编写
签名,这是⽤于此⽬的的⾏业标准⼯具:

rule cobaltstrike_beacon_strings
{
meta:
 author = "Elastic"
 description = "Identifies strings used in Cobalt Strike Beacon DLL."
strings:
 $a = "%02d/%02d/%02d %02d:%02d:%02d"
 $b = "Started service %s on %s"
 $c = "%s as %s\\%s: %d"
condition:
 2 of them
}

这将为我们提供良好的保障基础,但我们可以通过参照启⽤了 sleep_mask 的示例来做得更好。如果我们看⼀下内存中通常可以找到 MZ/PE 标头的位置,现在会看到它被模糊化了:
1645531556-175929-3.png
快速看⼀下这张图,我们可以看到许多重复的字节(在本例中为 0x80),⽽我们实际期望看到的是空字节。这可能表明 Beacon 正在使⽤简单的单字节 XOR 混淆。我们可以使⽤ CyberChef 来进⼀步确认⼀下:
1645531617-622906-4.png
⼤家可以看到,解码后出现 “This program cannot be run in DOS mode”(此程序⽆法在 DOS 模式下运⾏)字符串,证实了我们的猜测。因为单字节 XOR 是最⽼套的技巧之⼀,yara 实际上⽀持使⽤ xor 修饰符进⾏原⽣检测:

rule cobaltstrike_beacon_xor_strings
{
meta:
 author = "Elastic"
 description = "Identifies XOR'd strings used in Cobalt Strike Beacon DLL."
strings:
 $a = "%02d/%02d/%02d %02d:%02d:%02d" xor(0x01-0xff)
 $b = "Started service %s on %s" xor(0x01-0xff)
 $c = "%s as %s\\%s: %d" xor(0x01-0xff)
condition:
 2 of them
}

到⽬前为⽌,我们可以通过在扫描时提供 PID 来确认基于我们 yara 规则的检测:
1645531700-476352-5.png
然⽽,这还没有结束。在使⽤最新版 Beacon(撰写本⽂时为 4.2)的示例上测试这个签名后,混淆例程已得到改进。
这⼀例程可以按照前⾯所示的调⽤堆栈来找到。它现在使⽤ 13 字节的 XOR 密钥,如以下 IDA Pro 代码段所示:
1645531714-310836-6.png
幸运的是,Beacon 的 obfuscate-and-sleep 选项只会混淆字符串和数据,让整个代码部分都可以进⾏签名。不过,我们应该为代码部分中的哪个函数开发签名确实也是个问题。现在,我们可以只在反混淆例程上创建⼀个签名,它就应该可以运作得很好:

rule cobaltstrike_beacon_4_2_decrypt
{
meta:
 author = "Elastic"
 description = "Identifies deobfuscation routine used in Cobalt Strike Beacon DLL version 4.2."
strings:
$a_x64 = {4C 8B 53 08 45 8B 0A 45 8B 5A 04 4D 8D 52 08 45 85 C9 75 05 45 85 DB 74 33 45 3B CB 73 E6 49 8B F9 4
C 8B 03}
 $a_x86 = {8B 46 04 8B 08 8B 50 04 83 C0 08 89 55 08 89 45 0C 85 C9 75 04 85 D2 74 23 3B CA 73 E6 8B 06 8D 3C 0
8 33 D2}
condition:
 any of them
}

我们可以验证,即使 Beacon 处于隐蔽休眠状态(32 位和 64 位变体),我们也可以检测到它:
1645531809-138940-7.png
为了将其构建为更强⼤的检测体系,我们可以定期扫描系统上(或整个企业中)的所有进程。这可以通过以下
powershell 单⾏指令来完成:
powershell -command "Get-Process | ForEach-Object {c:\yara64.exe my_rules.yar $_.ID}"

总结

基于签名的检测虽然经常被⼈们所忽视,但却是⼀种极其重要的检测策略 — 尤其是在我们考虑内存中扫描时。只需少量签名,我们就可以在有效误报率为零的情况下检测 Cobalt Strike,⽽不管它的配置或隐蔽功能如何。

参考哈希

7d2c09a06d731a56bca7af2f5d3badef53624f025d77ababe6a14be28540a17a
277c2a0a18d7dc04993b6dc7ce873a086ab267391a9acbbc4a140e9c4658372a
A0788b85266fedd64dab834cb605a31b81fd11a3439dc3a6370bb34e512220e2
2db56e74f43b1a826beff9b577933135791ee44d8e66fa111b9b2af32948235c
3d65d80b1eb8626cf327c046db0c20ba4ed1b588b8c2f1286bc09b8f4da204f2
原文地址:https://fendou.gqr5.cn/1471.html
------本页内容已结束,喜欢请分享------

感谢您的来访,获取更多精彩文章请收藏本站。

© 版权声明
THE END
喜欢就打个赏呗
点赞14 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容