你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

admin 2024年8月10日14:02:38评论25 views字数 3963阅读13分12秒阅读模式
你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

在这篇文章中,我们将回顾我们开发的一种简单技术,该技术在执行 BOF 时加密内存中的 Cobalt Strike 的 Beacon,以防止内存扫描检测到 Beacon。

想象一下——你正在参加红队交战,你的网络钓鱼成功了,你的初始访问有效载荷通过了 EDR,你的信标现在存在于内存中并向你发出回调。最困难的部分已经过去,是时候进行一些后期利用了。你启动你值得信赖的 BOF 工具包,看着“最后”计时器无限期地滴答作响。

虽然初始信标可能无法被检测到,但从信标对象文件执行常见的后利用活动可以触发EDR对您的进程进行内存扫描。这可能导致 EDR 产品发现您的信标位于内存中并终止该进程。

Cobalt Strike(某种程度上)最近引入了 Sleep Mask 功能,该功能用于在 Beacon 休眠时将其隐藏在内存中。这有助于防止威胁搜索工具或内存扫描器检测 Beacon 签名或可疑工件(如未备份的可执行内存)。从 Cobalt Strike 4.7 开始,Sleep Mask 以 BOF 的形式实现,这为操作员提供了对 Sleep Mask 工作方式的更多控制。这表明在 BOF 执行期间可以加密 Beacon 并使其休眠。但是,在正常的 BOF 执行期间,Beacon 位于内存中。让我们看看如何改变这种情况。

Beacon 对象文件基础知识

如果您不熟悉 Beacon 对象文件 (BOF) 的内部结构,那么它们本质上是一种编写位置无关代码的方法,Beacon 负责加载和链接任何依赖项。这使操作员能够快速开发后漏洞利用工具,而无需编写 shellcode 或反射 DLL。

当你执行 BOF 时,它看起来像这样:

  1. Beacon 根据您的 Malleable C2 设置分配内存并写入 BOF 内容

  2. BOF 加载器负责链接任何导入的函数并查找 BOF 的指定入口点

  3. 执行传递到入口点,您的 BOF 内容运行,Beacon 恢复执行

  4. 根据您的 Malleable C2 设置清理分配的 BOF 内存

本博客并非旨在作为 BOF 的参考,因此您可以在此处找到有关 BOF 的更多信息:

  • 面向开发人员的 Beacon 对象文件介绍、TrustedSec

  • Beacon 对象文件,Cobalt Strike

查找 Beacon 的基地址

为了在内存中屏蔽 Beacon,我们需要知道它的基地址和大小。有几种方法可以找出这些信息,但我发现最可靠的方法是使用一些汇编和 VirtualQuery API。

当执行 BOF 时,我们从 BOF 入口点调用一个函数,我们的堆栈框架在顶部如下所示:

  • 当前功能

  • BOF 入口点

  • 灯塔

下面是一段返回两个堆栈框架的汇编代码。这将使我们从函数转到 BOF 入口点,再转到 Beacon 的返回地址。这将为我们提供 BOF 完成后 Beacon 恢复执行的地址,该地址位于 Beacon 的 .text 部分内。

你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

现在我们已经有了 Beacon 内存范围的地址,我们需要找到它的基地址。我们可以通过两次调用 VirtualQuery 来实现这一点。第一次调用将获得前一个地址所在区域的基地址,第二次调用将获得为 Beacon 分配的基地址和大小。后两个值是我们进行掩码所需的值。

考虑可塑性 C2 和 UDRL

Beacon 最出色的功能之一是它在许多方面为操作员提供了灵活性。有两种主要机制可以更改 Beacon 加载到内存中的方式:可塑 C2 设置和用户定义的反射加载器。以下是一些深入介绍这两种机制的链接:

  • 定义 Cobalt Strike 反射加载器,安全情报https://securityintelligence.com/posts/defining-cobalt-strike-reflective-loader/

  • PE 和内存指标, Cobalt Strike-https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2-extend_pe-memory-indicators.htm#_Toc65482854

我们需要考虑这样一个事实:Beacon 可能会以不同的方式加载到内存中,这会破坏我们的 VirtualQuery 逻辑。当您在内存区域上调用 VirtualQuery 时,它将返回内存中所有具有相同属性(内存保护和页面状态)的后续页面的结果。因此,如果 Beacon 完全分配有 RWX 权限,则调用 VirtualQuery 两次就可以完美运行。但是,如果您正确设置了 Beacon 每个部分的内存保护,那么在 Beacon 的基址上调用 VirtualQuery 将仅返回 NT Header 部分的大小,因为它的内存保护设置与 .text 部分不同。

值得庆幸的是,解决这个问题非常简单。我们可以查询内存中的下一个区域并验证它是否可执行,以及我们之前获得的 Beacon 返回地址是否在该区域内。如果确实如此,那么我们就找到了 Beacon 的 .text 部分!

遮蔽信标

现在我们有了 Beacon 的 .text 部分的基地址和大小,我们可以更改页面保护,然后应用我们的掩码。

你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

