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

本文深入探讨了DLL代理攻击技术,通过分析Microsoft Teams和Outlook中的漏洞,展示了如何利用文件夹权限和COM对象注册表项实现低权限代码执行,并介绍了自动化工具FaceDancer。

通过DLL代理实现代码执行——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之间的代理。

图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 or 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可能会出现问题,特别是进程死锁。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确保一个用户所做的更改不会影响其他用户。这意味着当前运行用户可以读取和写入注册表键,即使是低权限用户。因此,通过添加包含进程正在寻找的DLL的COM ID的注册表键在HKCU\SOFTWARE\Classes\CLSID\中,可以使此进程从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加载的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 设计