分析DLL搜索顺序劫持的原理

分析DLL搜索顺序劫持的原理

Context的智能和响应团队已经看到DLL搜索命令被滥用,作为在真实环境中进行网络入侵的一种手段。滥用DLL搜索顺序并利用这种机制来加载一个流氓DLL而不是合法的被称为DLL预加载,或者在MITRE ATT&CK框架中劫持。

在这篇文章中,你将了解更多关于DLL搜索顺序的基本原理,以及合法的二进制文件如何被武器化,并介绍一个通过DLL劫持自动发现适合有效载荷执行的二进制文件的工具。

关于动态链接库

动态链接库(DLL)是一个模块,它包含可以被另一个模块(应用程序或DLL)使用的函数和数据。这些函数从库文件中导出,以供依赖于它们的应用程序或DLL使用。为了使用这些函数,应用程序必须从库文件中导入它们。应用程序从模块导入函数有两种方式:隐式(加载时动态链接)和显式(运行时动态链接),奇热让我们各看看。

隐式链接(加载时动态库链接)

当一个应用程序被打开时,Windows加载器采取步骤在内存中映射应用程序的可执行映像,并最终启动一个托管并执行其代码的进程。在加载过程中,加载器解析可执行映像的导入表,以便将导入的模块(动态链接库)映射到该进程的地址空间中。

可执行映像可能嵌入了描述Windows并行程序集上依赖关系的清单。在加载导入的DLL之前,并行管理器(SxS Manager)检查这个可执行文件的清单文件中存在的任何依赖项是否得到满足。如果是,则从路径中加载所需的模块。

对于其余的导入模块,加载程序首先检查由KnownDLLs注册表项(HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Session Manager \ KnownDLLs)设置的列表上是否存在要导入的所有DLL。如果是,加载程序将使用此注册表项指向的DLL的副本。否则,它将通过应用DLL搜索顺序来搜索模块。有关DLL搜索顺序的更多信息,请参见本文其他章节。

显式链接(运行时动态库链接)

应用程序可能需要使用DLL中的函数,这些函数在应用程序运行时动态加载。以这种方式加载DLL称为运行时DLL动态链接,这种类型的加载发生在应用程序调用LoadLibrary或LoadLibraryEx函数时。

这两个函数接受要加载的模块的名称,名称可以是模块的文件名,也可以是模块的完整路径。如果应用程序没有指定模块的完整路径,Windows加载程序将查找应用动态库搜索顺序的DLL。

DLL搜索顺序劫持及其识别方法

滥用DLL搜索顺序并利用这种机制使应用程序加载流氓DLL(而不是合法的DLL)被称为DLL预加载。之所以称为预加载,是因为攻击者可以将其DLL放在搜索顺序的前面,从而使应用程序加载此DLL,而不是合法的DLL。该技术在MITER ATT&CK框架(T1038)中记录为DLL搜索顺序劫持。在本文的以下各节中,我们演示如何滥用合法应用程序通过搜索顺序劫持来加载和执行Cobalt Strike信标有效载荷。

DLL搜索顺序劫持主要提供两个优点,使其成为一种有效的技术第一个优点是可以用来逃避检测。武器化的应用程序通常是合法的经过签名的二进制文件,可以通过调用此DLL导出的函数在其地址空间中加载恶意DLL。因此,为了执行恶意DLL,自动化沙箱必须首先确定要调用或执行无害二进制文件的导出函数,并设置环境以加载恶意DLL。

该技术提供的另一个优点是可以提升特权,当在其地址空间中加载DLL的合法应用程序以提升的特权运行时,在其上下文中执行的任何代码都将以相同的特权级别执行。这意味着有效载荷DLL及其实现的功能将以与加载它的进程相同的特权执行。

识别用于劫持的候选DLL有两种不同的方法静态分析和动态分析,就像恶意软件分析中采用的方法一样。动态分析包括执行应用程序和监视其加载的库。这可以通过监视API调用的工具(例如Procmon和API Monitor)来实现。静态分析方法包括使用IDA和Ghidra等反汇编工具来识别出现的特定API调用,而不执行应用程序。

这两种方法的主要区别在于,通过使用动态分析,可以显示用于加载时和运行时动态链接的大量候选DLL,而静态分析仅显示在运行时加载的候选DLL。

DLL搜索顺序