在上面的代码片段中,我们调用 VirtualProtect 将 Beacon 的页面保护更改为 RW,然后在 Beacon 上应用一个简单的 XOR 掩码。为了简单起见,我们在设置函数中生成一次这个随机掩码。要取消 Beacon 的掩码,我们只需通过再次应用 XOR 并将 Beacon 的页面保护更改为之前的保护(RWX 或 RX)来反转这两个操作的顺序。

示范

为了演示目的,我们有一个 BOF,它仅调用 MessageBoxA 来阻止执行,并让我们有机会使用一些常见的内存分析工具扫描 Beacon 进程的内存:Moneta、PESieve 和 YARA。

无遮罩

这是 Moneta 报告的三个未备份 RX 区域。这是我们的 Beacon、我们的 Sleep Mask BOF 和我们当前正在执行的 BOF。根据您的 Malleable C2 配置文件,这可能看起来有所不同。

你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

这是 PE-Sieve,带有 /shellc 和 /data 三个选项,转储出我们可以看到的 Beacon 区域。

你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

这是Elastic 发布的用于检测 Cobalt Strike 的规则集中的 YARA 检测。

你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

带遮罩

现在我们可以应用屏蔽代码将 Beacon 隐藏在内存中并重试。以下是 Moneta 对我们的 Sleep Mask BOF 和我们当前正在执行的 BOF 的报告,但不是我们的 Beacon。

你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

PE-Sieve 输出为零检测。

你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

YARA 没有检测到任何异常。

你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

如您所见,这种技术确实产生了效果,并且应该有助于防止内存扫描器在 BOF 执行期间通过基于签名的检测或内存伪像检测到我们的 Beacon。我们当前的 BOF 和 Sleep Mask BOF 的存在并不理想,因为它们是不受支持的 RX 区域 IOC,但如果在内存扫描期间未识别出任何签名,EDR 可能不会仅针对此发出警报。

如果担心这些未备份的内存区域,那么以类似的方式识别和屏蔽 Sleep Mask BOF 相对简单。至于屏蔽当前 BOF,应该可以使用一些现有的 ROP 技术进行屏蔽,但对于更复杂的 BOF 来说,这变得非常困难。

注意事项

使用此技术时需要注意的最重要的一点是,当 Beacon 加密时,您无法从 BOF 调用 Beacon API — 这意味着任何内部 Beacon API(如 BeaconPrintf、BeaconSpawnInject 等)都无法调用。由于这些函数位于 Beacon 的 .text 部分,因此您将把执行权交给不可执行的垃圾代码,您的 Beacon 将会死亡。如果您有需要从 BOF 获取的输出,那么您可以在取消掩码后将其全部发回,也可以在每次 Beacon API 调用之前/之后切换掩码。

与现有工具集成

为了让红队能够模拟更高级的威胁行为者,并让蓝队更熟悉内存扫描规避技术,我们希望实现这项技术,以便尽可能轻松地将其与您的 BOF 武器库集成。为此,我们将该项目发布为单个 C 头文件,您可以将其包含在现有的 BOF 中。您只需在第一次调用 MaskBeacon 之前调用 GetBeaconBaseAddress 函数,然后就可以调用 MaskBeacon/UnmaskBeacon 函数来切换掩码。BOF 入口点的示例如下所示。

你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

如果您想在代码中调用 Beacon API,您可以像这样切换掩码。

你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

通过 C2 通道操作时,稳定性始终是一个问题,而 BOF 中的错误是毁掉您辛苦获得的 Beacon 的绝佳方法。我们已尝试使此代码尽可能可靠和稳定,但总有出错的可能。如果您的 BOF 依赖于任何 Beacon API 调用,则应进行彻底测试,以确保在执行过程中不会因屏蔽而遇到任何障碍。将此代码与任何复杂的加载器一起使用时也是如此 — 您应该确保在执行之前正确定位 Beacon 的 .text 部分。已包含一些调试指令以帮助进行故障排除。

检测

与任何 C2 相关主题一样,检测是主要关注点。但是,检测 BOF 特定的执行并不是一个特别有用的领域。BOF 最终只是与位置无关的代码,加载了一些良性的 API 调用。检测工作最好花在检测 Beacon 执行和后利用活动上。要使 BOF 有用,它必须在主机或网络上生成一些活动,而追踪这些行为会更有成效。一些示例 BOF 活动可能包括枚举本地主机或 Active Directory、凭据转储活动或注入另一个进程。

尽管如此,这种技术确实将正在执行的 BOF 和 Sleep Mask BOF 留在内存中作为不受支持的 RX(或 RWX)区域。对于威胁猎手和内存扫描器来说,这些通常是恶意活动的良好指标。但是,如上所述,熟练的操作员可以通过多种方式隐藏这些工件。

结论

在这篇文章中,我们展示了如何应用与 Beacon 的 Sleep Mask 套件相同的原理,在 BOF 执行期间为 Beacon 提供一些额外的 OPSEC。我们认为这是一种相对简单的技术,可以针对使用内存扫描和静态签名检测的产品提供巨大的回报。

原文始发于微信公众号(Ots安全):你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月10日14:02:38
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   你的 BOF 太恶心了,戴上面具:如何在 BOF 执行期间隐藏信标https://cn-sec.com/archives/3052591.html

发表评论

匿名网友 填写信息