Joe Desimone

内存狩猎

威胁猎手的任务是从各种不同的数据源中筛选出攻击活动在其攻击的任何阶段。

11 分钟阅读安全研究
Hunting In Memory

威胁猎手的任务是从各种不同的数据源中筛选出攻击活动在其攻击生命周期的任何阶段。为了成功,猎手必须不断磨练他们对最新攻击者技术和检测方法的主题专业知识。内存驻留恶意软件以多种形式存在,是一种已经存在十多年的攻击者技术。内存驻留恶意软件的普及率稳步增加,可能是由于代码的扩散和内存技术知识的普及所致。更有可能的是,它的普及反映了基于内存的技术在逃避安全产品和从业人员的检测方面的成功。内存驻留技术曾经仅限于高级攻击者,现在已成为各种级别攻击者常用的技术。我将研究最常见的这些基于内存的攻击者技术,并通过我们团队的研究,制定一种可扩展的、低噪音的方法来搜寻隐藏在内存中的攻击者。

攻击者技术

在我讨论用于检测网络中攻击者的内存狩猎方法之前,了解常见的内存驻留恶意软件形式很有帮助。这些技术包括 Shellcode 注入、反射 DLL 注入、内存模块、进程和模块空洞以及 Gargoyle(ROP/APC)。

SHELLCODE 注入

Shellcode 注入是最基本的内存技术,而且存在时间最长。“shellcode 注入”的基本“配方”是一个四步过程。这些步骤是:1) 打开目标进程 (OpenProcess);2) 在进程中分配一块内存 (VirtualAllocEx);3) 将 shellcode 有效负载写入新分配的节 (WriteProcessMemory);4) 在远程进程中创建一个新线程以执行 shellcode (CreateRemoteThread)。受人尊敬的 Poison Ivy 恶意软件使用了这项技术,这也是许多 APT 组织多年来被它吸引的一个重要原因。

如果您使用 x64dbg 提取 Poison Ivy 的 样本,并在 VirtualAllocEx 上设置断点,您很快就会找到负责注入的代码块。

在第一张图中,调用 VirtualAllocEx 之前的 push 40 指令对应于 PAGE_EXECUTE_READWRITE 的页面访问保护值。在下面的来自 ProcessHacker 的 Poison Ivy 植入的内存布局的屏幕截图中,您可以看到它分配了多个这些 RWX 节。

典型的代码节类型为“映像”,并映射到磁盘上的文件。但是,这些代码节的类型为“私有”,不映射到磁盘上的文件。因此,它们被称为未备份的可执行节或浮动代码。从这些类型的内存区域开始的线程是异常的,并且是恶意活动的一个很好的指标。ProcessHacker 还可以向您显示恶意软件线程的调用堆栈。调用堆栈中有多个函数不映射到与已加载模块关联的内存。

反射 DLL 注入

反射 DLL 注入最初由 Steven Fewer 开发,是另一种类型的内存攻击者技术。Metasploit 的 Meterperter 有效负载是首次尝试完全武器化该技术的尝试之一,但许多恶意软件家族今天都在使用它。反射 DLL 注入的工作原理是创建一个 DLL,当执行该 DLL 时,它会自行映射到内存中,而不是依赖于 Windows 加载程序。注入过程与 shellcode 注入相同,只是 shellcode 被自映射 DLL 取代。添加到 DLL 的自映射组件负责解析导入地址、修复重定位和调用 DllMain 函数。攻击者可以从能够使用更高级的语言(如 C/C++)而不是汇编语言进行编码中获益。

经典反射 DLL 注入(例如 Meterpreter 使用的注入)很容易被猎手发现。它在进程中留下大量的 RWX 内存节,即使 Meterpreter 会话已关闭也是如此。这些未备份的可执行内存节的开头包含完整的 MZ/PE 标头,如下面的图像所示。但是,请记住,其他反射 DLL 实现可能会擦除标头并修复内存泄漏。

加载到内存中的 DLL 还会方便地导出一个名为 ReflectiveLoader() 的自描述函数。

内存模块

内存模块是另一种内存驻留攻击者技术。它类似于反射 DLL 注入,只是注入器或加载器负责将目标 DLL 映射到内存中,而不是 DLL 自行映射。本质上,内存模块加载器重新实现 LoadLibrary 函数,但它在内存中的缓冲区上工作,而不是在磁盘上的文件上工作。最初的实现旨在映射到当前进程中,但更新的技术可以将模块映射到远程进程中。大多数实现都尊重目标 DLL 的节权限,并避免嘈杂的 RWX 方法。

NetTraveler 是一种使用内存模块样式技术的恶意软件家族。当 NetTraveler 启动时,它会解压缩核心功能并将其映射到内存中。页面权限更类似于合法的 DLL,但是内存区域仍然是私有的,而不是映像。

活动线程的起始地址位于这些私有区域。调用堆栈也显示了这些恶意节。

Winnti 是另一个使用内存模块技术的恶意软件样本。正如您在下面看到的,它们在第一页的节权限上略有失误。

但是,Winnti 样本值得注意,因为它擦除了 DLL 中的 MZ/PE 标头,从而使其更难检测。

进程空洞

进程空洞是攻击者用来防止其恶意软件被安全产品和猎手检测到的另一种技术。它涉及创建一个挂起的进程,从该进程中取消映射(空洞化)原始可执行文件,将新的有效负载分配并写入该进程,使用 SetThreadContext 将原始线程的执行重定向到新的有效负载,最后调用 ResumeThread 以完成。更隐秘的变体使用 Create/Map 节 API 来避免 WriteProcessMemory。其他变体使用跳转来修改入口点,而不是使用 SetThreadContext。

