dll oem证书导入工具_探索DLL搜索顺序劫持的原理和自动化侦查方法

5915ad75a77f748571d4f61df644c723.png

7f02fc4ed8e09725c1ff7972ff9f8c93.png一、前言 在本篇文章中,将描述动态链接库(DLL)搜索顺序劫持的改建,以及攻击者可能如何将其用于Windows系统上的用户态持久性。这种技术可以对应到MITRE ATT&CK框架中的T1038:DLL搜索顺序劫持。 由于种种原因,DLL劫持对于攻击者来说很有帮助,但本文将重点介绍与自动启动应用程序结合使用的持久化用法。例如,在默认情况下,Slack和Microsoft Teams会在系统启动时运行,因此如果能将其中一个应用程序的DLL进行劫持,每当用户登录系统时,攻击者就可以持久访问其目标。 在介绍DLL、DLL搜索顺序和DLL劫持的概念之后,我们将探讨自动化DLL劫持侦查的方法。在这篇文章中,我们将介绍在Slack、Microsoft Teams和Visual Studio中如何侦查DLL劫持。 最后,我注意到,有许多DLL劫持是可以在不同应用程序之间共享的。我调查了其根本原因,发现如果应用程序没有位于C:WindowsSystem32路径下,使用特定Windows API调用的应用程序可能会存在DLL劫持的风险。 在这里,我要感谢我的同事Josiah Massari( @Airzero24 ),他在最初发现了一些DLL劫持事件,并在处理过程中阐述了他的方法,从而激发我研究自动化侦查的方法。   7f02fc4ed8e09725c1ff7972ff9f8c93.png二、关于DLL DLL是一个包含代码和数据的库,可以同时由多个程序使用。 Windows应用程序可以使用某一个 LoadLibrary* 函数来利用DLL中的功能。应用程序可以引用为该应用程序自定义创建的DLL,也可以引用位于System32路径下的已有DLL。开发人员可以定义应用程序从System32加载DLL,以使用Windows中已实现的功能,这样就不必再自行编写特定功能。 例如,如果应用程序需要发出HTTP请求,那么开发人员就可以利用WinHTTP库( winhttp.dll ),而不需要再使用原始套接字实现HTTP请求。   7f02fc4ed8e09725c1ff7972ff9f8c93.png三、DLL搜索顺序劫持 由于DLL在磁盘上以文件的形式存在,因此我们可能会产生疑问,应用程序怎么知道要从哪里加载DLL?Microsoft在这里完整记录了DLL的搜索顺序。 从Windows XP SP2开始,操作系统在默认情况下就已经启用了安全DLL搜索模式( HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerSafeDllSearchMode )。在启用安全的DLL搜索模式后,搜索顺序如下: 1、加载应用程序的目录; 2、系统目录,使用 GetSystemDirectory 函数获取该目录的路径; 3、16位系统目录,没有获取该目录路径的函数,但会对该目录进行搜索; 4、Windows目录,使用 GetWindowsDirectory 函数获取该目录的路径; 5、当前目录; 6、PATH环境变量中列出的目录,这里不包括 App Paths 注册表项指定的每个应用程序路径,在计算DLL搜索路径是不会使用到 App Paths 键。 在系统中可以包含同一个动态链接库(DLL)的多个版本。应用程序可以通过指定完整路径或使用其他机制(例如清单)来控制DLL的加载位置。 如果应用程序未指定从哪里加载DLL,那么Windows将会默认使用上述DLL搜索顺序。因此,作为攻击者来说,往往就会对DLL搜索的第一个位置(加载应用程序的目录)感兴趣。 如果应用程序开发人员希望从C:WindowsSystem32加载DLL,但在应用程序中没有明确写入,那么就会在搜索System32中的合法DLL之前,先加载应用程序目录中被植入的恶意DLL。这种恶意DLL加载方式被称为DLL劫持,攻击者以这种方式将恶意代码加载到受信任或已签名的应用程序中。   7f02fc4ed8e09725c1ff7972ff9f8c93.png四、使用DLL劫持技术实现持久化 在攻击者将恶意DLL植入到易受攻击的位置之后,就可以利用DLL劫持技术实现持久化,在存在漏洞的应用程序或服务运行时执行恶意代码。我的同事 @Airzero24 发现有攻击者在Microsoft OneDrive、Microsoft Teams和Slack中,使用了 userenv.dll 来实现DLL劫持。 攻击者针对了特定的应用程序进行攻击,因为在默认情况下,这些程序会被配置为在Windows启动时自动启动。我们可以在任务管理器中找到它们。 配置为开机时自动启动的Windows应用程序: 3133dc7a806081352e00b91e93417d23.png 为了验证DLL劫持,我创建了一个DLL Shellcode加载程序,它将会启动一个Cobalt Strike Beacon。我将恶意DLL重命名为 userenv.dll ,并将其复制到易受攻击的应用程序的目录中。在启动该应用程序之后,我就看到了新的Beacon回调。 通过DLL劫持实现Cobalt Strike Beacon: 410fe65845b08f5d206ce4d93b3a1ac7.png 在进程管理器中,我们验证了易受攻击的应用程序确实已经加载了我的恶意DLL。 进程管理器显示恶意DLL已加载。 b8df12b22fba5e8126ea525f3696f6a4.png 7f02fc4ed8e09725c1ff7972ff9f8c93.png五、自动化DLL劫持侦查 在我们研究已知的DLL劫持之后,我想看看是否可以找到其他的DLL劫持。 在测试过程中,我所使用的代码可以在这里找到: https://github.com/slyd0g/DLLHijackTest

