Joe Desimone

搜寻内存中的 .NET 攻击

作为我对 DerbyCon 演示的后续,这篇文章将研究一种新兴趋势,即攻击者使用基于 .NET 的内存技术来逃避检测。

阅读需要 8 分钟安全研究
Hunting For In-Memory .NET Attacks

在过去的博客文章中,我们分享了我们用于搜寻传统内存攻击的方法,以及对许多注入技术的深入分析。作为我对 DerbyCon 演示的后续,这篇文章将研究一种新兴的趋势,即攻击者使用基于 .NET 的内存技术来逃避检测。我将讨论这些 .NET 技术的事件(实时)和按需检测策略。在 Endgame,我们理解这些不同的检测和预防方法是互补的,并且共同构成了针对内存攻击的最强大防御。

.NET 的诱惑

在内存中使用 .NET 技术,甚至使用标准的 .NET 应用程序,对攻击者有几个吸引人的原因。首先也是最重要的是,所有 Windows 版本都预安装.NET 框架。这很重要,因为它使攻击者的恶意软件在受害者中具有最大的兼容性。其次,.NET PE 元数据格式本身相当复杂。由于资源限制,许多端点安全供应商对这些应用程序的托管 (.NET) 结构的洞察力有限,仅限于与普通的、非托管(非 .NET)应用程序共享的内容。换句话说,大多数 AV 和安全产品都不能很好地防御恶意的 .NET 代码,而攻击者也知道这一点。最后,.NET 框架具有内置功能,可以通过 Assembly.Load(byte[]) 函数(及其各种重载)动态加载仅限内存的模块。此功能允许攻击者轻松制作加密器/加载器,将其有效负载保留在磁盘外,甚至绕过应用程序白名单解决方案(如Device Guard)。由于 Assembly.Load 函数支持强大的攻击者功能集,因此本文重点关注它。

.NET 攻击者技术

攻击者利用 .NET 内存技术并非完全新鲜。然而,在过去的六个月里,我注意到了一种明显的技巧提升,我将简要讨论一下以说明其危险性。例如,在 2014 年,被怀疑在中国活动的威胁组织 DEEP PANDA 被观察到使用了用 .NET 编写的多阶段 MadHatter 植入程序。更值得注意的是,此植入程序仅在多阶段 Assembly.Load 引导过程(从 PowerShell 开始)之后才存在于内存中。PowerShell 可以直接调用 .NET 方法,Assembly.Load 函数也不例外。它就像调用 [System.Reflection.Assembly]::Load($bin) 一样简单。最近,OilRig APT 组织使用了一个名为 ISMInjector 的打包 .NET 恶意软件样本来逃避基于签名的检测。在解包例程期间,该样本使用 Assembly.Load 函数来访问嵌入的下一阶段恶意软件,称为 ISMAgent

第三个例子,对于红队来说比较熟悉,是 ReflectivePick,由 Justin WarnerLee Christensen 开发。ReflectivePick 允许 PowerShell Empire 将 PowerShell 注入并引导到任何正在运行的进程中。它利用 Assembly.Load() 方法加载 PowerShell 运行器 DLL,而无需将其放到磁盘上。下图显示了他们工具的相关源代码。

需要指出的是,Assembly.Load 作为 .NET 框架的核心功能,经常在合法程序中使用。这包括内置的 Microsoft 应用程序,这导致了一系列有趣的防御逃避和应用程序白名单绕过。例如,Matt Graeber 发现了一种 Device Guard 绕过,它以竞争条件为目标来劫持对 Assembly.Load 的合法调用,允许攻击者在受 Device Guard 保护的主机上执行任何未签名的 .NET 代码。由于难以修复这种技术,微软目前已决定不处理此问题,这为攻击者留下了一个方便的“永远存在漏洞”,以针对使用应用程序白名单加固的主机。

Casey Smith 还发布了大量关于绕过应用程序白名单解决方案的研究。这些技术中的许多技术,其核心是针对使用攻击者提供的代码调用 Assembly.Load 方法的签名 Microsoft 应用程序。一个例子是 MSBuild,它预安装在 Windows 上,并允许攻击者在合法且已签名的 Microsoft 进程中执行未签名的 .NET 代码。这些技术不仅对以应用程序白名单保护的环境为目标的攻击者有用。由于它们允许以非常规方式将攻击者代码加载到合法的签名进程中,因此大多数防病毒和 EDR 产品都看不到攻击者的活动,并且可以被绕过。

