通过代理实现代码执行——DLL劫持的全新视角

本文深入探讨了一种新型DLL代理攻击技术,通过分析Microsoft Teams和Outlook中的漏洞实现低权限代码执行。文章详细介绍了攻击原理、武器化方法以及微软的回应,并提供了自动化工具FaceDancer的实现方案。

通过代理实现代码执行——DLL劫持的全新视角

在不断发展演变的网络安全领域,攻击者不断设计新方法来利用端点漏洞执行恶意代码。最近越来越流行的一种方法是DLL劫持。虽然DLL劫持攻击可以采取多种不同形式,但本文将探讨一种称为DLL代理的特定攻击类型,深入分析其工作原理、潜在风险,并简要介绍发现这些易受攻击DLL的方法论,这导致了多个零日漏洞DLL的发现,微软已承认这些漏洞但目前选择不修复。在讨论方法论的同时,我们还将研究如何轻松武器化这些DLL以进行隐蔽攻击。

什么是DLL劫持?

DLL劫持包含多种不同技术,包括DLL侧劫持和侧加载,但从高层次来看,DLL劫持利用了Windows应用程序搜索和加载DLL的方式。当进程执行时,它会加载一系列DLL以正常运行。有时进程会在端点上多个位置查找正确的DLL,而在其他情况下,DLL可能根本不存在。通过将恶意DLL放置在进程首先查找的位置,攻击者可以诱骗进程加载他们的DLL而不是合法的DLL,从而允许攻击者以运行应用程序的相同权限执行任意代码。

这种技术在规避安全控制(如应用程序允许列表)甚至端点安全控制方面非常有效,因为有效(较少受审查)的应用程序会作为应用程序标准运行时过程的一部分加载这些DLL。此外,通过利用易受攻击的DLL,攻击者可以避免使用任何Living off the Land二进制文件(LOLbins)来执行其恶意DLL,这些二进制文件已成为许多基于检测的产品的焦点。

虽然非常有效,但这种技术也有其缺陷。通过劫持必需的DLL,攻击者可能使进程不稳定,或者在大多数情况下导致应用程序功能缺失,从而破坏操作。这可能引起用户或系统管理员不必要的关注,特别是在攻击者试图隐蔽时。另一个问题是,进程检查DLL的大多数文件夹需要提升权限才能写入。因此,我开始研究实现此类攻击的替代方法,这引导我进入了一个巨大的研究兔子洞,最终发现了我喜欢称之为DLL代理攻击的技术。

什么是DLL代理攻击?

DLL代理采取了与传统DLL劫持不同的方法。DLL代理不利用进程的搜索顺序,而是依赖两件事。首先是DLL所在文件夹的访问控制配置错误,允许任何用户写入该文件夹的内容。这允许攻击者将DLL放入与易受攻击DLL相同的文件夹中。

现在,同一文件夹中不能有两个同名DLL,因此利用此写入权限,我们可以将DLL重命名为任意名称。这对于第二部分——代理方面很重要。这种技术背后的想法仍然是允许访问我们目标DLL中的函数。为此,我们需要将所有流量从恶意DLL转发到合法DLL;这确保我们不会破坏应用程序的操作。当应用程序尝试加载DLL时,它将加载恶意DLL,从而有效允许我们的恶意代码运行,同时将任何函数请求转发到合法DLL而不会中断或崩溃。这使我们的恶意DLL成为应用程序和合法DLL之间的代理。

图1 – DLL代理攻击

DLL代理攻击非常有效,因为它们不需要提升权限即可执行。通常,当程序安装DLL时,这些文件被放置在具有严格安全权限的目录中。这些权限确保只有具有管理权限的用户才能写入或重命名这些目录中的文件。这种保护机制至关重要,因为它可以防止低权限用户将恶意DLL引入存储合法DLL的文件夹,从而保护系统免受潜在劫持尝试。

发现它们

识别易受DLL代理攻击的DLL类似于查找可劫持的DLL。我们需要查找进程首次执行时加载的任何DLL。但是,我们不是寻找缺失的DLL或不同路径中的DLL,而是查找在运行时加载的DLL并审查文件夹权限。我们通过过滤掉所有我们知道默认受保护的位置(如System32和任何程序文件文件夹)来做到这一点,这些位置不允许低权限用户写入。