5.1 案例分析:Slack

在一开始,我在进程管理器(ProcMon)中使用了以下过滤器: 1、进程名称为 slack.exe ; 2、结果包含 NOT FOUND ; 3、路径以 .dll 结尾。 使用ProcMon过滤丢失的DLL: beb07a5800c8c4e2393541b6063f70a0.png 接下来,我启动了Slack,并观察ProcMon中是否存在Slack正在搜索但无法找到的DLL。 通过ProcMon发现潜在的DLL劫持攻击点: 1fad75172ad81eb597502296fb587710.png 我将这些数据从ProcMon导出为CSV文件,以便在PowerShell中轻松进行解析。 使用当前的Shellcode加载程序DLL,我们不能轻松确定Slack成功加载的DLL名称。为此,我创建了一个新的DLL,该DLL使用 GetModuleHandleExGetModuleFileName 来确定加载的DLL的名称,并将其写入文本文件。 我们的下一个目标是解析CSV文件,以获得DLL路径列表,遍历这个路径列表,将测试DLL复制到指定的路径,启动目标进程,停止目标进程,并删除测试DLL。如果这个测试DLL能成功加载,就会将这个文件名写入到结果文件中。 在这一过程完成时,我们就有了一个文本文件,其中包含可以用于DLL劫持的列表。 在我的DLLHijackTest项目中,主要使用PowerShell脚本来完成所有工作。它负责接受ProcMon生成的CSV文件中包含的路径、恶意DLL路径、要启动的进程路径以及要传递给该进程的所有参数。 Get-PotentialDLLHijack 参数: 83199f91c4d3d7dba1de5dd32f2042ff.png Get-PotentialDLLHijack.ps1bc5110deb5bb3e87c22d98dac07ebb8c.png 在几分钟后,我检查了在“恶意”DLL中指定的文本文件中,是否包含可用的DLL劫持,并发现了针对Slack的以下劫持:
PS C:UsersJohnDesktop> Get-PotentialDLLHijack -CSVPath .Logfile.CSV -MaliciousDLLPath .DLLHijackTest.dll -ProcessPath "C:UsersJohnAppDataLocalslackslack.exe"C:UsersJohnAppDataLocalslackapp-4.6.0WINSTA.dllC:UsersJohnAppDataLocalslackapp-4.6.0LINKINFO.dllC:UsersJohnAppDataLocalslackapp-4.6.0ntshrui.dllC:UsersJohnAppDataLocalslackapp-4.6.0srvcli.dllC:UsersJohnAppDataLocalslackapp-4.6.0cscapi.dllC:UsersJohnAppDataLocalslackapp-4.6.0KBDUS.DLL

