BOFMask:隐藏Cobalt Strike Beacon的BOF执行
作者:Sec-Labs | 发布时间:
项目地址
https://github.com/passthehashbrowns/BOFMask
BOFMask项目简介
相关技术点
- Cobalt Strike
- BOF( Beacon Object File)
- VirtualQuery API
- VirtualProtect API
项目用途
BOFMask是一个证明性的概念,通过掩盖Cobalt Strike的Beacon有效负载,同时执行Beacon Object File(BOF)。Beacon的执行在BOF执行期间通常是暴露的。如果用户提供的BOF触发了EDR产品的内存扫描,则Beacon很可能会被检测到。因此,这个项目旨在通过执行BOF时隐藏Beacon,从而证明这是可能的。
BOFMask的实现方式很简单:使用一个设置函数GetBeaconBaseAddress生成密钥并查找Beacon的基地址。通过在BOF执行结束后向上查找两个堆栈帧以查找返回地址,从而找到Beacon的基地址。这将是Beacon的.text部分内的地址,我们可以将其传递给VirtualQuery API以获取.text部分的基地址。然后,使用简单的XOR掩码来隐藏Beacon,并使用VirtualProtect API更改内存保护设置。
BOFMask项目主要用途是在BOF脚本中隐藏Beacon,从而在执行时不被发现。在使用时需要注意,必须从BOF入口点调用GetBeaconBaseAddress函数,然后使用MaskBeacon和UnmaskBeacon函数来切换BOF掩码。同时需要避免在掩码时调用Beacon API函数,否则可能会导致Beacon崩溃。
BOFMask
本仓库包含了这篇博客文章的代码:
BOFMask 是一个掩盖 Cobalt Strike 的 Beacon payload 的概念验证,同时执行一个 Beacon Object File (BOF)。通常,BOF 执行时会暴露 Beacon。如果用户提供的 BOF 触发 EDR 产品的内存扫描,那么 Beacon 很可能会在内存中被检测到。自 Cobalt Strike 4.7 发布以来,用户可以提供一个 Sleep Mask 来隐藏正在休眠的 Beacon,这是由用户提供的 BOF 实现的。这证明了在掩盖 Beacon 的同时执行 BOF 是可能的。
实际上,这个实现很简单:一个设置函数 GetBeaconBaseAddress 用于生成密钥并找到 Beacon 的基址。通过向上两个堆栈帧来找到 BOF 执行结束后的返回地址,可以找到 Beacon 的基地址。这将是在 Beacon 的 .text 段内的一个地址,我们可以将其传递给 VirtualQuery API 来获取 .text 段的基地址。然后,使用简单的 XOR 掩码来隐藏 Beacon,并使用 VirtualProtect API 更改内存保护设置。
用法
这段代码的主要目的之一是让用户将其放入他们现有的 BOF 武器库中,并进行最小的修改。为此,使用 BOF 掩码相当简单。
必须从 BOF 入口点调用 GetBeaconBaseAddress 函数。您不能从入口点调用另一个函数,然后调用 GetBeaconBaseAddress。如果 "go" 是 Beacon 将在您的 BOF 中执行的函数的名称,则必须从 "go" 中调用 GetBeaconBaseAddress。
在调用 GetBeaconBaseAddress 设置一切之后,您可以使用 MaskBeacon 和 UnmaskBeacon 切换 BOF 掩码。这里有两个主要的警告:您不能在 Beacon 掩码时调用 Beacon API 函数,并且如果您不以正确的顺序调用 MaskBeacon 和 UnmaskBeacon,则您的 Beacon 将死亡!例如,如果您连续两次调用 MaskBeacon 而不解除掩码,则 Beacon 将进行两次 XOR 并且调用 UnmaskBeacon 将无法修复它。如果您连续调用 UnmaskBeacon 两次,则可能会出现访问冲突,因为 Beacon 可能无法写入。
下面是一个简单的预期用例。
void go(char* args, int length){
//YOUR CODE HERE, YOU MUST CALL ANY ARGUMENT UNPACKING FUNCTIONS BEFORE CALLING MaskBeacon
GetBeaconBaseAddress();
//YOU CAN STILL CALL BEACON APIS HERE
MaskBeacon();
//YOUR CODE HERE
//DO NOT CALL ANY BEACON APIS BETWEEN MASKING AND UNMASKING!!!!! IT WILL KILL YOUR BEACON!!!!!
UnmaskBeacon();
//YOUR CODE HERE, YOU CAN NOW CALL BEACON APIS AGAIN
}
example.c 文件包含了一个简单的用例,该用例掩盖 Beacon,调用 MessageBoxA 阻止执行,然后解除掩码。
编译
此代码旨在使用 MINGW 编译。您可以像这样编译此存储库中包含的示例 BOF:
x86_64-w64-mingw32-gcc -c example.c -o example.x64.o -masm=intel
防御性考虑
检测 Beacon 的 BOF 执行并不是一个特别有成果的领域。最终,Beacon Object File 只是由一些良性的 API 调用 (LoadLibraryA/GetProcAddress/VirtualAlloc 等) 加载的位置无关代码。更有成果的方法是专注于防止初始的 Beacon 执行,或检测随后的后渗透活动。对于一个 BOF 而言,它必须在主机或网络上生成一些活动,比如通过 LDAP 枚举 Active Directory 或执行凭证转储攻击。
话虽如此,这种技术确实将正在执行的 BOF(以及如果正在使用的话的 Sleep Mask BOF)留在了内存中作为未备份的 RX(或 RWX)区域。这些通常是威胁猎人和内存扫描器检测恶意活动的好指标。然而,有办法让这些残留物被熟练的操作员隐藏起来。
下面是一个非全面的资源列表,您可以使用它来检测 Cobalt Strike。
- Cobalt Strike YARA 规则 - Elastic - https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_CobaltStrike.yar
- PE-Sieve - Hasherezade - https://github.com/hasherezade/pe-sieve
- Moneta - Forrest Orr - https://github.com/forrest-orr/moneta
- Hunt Sleeping Beacons - @thefLinkk - https://github.com/thefLink/Hunt-Sleeping-Beacons
- BeaconEye - Ceri Coburn - https://github.com/CCob/BeaconEye
- Cobalt Strike, A Defenders Guide - DFIR Report - https://thedfirreport.com/2021/08/29/cobalt-strike-a-defenders-guide/