用于此目的的一个有效工具是Process Monitor,这是一个用于Windows的免费工具,可监视和显示实时文件系统、注册表和进程/线程活动。Process Monitor可用于观察应用程序的"Load Image"事件,这些事件在应用程序加载DLL时发生。通过过滤掉特定文件位置,可以识别可能被代理的DLL。

图2 – 搜索过滤器

开始狩猎时,我们启动应用程序。对于Microsoft Office产品,其他应用程序之间存在许多交叉兼容性和支持,特别是Outlook和Teams。通过监视这些应用程序,我注意到Outlook会从AppData加载几个DLL。深入研究这些事件,我发现了易受攻击的DLL(用于代理)存在于Microsoft Teams版本2(又名Microsoft Teams for Work and School)和Microsoft Teams Classic中。

当Microsoft Teams v2配置用户配置文件时,它会将名为TeamsMeetingAddin的包安装到Outlook中(如果安装了Outlook)。包含此插件相关DLL的文件夹可由低权限用户修改,以重命名合法DLL并添加恶意DLL。这意味着下次启动Outlook时,恶意DLL将被Outlook加载,导致在Outlook进程中执行代码。此目录中的所有文件都可以由低权限用户修改。

图3 – Process Monitor结果 – Outlook.exe

Windows中的AppData文件夹是一个隐藏的系统目录,用于存储单个用户帐户的应用程序特定数据和设置。Windows系统上的每个用户帐户都有自己的AppData文件夹,这确保应用程序数据为每个用户保持分离和安全。因为它专注于用户的数据,所以用户本身有权写入AppData中的任何内容。这使其成为托管恶意代码的完美场所,也是托管进程使用的合法DLL的非常糟糕的地方。如下所示,存在"TeamsMeetingAddin"的文件夹可由我们的低权限用户写入。

图4 – OneAuth.dll的安全权限

现在我们有一个我们知道在执行时加载的DLL,文件夹权限允许我们写入新的DLL,并且我们可以重命名该文件夹中的任何DLL。下一步是创建代理功能。这就是定义文件(.def)发挥作用的地方。定义文件是包含一个或多个模块语句的文本文件,这些语句描述DLL的各种属性。使用.def文件,我们可以定义所有导出的函数并将它们映射到包含请求函数的合法DLL。因此,我们可以将合法DLL重命名为任意名称(在下面的示例中,我们将-legitimate附加到名称),将我们的DLL放在同一文件夹中,当进程加载它时,它将下面概述的函数的任何请求代理到合法DLL的请求。

图5 – 示例 – Def文件

因此,只有一个DLL被加载(不是OneAuth.dll和OneAuth-legitimate.dll),但当我们查看DLL的导出函数时,我们可以看到每个代理函数都回调到OneAuth-legitimate.dll。在下面的示例中,我们的OneAuth.dll将弹出一个简单的hello world语句,显示我们的DLL已加载。当我们深入探讨这一点时,我们可以看到合法的DLL在导出中被引用。

图6 – 概念证明 – Outlook弹出"Hello World"消息 图7 – 我们的恶意OneAuth.dll将函数代理到合法DLL

我观察到以下DLL易受此攻击。

Microsoft Teams V2或Microsoft Teams for Work或School

C:\Users\{username}\AppData\Local\Microsoft\TeamsMeetingAddin\{version}\x64\OneAuth.dll

注意:在审查此插件的许多不同版本时,我发现根据版本,文件夹名称可以从TeamsMeetingAddin更改为TeamsMeetingAdd-in。我无法得到关于为什么会发生这种情况的直接答案,但这似乎是Microsoft开发人员的偏好。(我们将在第二部分中更多讨论这方面)

Microsoft Teams V1或Microsoft Teams Classic

C:\Users\{username}\AppData\Local\Microsoft\Teams\current\ffmpeg.dll

C:\Users\{username}\AppData\Local\Microsoft\Teams\current\resources\app.asar.unpacked\node_modules\slimcore\bin\SlimCV.dll

武器化它们