DarkComet 是使用进程空洞技术的众多恶意软件家族之一。可以使用多个工件来检测进程空洞。此活动的一个明显线索是使用 CREATE_SUSPENDED 标志生成的进程,如以下 DarkComet 样本的屏幕截图所示。

模块覆盖

到目前为止,讨论的所有技术都导致了未映像备份代码的执行,因此相当容易检测。另一方面,模块覆盖避免了此要求,从而使其更难检测。此技术包括将未使用的模块映射到目标进程中,然后使用其自身的有效负载覆盖该模块。Flame 是第一个广泛宣传的使用此技术的恶意软件家族。最近,Careto 和 Odinaff 恶意软件家族使用了模块覆盖技术。可以使用各种技术来可靠地检测模块覆盖,这涉及将内存与磁盘上的关联数据进行比较。

GARGOYLE

Gargoyle 是一种概念验证技术,用于内存驻留恶意软件,可以逃避许多安全产品的检测。它通过设置只读页面保护来实现这一壮举,从而保持休眠状态。然后,它会定期使用异步过程调用唤醒,并执行 ROP 链,将其有效负载标记为可执行,然后再跳转到该有效负载。有效负载执行完成后,Gargoyle 会再次屏蔽其页面权限并返回休眠状态。检测这种攻击者技术的一种方法是检查线程和用户 APC,寻找 ROP 链的证据。

检测内存中的攻击

鉴于这些技术的普及和可访问性,安全人员必须警惕基于内存的攻击者技术,并积极在其网络上搜寻这些技术。然而,大多数产品无法大规模通用地检测内存中的攻击,这使得防御者在防御这些攻击的能力方面存在巨大差距。Endgame 进行了大量研究,将低噪音检测功能引入我们的产品,用于上述每种方法。

鉴于此检测差距的巨大规模和影响,重要的是要提高所有人的能力,而不仅仅是我们的客户。因此,我们与 Jared Atkinson 合作开发了他的 powershell 工具 Get-InjectedThreads,该工具实现了一种相对低噪音的内存威胁检测方法。它会扫描系统上的活动线程,寻找可疑的起始地址。攻击者可以利用它来扫描其网络中的主机,并快速识别许多内存驻留恶意软件技术。该脚本的工作原理是使用 NtQueryInformationThread 函数查询每个活动线程,以检索其起始地址。然后,使用 VirtualQueryEx 函数查询起始地址,以确定关联的段属性。如果线程启动的内存区域是未备份且可执行的(即,不是图像类型并且设置了执行位),则该线程被视为已注入。以下屏幕截图显示了在感染了 9002 RAT 示例 的系统上运行时的一个检测示例。

该脚本将捕获各种利用 shellcode 注入、反射 DLL、内存模块和某些进程掏空技术的恶意软件家族。但是,它不能替代全面阻止内存中攻击的安全产品,例如 Endgame。

大规模企业级内存检测

Endgame 已将每种这些技术(以及更多技术)的检测功能构建到我们的企业安全平台中,从而提供市场上最佳的定位内存中威胁的能力。我们不只是依赖诸如监控众所周知的系统调用序列进行进程注入之类的简单方法,而是有效地分析内存以查找所有已知的逃避功能。这为我们的用户提供了有关注入代码的线程级可见性,以及复杂的后续操作,例如检查注入的代码并仅暂停恶意注入的线程以修复威胁。我们的平台在实时阻止注入发生方面以及定位已驻留在内存中的对手方面都非常有效,可以在几秒钟内定位数万台主机上的威胁。

与任何无特征检测技术一样,误报(FP)是一个重要的考虑因素。当我们研究并实施针对上述每种攻击者技术的基于技术的防御措施时,我们最初在每一步都遇到了 FP。在我们的产品中正确处理这些问题至关重要。

大多数 FP 与安全软件、即时 (JIT) 编译的代码或受 DRM 保护/打包的应用程序有关。安全产品有时会向系统上的某些或所有进程注入代码,以增强其行为检测能力。缺点是如果产品的方法马虎,实际上可能会 损害 系统的安全性,并使寻找真正的内存威胁变得更加困难。JIT 代码是另一个可能出现误报的区域,它会在运行时生成汇编代码,这些代码位于未备份或浮动的内存区域中。 .NET 或 Java 应用程序是使用 JIT 技术的一些示例。幸运的是,这种类型的代码比恶意安全产品更容易识别和过滤。最后,应该牢记使用数字版权管理 (DRM) 方案打包或保护的应用程序。这些应用程序可能会在内存中解密或反混淆其核心功能,以阻止调试和逆向工程。但是,恶意软件也使用相同的技术来逃避检测并阻止安全从业人员进行分析。

通过仔细的设计决策和广泛的测试,我们成功地实现了非常低的误报率,从而使 Endgame 用户能够快速清除内存中的威胁。

结论

攻击者将继续创新新技术以避免检测并实现其目标。内存驻留技术也不例外,并且十多年来一直是终端安全防御者的眼中钉。幸运的是,通过了解最新的技术,我们可以扭转局面,并利用这些知识来开发新的高保真检测方法。在 Endgame,我们对这些攻击的全面方法使我们在无文件攻击检测方面处于市场领先地位(添加到我们的其他关键技术中)。有关搜寻内存中攻击的更多信息,请查看我们在 SANS 威胁搜寻和 IR 峰会演示中的 幻灯片