从Windows XP开始,启用SafeDllSearchMode选项时,模块将在加载时或运行时加载到应用程序的地址空间中,并且未明确指定模块的完整路径或者未声明清单文件在可以查找依赖项的位置,操作系统按照定义的搜索顺序搜索DLL,该DLL包含以下内容:

从中加载应用程序的目录

系统目录

16位系统目录

Windows目录

当前目录(除非另有说明,否则与第一个相同)

PATH环境变量中列出的目录

当未启用SafeDllSearchMode时以上搜索顺序略有不同,有关这方面的其他信息,请参阅Microsoft文档

当操作系统开始搜索应用程序导入的DLL时,除非指定了完整路径,否则首先搜索加载应用程序的目录。如果DLL不存在,接下来搜索系统目录,依此类推。当攻击者观察到应用程序的行为后,将他们自己的DLL放在搜索顺序的较早位置,以便应用程序加载该DLL而不是继续搜索时,就会发生滥用。Context的情报团队作为AVIVORE跟踪的威胁小组使用了这种技术,以实现在受害者环境中的有效载荷执行。

加载时动态链接的示例

为了说明加载时的加载情况,我们分析了一个已签名的Google可执行文件(GoogleCrashHandler-MD583bb030c71c9727dcfb2737005772c4e)Context的情报团队观察到该文件被用于入侵。

我们之所以关注此二进制文件,是因为它可以找到合适的候选人。这是什么意思呢?首先,它是来自受信任供应商的合法且经过签名的二进制文件。一旦执行了此应用程序,它将不显示可见窗口,并且在执行时终止,因此在执行此二进制文件时,不会使用户知道该二进制文件确实已在运行,并且进程不会停留在运行状态。最后一点同样重要,即使应用程序加载了恶意DLL,它也不会生成任何其他活动(例如弹出窗口),而这可能会引起用户的怀疑。因此,它可用作执行有效载荷DLL的杠杆。

为了识别此可执行文件尝试加载并可能被劫持的模块,我们将SysInternal的Procmon与以下过滤器一起使用

分析DLL搜索顺序劫持的原理

应用过滤器后,我们得到以下候选DLL

分析DLL搜索顺序劫持的原理

自动化DLL搜索顺序

为了武器化GoogleCrashHandler.exe,我们创建了一个自定义DLL,该DLL执行从CobaltStrike生成的beacon shellcode。我们将输出DLL命名为wkscli.dll,并将其放置在GoogleCrashHandler可执行映像所在的目录中。然后,我们打开了GoogleCrashHandler下一张图片显示恶意DLL被映射到GoogleCrashHandler的地址空间中,并且启动了一个信标。

分析DLL搜索顺序劫持的原理

运行时动态链接的示例

为了说明运行时加载,我们分析了一个经过签名的Microsoft可执行文件(OleView-MD5:d1e6767900c85535f300e08d76aac9ab)。已签名的可执行文件用于加载DLL,该DLL随后解密了PlugX有效载荷。

让我们与Procmon一起查看该可执行文件一旦启动即尝试加载的DLL

分析DLL搜索顺序劫持的原理

为了确认此DLL是动态加载的,而不是在加载时加载的,我们使用API Monitor。通过挂钩LoadLibrary和LoadLibraryEx API,我们观察到该应用程序尝试动态加载多个DLL

分析DLL搜索顺序劫持的原理

将从Procmon和API监视器获得的数据进行关联,应用DLL搜索顺序确定所搜索的DLL为ACLUI.DLL。我们可以通过分析Ghidra上的可执行文件来做同样的事情。在定义字符串部分(窗口->定义字符串)我们搜索字符串ACLUI。出现了三个结果:

分析DLL搜索顺序劫持的原理

然后,我们遵循对字符串ACLUI.DLL的引用,并最终完成对LoadLibraryW的调用

分析DLL搜索顺序劫持的原理

我们观察到LoadLibraryW API的参数不是完整路径,因此我们确认应用了DLL搜索顺序。

如果我们创建一个有效载荷DLL,将其放置在与可执行文件相同的目录中,然后运行该可执行文件,则会显示以下消息框:

分析DLL搜索顺序劫持的原理

这意味着可执行文件从我们的有效载荷DLL请求一个不存在的函数,为了允许我们的有效载荷从应用程序执行,我们必须导出函数EditSecurity。以下屏幕快照显示了使用C / C ++代码执行此操作的方法

分析DLL搜索顺序劫持的原理

自动化DLL搜索顺序