5.2 案例分析:Microsoft Teams

再次进行以上的步骤: 1、使用ProcMon识别出潜在的DLL劫持,并将数据导出为CSV文件; 2、确定启动进程的路径; 3、确定要传递给进程的所有参数; 4、使用适当的参数运行 Get-PotentialDLLHijack.ps1 。 最后发现,Microsoft Teams存在以下劫持:
PS C:UsersJohnDesktop> Get-PotentialDLLHijack -CSVPath .Logfile.CSV -MaliciousDLLPath .DLLHijackTest.dll -ProcessPath "C:UsersJohnAppDataLocalMicrosoftTeamsUpdate.exe" -ProcessArguments '--processStart "Teams.exe"'C:UsersJohnAppDataLocalMicrosoftTeamscurrentWINSTA.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentLINKINFO.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentntshrui.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentsrvcli.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentcscapi.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentWindowsCodecs.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentTextInputFramework.dll
需要特别说明的是,在这里需要对PowerShell脚本进行少量修改,才能终止 Teams.exe ,因为我的脚本试图终止它尝试启动的进程,即 Update.exe

5.3 案例分析:Visual Studio Code

重复上述过程,我发现了Visual Studio Code存在以下劫持:
PS C:UsersJohnDesktop> Get-PotentialDLLHijack -CSVPath .Logfile.CSV -MaliciousDLLPath .DLLHijackTest.dll -ProcessPath "C:UsersJohnAppDataLocalProgramsMicrosoft VS CodeCode.exe"C:UsersJohnAppDataLocalProgramsMicrosoft VS CodeWINSTA.dllC:UsersJohnAppDataLocalProgramsMicrosoft VS CodeLINKINFO.dllC:UsersJohnAppDataLocalProgramsMicrosoft VS Codentshrui.dllC:UsersJohnAppDataLocalProgramsMicrosoft VS Codesrvcli.dllC:UsersJohnAppDataLocalProgramsMicrosoft VS Codecscapi.dll

5.4 共同的DLL劫持

在进行上述分析之后,我们注意到,Slack、Microsoft Teams和Visual Studio Code共享了以下的DLL劫持: WINSTA.dll
LINKINFO.dll
ntshrui.dll
srvcli.dll
cscapi.dll 这非常值得关注,我们想要分析是什么导致了这样的情况。   7f02fc4ed8e09725c1ff7972ff9f8c93.png六、理解共享的DLL劫持 当Slack尝试加载 WINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dllcscapi.dll 时,我观察了堆栈跟踪。

6.1 延迟加载的DLL