一旦我们的DLL加载到进程中,我们需要一些东西来触发我们的代码。由于我们将函数代理到合法DLL,运行恶意代码的唯一方法是将其放在DLLMain函数中。不幸的是,直接从DLLMain运行shellcode可能会出现问题,特别是对于DLL劫持攻击,具体是进程死锁。Microsoft有关于DLL最佳实践的文档(如果您有兴趣进一步阅读,可以在这里找到)。他们的建议之一是"推迟DllMain中任何可以等到稍后的调用。“这个陈述给了我一个想法,即创建一个单独的线程,然后使其睡眠10秒。这确保我们的恶意代码仅在进程中的所有其他内容加载后运行。通过这样做,我们可以帮助保持低调,因为从用户的角度来看,服务或功能没有中断。

图8 – 睡眠延迟代码

DLL代理攻击的影响

DLL代理攻击的影响可能很大,因为它们允许攻击者绕过各种安全控制。关键影响之一是能够绕过应用程序允许列表。应用程序允许列表是一种安全实践,其中只有预先批准的应用程序被允许在系统上运行。由于DLL代理攻击中的恶意代码由合法的允许应用程序加载,因此通常可以逃避检测。此外,这些攻击不需要任何特殊权限,使它们成为初始访问的完美方法。

微软的回应

截至目前,微软没有计划修复或补救这些问题,但承认它们是有效的漏洞。他们的官方回应是:

我们确定您的发现是有效的,但不符合我们立即服务的要求,因为即使与此插件关联的DLL,它也只提供低/中等风险。但是,我们已将您的发现标记为未来审查,作为改进我们产品的机会。我没有此审查的时间表。由于目前不需要进一步操作,我正在结束此案例。

继续这项研究

虽然来自微软的消息并不理想,但在审查一些文档后,我发现Microsoft Outlook和Microsoft Teams Classic正在被其新对应物olk.exe和ms-teams.exe(又名Microsoft Teams V2)淘汰。经过一些调查,我发现新版本包含几个安全控制,防止中等完整性和提升的用户访问这些产品的安装路径,保护其免受DLL侧加载和劫持攻击。虽然这些控制已到位,但可以绕过这些控制,并仍然使用注册表让这些应用程序从端点上的任何位置加载恶意DLL。

首先,我们可以看到这些应用程序安装在与以前安装不同的目录中。此路径"C:\Program Files\WindowsApps"似乎被严重锁定。通过尝试访问文件夹以查看内容,即使以管理员身份运行,我们也被拒绝访问。

图9 – Outlook OLK.exe文件路径 图10 – 管理员无法查看文件夹内容

由于这些应用程序没有任何驻留在用户控制区域(即Appdata)的第三方或外部插件,因此不可能以传统意义进行任何DLL劫持攻击。即使具有提升的权限,也不可能访问或写入这些文件夹。这降低了使用传统方法利用这些应用程序的可能性。但是,如果我们使用Process Monitor监视这些应用程序启动,我们可以看到这些应用程序使用COM加载几个系统DLL。

COM对象(组件对象模型对象)是Microsoft框架的关键部分,用于使软件组件能够相互通信,无论它们是用何种语言编写的。COM对象支持诸如进程间通信、版本控制和动态对象创建等功能,这些对于在Windows操作环境中构建复杂的分布式系统和应用程序至关重要。在这种情况下,这些对COM的查询用于查找某些系统DLL的路径,然后加载。使这些请求有趣的是,它们首先检查注册表的当前用户(HKCU)部分;但是,它们无法找到正确的注册表值,然后回退到存在条目的注册表的另一部分。

图11 – 跟踪OLK.exe的RegOpenKey操作 图12 – 包含DLL信息的注册表键

Windows中的HKEY_CURRENT_USER(HKCU)注册表配置单元是一个关键组件,存储特定于当前登录用户的配置设置和首选项。它包括用户特定的软件设置、用户界面配置和网络连接等信息,为系统上的每个用户启用个性化体验。通过将这些设置与HKEY_LOCAL_MACHINE(HKLM)中更广泛的系统范围配置隔离,HKCU确保一个用户所做的更改不会影响其他用户。这意味着当前运行的用户可以读取和写入注册表键,即使是低权限用户。因此,通过添加包含进程在HKCU\SOFTWARE\Classes\CLSID\中查找的DLL的COM ID的注册表键,可以使此进程从WindowsApps或System32文件夹外部加载DLL。