最后,James Forshaw 开发了 DotNetToJScript 技术。其核心是,此技术利用 BinaryFormatter 反序列化方法仅使用 JScript 加载 .NET 应用程序。有趣的是,此技术在底层会调用 Assembly.Load 方法。DotNetToJscript 为以隐秘方式执行未签名的 .NET 代码打开了许多新的巧妙技术的大门。例如,James 演示了如何将 DotNetToJScript 与 com 劫持和 Casey 的 squiblydoo 技术相结合,将代码注入到受保护的进程中。在另一个例子中,Casey 在 universal.js 中将 DotNetToJScript 武器化,以执行任意 shellcode 或 PowerShell 命令。

可以滥用以隐秘方式执行攻击者代码的 Microsoft 签名应用程序的数量令人眼花缭乱。幸运的是,社区已迅速在许多地方公开记录和跟踪它们。一个很好的参考资料是 Oddvar Moe 的 UltimateAppLockerByPassList,另一个是微软自己的参考资料

检测 .NET 攻击

正如这些示例所示,攻击者正在以各种方式利用 .NET 来击败和逃避端点检测。现在,让我们探索两种检测这些攻击的方法:按需技术和基于实时技术。

按需检测

按需检测利用了时间型数据收集中的快照。当攻击发生时,您不需要持久运行和收集数据的代理,但是您需要在搜寻/收集期间运行恶意代码。诀窍是关注可以捕获与攻击者无关的技术的高价值数据,并且具有高信噪比。一个例子是用于检测传统非托管内存注入技术的 Get-InjectedThread 脚本。为了演示检测 .NET 恶意软件对 Assembly.Load 函数的使用情况,我利用了由 Will Schroeder 等人开发的 PowerShell Empire。Empire 允许您通过远程引导 PowerShell 将代理注入到任何进程中。如下所示,在注入后,calc.exe 加载了 PowerShell 核心库 System.Management.Automation.ni.dll。

仅此一点就很有意思,但令人惊讶的是,有大量合法的应用程序会加载 PowerShell。 将此与进程网络活动相结合,并在所有数据中查找异常值,可能会获得更好的效果。 经过更深入的检查,我们发现了一些更有趣的东西。 如下所示,内存段 0x2710000 包含完整的 .NET 模块(存在 PE 标头)。 内存区域的特性有点不寻常。 类型为 MEM_MAPPED,尽管没有关联的文件映射对象(请注意 ProcessHacker 中的“使用”字段为空)。 最后,该区域具有 PAGE_READWRITE 的保护,但令人惊讶的是,它不是可执行的。 这些内存特性是使用 Assembly.Load(byte[]) 方法加载纯内存模块的副作用

为了自动化这种类型的搜索,我编写了一个名为 Get-ClrReflection 的 PowerShell 函数,它会查找这种内存特性组合,并将保存任何匹配项以供进一步分析。 以下是在针对感染了 Empire 的工作站运行该函数后的示例输出。

同样,您将看到利用 Assembly.Load 函数的合法应用程序的匹配项。 一个常见的误报是 XmlSerializer 生成的程序集。 标准搜索实践适用。 按进程名称或更好的是使用模糊哈希匹配来对匹配项进行分类。 例如,ClrGuard(详细信息见下文)将为您提供带有“-f”开关的 TypeRef 哈希。 以下是来自 Empire 的示例。

基于事件的检测

基于事件的检测非常棒,因为您不需要在搜索时碰巧遇到正在活动的攻击者。 它还让您有机会实时阻止攻击者技术。 为了提供 .NET 运行所在的 CLR 信号,我们开发并发布了 ClrGuard。 ClrGuard 将挂钩系统上的所有 .NET 进程。 从那里,它会内联挂钩本机 LoadImage() 函数。 这是 CLR 底层 Assembly.Load() 调用的内容。 当观察到事件时,它们会通过命名管道发送到监视进程,以进行进一步的检查和缓解决策。 例如,可以立即检测到 Empire 的 psinject 函数,并可以实时阻止,如下面的图像所示。

以类似的方式,可以快速检测并阻止 OilRig 的 ISMInjector。

下面的另一个示例显示了 ClrGuard 针对 Casey Smith 的 universal.js 工具的操作。

虽然我们不建议您在整个企业中运行 ClrGuard(它是概念验证级),但我们希望它能激发社区针对这些类型的 .NET 攻击进行讨论和创新。 这些类型的防御技术为整个 Endgame 产品提供保护,并且企业级类似 ClrGuard 的功能即将推出。

结论

重要的是要感谢那些进行出色的攻击性安全研究的人员,他们愿意为了社区的更大利益而发布他们的能力和技术。 近期 .NET 内存攻击的进步表明,防御者是时候提升自己的水平,与更高级的红队和对手正面交锋了。 我们希望 ClrGuard 和 Get-ClrReflection 有助于平衡风险。 这些工具可以提高防御者对 .NET 恶意软件活动的洞察力,并提高对此类最新演变的攻击者技术的可见性。