就像我们对GoogleCrashHandler图像所做的一样,我们创建了一个自定义DLL,该DLL执行从CobaltStrike生成的beacon shellcode。我们将输出DLL命名为ACLUI.DLL,并将其放置在与OleView.exe可执行映像相同的目录中。然后,我们打开OleView。下一张图片显示恶意DLL被映射到OleView的地址空间中并启动了一个信标。

分析DLL搜索顺序劫持的原理

缓解策略

基于我们所观察到的事件以及过去如何滥用DLL搜索顺序,我们可以推荐在这些环境中应用的特定最佳实践。这些建议旨在减少攻击面,限制潜在攻击的后果,并减少检测相关攻击所需的时间。

通常建议公司在其环境中部署功能和策略,作为功能的一部分,强烈建议部署事件检测和响应(EDR)软件。在策略方面,填充和维护授权在该环境中运行的所有应用程序的列表,并实现应用程序白名单,以防止不属于该列表的应用程序运行,这是一个很好的实践。为了检测流氓DLL,建议对环境中观察到的DLL进行频率分析。DLL的低频发生可能是值得进一步分析的指标。可以防止其他DLL劫持攻击的另一件事是启用SafeDllSearchMode并在系统上配置CWDIllegalInDLLSearch注册表。

软件开发人员也必须遵循最佳实践,例如,当应用程序在运行时加载模块时,建议为提供给LoadLibrary和LoadLibraryEx API的模块指定绝对路径,或使用API SetDllDirectory专门设置Windows加载器将从中加载提供的模块的路径。这样,就不会查找正常的搜索顺序。根据最佳实践,另一项建议是通过“应用程序清单”对加载的模块实施完整性检查。通过这样做,应用程序将防止恶意DLL的加载,并有可能将识别出的异常通知用户。

DLLHSC简介

DLLHSC是一个应用程序,旨在自动扫描提供的可执行映像,生成潜在顾客(以后可以手动评估)并报告利用DLL搜索顺序的潜在路径,最终目的是在地址空间中加载有效载荷DLL。通过搜索顺序劫持提供的图像。

操作模式

该工具实现3种操作模式,如下所述。

轻量级的模式

在内存中加载可执行映像,解析导入表,然后用有效载荷DLL替换导入表中引用的任何DLL。该工具将一个模块(DLL)放在应用程序目录中,该模块不存在于应用程序目录中,不属于WinSxS,也不属于KnownDLLs。

然后,它启动应用程序并报告是否执行了有效载荷DLL。有效载荷DLL在执行后会在路径C:\ Users \%USERNAME%\ AppData \ Local \ Temp \ DLLHSC.tmp中创建一个临时文件。如果临时文件存在,则表明扫描的应用程序可能被滥用。当某些可执行文件从它们加载的DLL导入函数时,当提供的DLL无法导出这些函数并因此满足提供的映像的依赖性时,可能会显示错误消息框。

但是,消息框表明如果满足依赖关系,DLL可能是有效载荷执行的好候选对象。在这种情况下,需要进行额外的分析。这些消息框的标题可能包含以下字符串:“找不到常规”或“找不到入口点” DLLHSC会查找包含这些字符串的窗口,并在出现这些窗口时立即关闭它们并报告结果。

模块列表模式

使用提供的可执行映像创建一个进程,枚举此进程的地址空间中加载的模块,并在应用过滤器后报告结果。

该工具仅报告从系统目录加载的模块,不属于KnownDLL。结果是需要进一步分析的线索。然后,分析人员可以将报告的模块放在应用程序目录中,并检查应用程序是否加载了提供的模块。

运行模式

通过Microsoft Detours(Detours是微软开发的一个函数库,可用于捕获系统API)挂钩LoadLibrary和LoadLibraryEx API时,并报告在运行时加载的模块。

每次扫描的应用程序调用LoadLibrary和LoadLibraryEx时,该工具都会拦截该调用,并将请求的模块写入文件C:\Users\%USERNAME%\AppData\Local\Temp\DLLHSCRTLOG.tmp中。如果使用标志LOAD_LIBRARY_SEARCH_SYSTEM32专门调用LoadLibraryEx,则不会将任何输出写入文件。完成所有拦截之后,该工具将读取文件并打印结果。对于进一步的分析,我们感兴趣的是KnownDLLs注册表键中不存在的模块、系统目录中不存在的模块以及没有完整路径的模块(对于这些模块,加载器应用正常的搜索顺序)。

你可以在我们的GitHub页面上找到DLLHSC的源代码以及x86和x64体系结构的编译二进制文件。