图13 – CLSID文件夹的权限 – 允许低权限用户访问

因此,任何时候应用程序运行,进程将以编程方式加载我们的DLL,而不是在"C:\Windows\System32"中找到的系统版本。虽然这是一个例子,但许多应用程序和DLL易受此攻击,因为应用程序首先在注册表的HKCU部分中查找。

图14 – OLK.exe成功查询HKCU COM对象

从下面的图像中可以看到,这有效,我们能够强制新版本的Outlook加载我们的DLL。虽然我们只披露了这些存储在锁定的WindowsApp文件夹中的新应用程序,但这个问题实际上更广泛,影响许多其他应用程序。

图15 – 加载我们的DLL,弹出消息窗口

为了撒下广泛的网,我们可以再次使用Process Monitor,过滤只查找以"HKCU"开头且结果为"Name Not Found"的任何RegOpenKey操作。通过监视这一点,我们可以看到哪些其他应用程序在HKCU中查找我们可以劫持的COM对象。在几个小时的监视过程中,发现许多本机Windows系统的应用程序依赖查询这些COM对象来加载DLL。

图16 – Process Monitor显示其他进程执行相同行为

有了这个广泛的COM对象UUID列表和上述步骤,我们可以创建许多映射到不同DLL的POC DLL。通过将这些DLL和注册表键部署在具有通常在企业中找到的众多应用程序的端点的HKCU\SOFTWARE\Classes\CLSID\部分中,我们可以观察哪些其他应用程序加载这些DLL。结果是更多本机Windows和其他应用程序。通过监视包含我们的POC DLL的文件夹的任何Load Image操作,我们可以看到这一点。

图17 – 进程加载我们的POC DLL

付诸行动

现在编译和设置这些DLL的过程可能有点繁琐,因此我创建了一个名为FaceDancer的工具来帮助自动化此过程。在下面的示例中,我将选择仅针对进程msedge。使用我选择的任何DLL有效负载(在这种情况下,我使用Cobalt Strike生成的普通DLL – 无规避),我可以将其输入此工具,它将生成以下内容:

我需要更新的注册表键设置。 一个将使用COM代理msedge加载的DLL执行的DLL。

图18 – FaceDancer生成DLL

一旦设置了注册表键,只需等待新实例msedge.exe执行:

图19 – Msedge加载我们的DLL 图20 – 我们的DLL使用Cobalt Strike回连

微软的第二次回应

我们再次联系微软,强调这些问题的重要性。微软回应如下:

“经审查,这不符合MSRC服务的DLL种植问题的任何类别。对于攻击者利用此在机器上获得代码执行,他们必须已经在机器上具有代码执行”

这是什么意思?微软不承认这些问题符合他们认为是DLL劫持的要求。微软有自己的术语称为DLL种植,涵盖种植/劫持/预加载DLL攻击。他们主要认为它是DLL种植,如果:

应用程序从 unsafe 位置搜索并加载DLL。 DLL不位于应用程序期望的目录中,导致Windows搜索其他目录。 攻击者可以将恶意DLL放置在合法DLL之前搜索的目录中。

截至目前,微软将不会修复或采取措施缓解此问题。这对企业意味着什么?不幸的是,这些漏洞将作为永久日保留,直到微软改变主意承认这些漏洞值得修复。由于这些进程是本机Windows和其他应用程序(如Outlook和Teams)的一部分,这些应用程序是日常业务的关键部分,因此防御者不可能阻止这些应用程序。由于所有这些,唯一可以部署的防御措施是基于检测的。

披露时间线

4月17日 – 向微软披露第一个发现。 4月25日 – 收到微软的以下回应,声明这是一个有效的零日漏洞但不会修复。 4月26日 – 请求审查他们的立场并提供更多信息。 4月26日 – 收到消息,不会采取进一步行动,也不会进行CVE识别。 7月24日 – 向微软披露第二个发现。 8月1日 – 案例关闭。

有关FaceDancer的更多信息可以在这里找到:https://github.com/Tylous/FaceDancer

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计