在加载 WINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dll 时,我注意到堆栈跟踪中存在相似之处。 Code.exe尝试加载 WINSTA.dll 时的堆栈跟踪: f30baa800dbd51234bf21239bda9a4b8.png Teams.exe尝试加载 LINKINFO.dll 时的堆栈跟踪: 4b6fa8cf09be24c766bb69a9169f5cf9.png Stack尝试加载 ntshrui.dll 时的堆栈跟踪: 2bf90a321ca5aa28a6a2c97f6b4a99b3.png 堆栈跟踪始终包含对 _tailMerge__dlldelayLoadHelper2 的调用,然后是 LdrResolveDelayLoadedAPI 。这三个应用程序之间的行为是一致的。 我可以确定,这样的行为与延迟加载的DLL有关。在加载 WINSTA.dll 时的堆栈跟踪中,我们发现负责延迟加载的模块是 wtsapi32.dll 。 于是,在Ghidra中打开 wtsapi32.dll ,并选择“Search” -> “For Strings” -> “Filter: WINSTA.dll”,双击找到的字符串,就可以查看其在内存中的位置。 wtsapi32.dll 中的“WINSTA.dll”字符串: bb3d40386f60cdd08b31716d878912df.png 右键单击内存中的位置,我们就可以找到对该地址的所有引用。 寻找对 WINSTA.dll 的引用: 1958c29694dce2d3bca47e2185be5f41.png 在引用之后,我们看到 WINSTA.dll 字符串会传递给名为 ImgDelayDescr 的结构。我们查看有关此结构的文档,可以确认它与延迟加载的DLL相关。
typedef struct ImgDelayDescr {    DWORD        grAttrs;        // attributes    RVA          rvaDLLName;     // RVA to dll name    RVA          rvaHmod;        // RVA of module handle    RVA          rvaIAT;         // RVA of the IAT    RVA          rvaINT;         // RVA of the INT    RVA          rvaBoundIAT;    // RVA of the optional bound IAT    RVA          rvaUnloadIAT;   // RVA of optional copy of original IAT    DWORD        dwTimeStamp;    // 0 if not bound,                                 // O.W. date/time stamp of DLL bound to (Old BIND)    } ImgDelayDescr, * PImgDelayDescr;
可以将这个结构传递给 __delayLoadHelper2 ,它将使用 LoadLibrary/GetProcAddress 加载指定的DLL,并在延迟加载导入地址表(IAT)中修补导入函数的地址。
FARPROC WINAPI __delayLoadHelper2(    PCImgDelayDescr pidd,  //Const pointer to a ImgDelayDescr struct    FARPROC * ppfnIATEntry //A pointer to the slot in delay load IAT);
查找对 ImgDelayDescr 结构的其他引用,我们可以找到对 __delayLoadHelper2 的调用,该调用随后会调用 ResolveDelayLoadedAPI 。在这里,我已经将函数名称、类型和变量进行重命名,以使其更加易于理解。 在Ghidra中查看的 __delayLoadHelper2ResolveDelayLoadedAPIcdaabb7cc6431aa0c73ea5b8ee176beb.png 非常好!这就与我们在Slack尝试加载 WINSTA.dll 时在ProcMon堆栈跟踪中看到的结果相匹配了。 ProcMon中的 __delayLoadHelper2ResolveDelayLoadedAPI356918ca220fe62e89ff897ff9b852fe.pngWINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dll 之中,行为是一致的。每个延迟加载的DLL之间,主要区别在于它们的父DLL。在这三个应用程序中: wtsapi32.dll 延迟加载 WINSTA.dllshell32.dll 延迟加载 LINKINFO.dllLINKINFO.dll 延迟加载 ntshrui.dllntshrui.dll 延迟加载 srvcli.dll 。 观察到了什么有趣的地方吗?似乎 shell32.dll 加载了 LINKINFO.dll ,而 LINKINFO.dll 又加载了 ntshrui.dll ,最后由 ntshrui.dll 加载了 srvcli.dll

6.2 NetShareGetInfo和NetShareEnum中的DLL劫持

当Slack尝试加载 cscapi.dll 时,我观察了堆栈跟踪,看到其中有一个 LoadLibraryExW 调用,该调用似乎源自 srvcli.dll 。 加载 cscapi.dll 时的堆栈跟踪: 3cd13a5b67bb22a92476f8eb31ace1e9.png 我们再次使用Ghidra打开 srvcli.dll ,并选择“Search” -> “For Strings” -> “Filter: cscapi.dll”,双击找到的字符串,并在跟踪引用,看能否找到预期的 LoadLibrary 调用。 srvcli.dllcscapi.dll 上调用 LoadLibrary3b20019d730511254f2ce8ae8f217f68.png 我们对包含 LoadLibrary 调用的函数进行重命名,并跟踪引用,最后找到了两个函数的位置: NetShareEnum
NetShareGetInfo NetShareEnum 加载 cscapi.dll61e653439f38f301986b62d253b8a665.png NetShareGetInfo 加载 cscapi.dll264aa7e7a9787db6babeddf48a3d0a99.png 通过调用 NetShareEnumNetShareGetInfo ,可以对PoC程序进行验证。 NetShareEnum 加载 cscapi.dll0733c8fb06acb6e1d14e18df1362e753.png NetShareGetInfo 加载 cscapi.dlle2a9ddea01d03b5d7ba4dd4735c2f4cf.png 7f02fc4ed8e09725c1ff7972ff9f8c93.png七、结果 以下DLL劫持存在于Slack中:
C:UsersJohnAppDataLocalslackapp-4.6.0WINSTA.dllC:UsersJohnAppDataLocalslackapp-4.6.0LINKINFO.dllC:UsersJohnAppDataLocalslackapp-4.6.0ntshrui.dllC:UsersJohnAppDataLocalslackapp-4.6.0srvcli.dllC:UsersJohnAppDataLocalslackapp-4.6.0cscapi.dllC:UsersJohnAppDataLocalslackapp-4.6.0KBDUS.DLL
以下DLL劫持存在于Microsoft Teams中:
C:UsersJohnAppDataLocalMicrosoftTeamscurrentWINSTA.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentLINKINFO.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentntshrui.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentsrvcli.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentcscapi.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentWindowsCodecs.dllC:UsersJohnAppDataLocalMicrosoftTeamscurrentTextInputFramework.dll
以下DLL劫持存在于Visual Studio Code中:
C:UsersJohnAppDataLocalProgramsMicrosoft VS CodeWINSTA.dllC:UsersJohnAppDataLocalProgramsMicrosoft VS CodeLINKINFO.dllC:UsersJohnAppDataLocalProgramsMicrosoft VS Codentshrui.dllC:UsersJohnAppDataLocalProgramsMicrosoft VS Codesrvcli.dllC:UsersJohnAppDataLocalProgramsMicrosoft VS Codecscapi.dll
此外,我发现使用 NetShareEnumNetShareGetInfo 的程序,由于其中包含硬编码的 LoadLibrary 调用,因此以 cscapi.dll 的形式引入了DLL劫持。通过Ghidra和PoC,我们最终得以确认了这种行为。   7f02fc4ed8e09725c1ff7972ff9f8c93.png八、总结 概括来说,DLL劫持是攻击者在已签名、受信任的应用程序中实现代码执行的一种方式。为防范此风险,我编写了一个工具来帮助自动化发现DLL劫持。使用该工具,我们成功发现了Slack、Microsoft Teams、Visual Studio Code中存在的DLL劫持风险。 我注意到这三个应用程序与其DLL劫持存在重叠的地方,并调查了根本原因。在研究过程中,我重点介绍了我的研究方法。最终,我理解了延迟加载DLL的原理,并从中确定了两个API调用,正是这两个API调用( NetShareEnum 加载 cscapi.dllNetShareGetInfo 加载 cscapi.dll )将DLL劫持引入了所有调用它们的程序之中。 感谢大家抽出宝贵的时间来阅读这篇文章,希望通过本文,能让大家对于Windows API、Ghidra、ProcMon、DLL和DLL劫持都能有所了解。   7f02fc4ed8e09725c1ff7972ff9f8c93.png九、致谢 非常感谢我的同事Daniel Heinsen( @hotnops )、Lee Christensen( @tifkin_ )和Matt Hand( @matterpreter ),他们帮助我解决了Ghidra和ProcMon中遇到的一些问题。

译文声明

译文仅供参考,具体内容表达以及含义原文为准。

29adc4ad5d801554065a4b6fc5f716d3.gif 戳“阅读原文”查看更多内容
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值