自动检测可能的DLL拦截路径(DLL劫持)

你好,哈布罗夫派。招募新课程“ Pentest。渗透测试实务“预期课程的开始,我们将与您分享有趣材料的翻译。







介绍



在本文中,我们将研究DLL劫持的概念以及如何将其用于在Windows系统上实现用户态持久性。 MITER ATT&CK下的“拦截DLL搜索顺序(T1038) ”中介绍了此方法



攻击者可以将DLL欺骗用于许多不同的目的,但是本文将重点介绍如何通过自动启动应用程序来实现弹性。例如,由于Slack和Microsoft Teams是在引导时启动的(默认情况下),因此这些应用程序之一中的DLL欺骗将使攻击者能够在用户登录时获得对其目标的强大访问权限。



在介绍了DLL的概念,DLL查找顺序和DLL欺骗之后,我将引导您完成自动执行DLL侦听检测过程本文将讨论在Slack,Microsoft Teams和Visual Studio Code中检测DLL拦截路径。



最后,我发现了不同应用程序使用的多个DLL拦截路径,调查了根本原因,并发现使用某些Windows API调用的应用程序如果不从运行,则很容易发生DLL拦截C:\Windows\System32\



我要感谢我的同事Josiah Massari(@Airzero24)率先发现了这些DLL挂钩,解释了它们的方法,并启发了我使检测自动化。



什么是DLL?



DLL是一个包含可被多个程序同时使用的代码和数据的库。



DLL功能可以由Windows应用程序使用以下功能之一使用LoadLibrary*应用程序可以引用专门为这些应用程序设计的DLL,也可以引用System32磁盘上已存在的Windows DLL。开发人员可以从System32加载DLL,以使用Windows在其应用程序中已经实现的功能,而不必从头开始编写此功能。



例如,需要发出HTTP请求的开发人员可以使用WinHTTP(winhttp.dll库,而不是使用原始套接字实现HTTP请求。



DLL搜索顺序和拦截



由于DLL以文件形式存在于磁盘上,因此您可能想知道应用程序如何知道从何处加载DLL?Microsoft已在此处详细记录了DLL查找顺序



从Windows XP SP2开始,默认情况下(HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode启用DLL安全搜索模式启用安全模式后,DLL搜索顺序如下:



  1. 从中加载应用程序的目录。
  2. 系统目录。使用GetSystemDirectory函数获取此目录的路径。
  3. 16位系统目录。没有提供该目录路径的函数,但会对其进行搜索。
  4. Windows目录。使用GetWindowsDirectory函数获取此目录的路径。
  5. 当前目录。
  6. , PATH. , , App Paths. App Paths DLL.


一个系统可以包含同一DLL的多个版本。应用程序可以通过指定完整路径或使用其他机制(如清单)来控制DLL加载位置的选择。 (



如果应用程序未指定从何处加载DLL,Windows将使用上面显示的默认DLL查找顺序。攻击者会对DLL搜索顺序中的第一位置(加载应用程序的目录)感兴趣。



如果应用程序开发人员打算从以下位置加载DLL:C:\Windows\System32,但没有在应用程序中明确编写它,因此将从System32加载到合法DLL之前的应用程序目录中放置的恶意DLL。加载恶意DLL称为DLL欺骗(或拦截),攻击者使用它来将恶意代码加载到受信任/已签名的应用程序中。



使用DLL欺骗来实现弹性



启动易受攻击的应用程序/服务并将恶意DLL放置在易受攻击的位置时,DLL欺骗可用于实现弹性。我的一位同事@Airzero24在Microsoft OneDrive,Microsoft Teams和Slack中发现了DLL欺骗userenv.dll



正是这些程序成为了拦截的目标,因为默认情况下,它们被配置为在Windows启动时启动。可以在下面的任务管理器中看到:





配置为自动启动的Windows应用程序



为了测试DLL欺骗,我创建了一个DLL shellcode加载器,该加载器启动了Cobalt Strike Beacon。我将恶意DLL重命名为userenv.dll并将其复制到受影响的应用程序目录。我启动了该应用程序,并看到了新的Beacon回调。





通过



使用DLL拦截拦截钴打击信标进程浏览器,我可以检查我的恶意DLL是否确实由易受攻击的应用程序加载。





进程资源管理器显示已加载的恶意DLL



自动检测DLL拦截潜力



在确认了先前已知的DLL劫持之后,我想看看是否可以找到其他可以利用的DLL欺骗功能。



我的结帐中使用的代码可以在这里找到



以Slack为例



要开始此过程,我运行了带有以下过滤器的过程监视器(ProcMon):



  • 流程名称-slack.exe
  • 结果包含NOT FOUND
  • 路径以结尾.dll




在ProcMon中查找丢失的DLL。



然后,我启动了Slack,并检查了ProcMon中是否有Slack正在寻找但找不到的DLL。





ProcMon发现的可能的DLL拦截路径



我将这些数据从ProcMon导出为CSV文件,以便在PowerShell中更轻松地进行解析。



使用当前的shellcode加载器DLL,我无法轻松找出Slack成功加载的DLL名称。我创建了一个新的DLL,它是用来GetModuleHandleEx,并GetModuleFileName确定加载的DLL的名称,并把它写入一个文本文件



我的下一个目标是解析列表中DLL路径的CSV文件,查看该列表,将我的测试DLL复制到指定的路径,启动目标进程,停止目标进程以及删除测试DLL。如果测试DLL成功加载,它将名称写入结果文件。



完成此过程后,我将获得一个可能的DLL劫持列表(希望)写入文本文件的列表。



我的DLLHijackTest项目中的所有魔术都是通过PowerShell脚本完成的。它接受ProcMon生成的CSV文件的路径,恶意DLL的路径,要运行的进程的路径以及要传递给该进程的所有参数。





Get-PotentialDLLHijack参数





Get-PotentialDLLHijack.ps1



几分钟后,我检查了“恶意” DLL中列出的文本文件,以查找可能的DLL劫持事件。我发现了Slack的以下可能拦截路径:



PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\slack\slack.exe"
C:\Users\John\AppData\Local\slack\app-4.6.0\WINSTA.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\LINKINFO.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\ntshrui.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\srvcli.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\cscapi.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\KBDUS.DLL


以Microsoft Teams为例



我们再次执行上述过程:



  1. 使用ProcMon识别潜在的DLL拦截路径,并将此数据导出为CSV文件。
  2. 确定开始该过程的路径。
  3. 定义要传递给流程的任何参数。
  4. Get-PotentialDLLHijack.ps1使用适当的参数运行


我发现了Microsoft团队的以下可能拦截路径:



PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\Microsoft\Teams\Update.exe" -ProcessArguments '--processStart "Teams.exe"'
C:\Users\John\AppData\Local\Microsoft\Teams\current\WINSTA.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\LINKINFO.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\ntshrui.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\srvcli.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\cscapi.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\WindowsCodecs.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\TextInputFramework.dll


注意:我必须对PowerShell脚本进行一些小的更改才能完成Teams.exe,因为我的脚本正试图终止尝试启动的进程,在本例中为Update.exe


以Visual Studio Code为例



通过重复上述过程,我发现了Visual Studio Code的以下潜在拦截路径:



PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\Programs\Microsoft VS Code\Code.exe"
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\WINSTA.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\LINKINFO.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\ntshrui.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\srvcli.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\cscapi.dll


共享DLL



我注意到Slack,Microsoft Teams和Visual Studio Code共享以下DLL:



  • WINSTA.dll
  • LINKINFO.dll
  • ntshrui.dll
  • srvcli.dll
  • cscapi.dll


我发现这很有趣,并且想了解是什么导致了这种现象。



方法:了解拦截共享DLL的方法



我看着麦蒂栈农闲时试图负载WINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dllcscapi.dll



延迟加载的DLL



在加载WINSTA.dll我在Tracy堆栈中发现了相似之处当Code.exe试图加载堆栈跟踪,当一个堆栈跟踪试图装入堆栈跟踪农闲时尝试加载 一个堆栈跟踪不断包含一呼叫接着。对于所有三个应用程序,此行为都是相同的。 我已确定此行为与延迟DLL加载有关。从启动时的跟踪堆栈LINKINFO.dllntshrui.dllsrvcli.dll





WINSTA.dll





Teams.exeLINKINFO.dll





ntshrui.dll



_tailMerge_<dllname>_dlldelayLoadHelper2LdrResolveDelayLoadedAPI



WINSTA.dll我可以看到负责此延迟加载的模块是wtsapi32.dll



wtsapi32.dll吉德拉(Ghidra)开张,习惯了Search -> For Strings -> Filter: WINSTA.dll。双击找到的行将带您到其在内存中的位置。





该行“ WINSTA.dll”中wtsapi32.dll



通过在存储器中的位置单击鼠标右键,就可以找到这个地址的任何引用。





链接到WINSTA.dll



以下链接,我们可以看到该字符串WINSTA.dll已传递到名为的结构ImgDelayDescr查看此结构文档,我们可以确认它与延迟DLL加载有关。



typedef struct ImgDelayDescr {
   DWORD        grAttrs;        // 
   RVA          rvaDLLName;     // RVA   dll 
   RVA          rvaHmod;        // RVA  
   RVA          rvaIAT;         // RVA IAT
   RVA          rvaINT;         // RVA INT
   RVA          rvaBoundIAT;    // RVA   IAT
   RVA          rvaUnloadIAT;   // RVA    IAT
   DWORD        dwTimeStamp;    // 0,   ,
                                // O.W. / DLL,   (Old BIND)
   } ImgDelayDescr, * PImgDelayDescr;


可以将此结构传递给__delayLoadHelper2,它将使用LoadLibrary/GetProcAddress加载指定的DLL,并在延迟加载导入地址表(IAT)中修复导入的函数地址。



FARPROC WINAPI __delayLoadHelper2(
   PCImgDelayDescr pidd,  //     ImgDelayDescr
   FARPROC * ppfnIATEntry //     IAT  
);


通过查找对我们结构的其他引用ImgDelayDescr,我们可以找到一个调用__delayLoadHelper2,然后调用ResolveDelayLoadedAPI我已将函数名称,类型和变量重命名,以使其更易于理解。





__delayLoadHelper2ResolveDelayLoadedAPI在Ghidra



好极了!这与我们在Slack尝试加载时在ProcMon堆栈跟踪中看到的一致WINSTA.dll





__delayLoadHelper2 ResolveDelayLoadedAPI在ProcMon中。



这种行为是对均匀WINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dll每个延迟加载DLL之间的主要区别是“父” DLL。在所有三个应用程序中:



  • wtsapi32.dll 延迟加载 WINSTA.dll
  • shell32.dll 懒加载 LINKINFO.dll
  • LINKINFO.dll 延迟加载 ntshrui.dll
  • ntshrui.dll 延迟加载 srvcli.dll


你有没有发现有趣的事情?看起来像是shell32.dll下载LINKINFO.dll,然后下载ntshrui.dll,最后下载srvcli.dll这将我们带到了最后一个潜在的DLL欺骗选项- cscapi.dll



NetShareGetInfo和NetShareEnum中的DLL替换



当Slack试图加载cscapi.dll并看到一个LoadLibraryExW显然来自的调用时我正在看堆栈跟踪srvcli.dllGhidra





引导cscapi.dll



打开了堆栈跟踪并使用了双击找到的行,然后单击链接将导致预期的呼叫。调用LoadLibrary以 重命名包含调用并跟随链接的函数,我在两个地方使用了该函数:srvcli.dllSearch -> For Strings -> Filter: cscapi.dllLoadLibrary





srvcli.dllcscapi.dll



LoadLibrary







NetShareEnum下载cscapi.dll





NetShareGetInfo下载cscapi.dll



我用调用NetShareEnum和的PoC程序对此进行了检查NetShareGetInfo





NetShareEnum.exedownloads cscapi.dll





NetShareGetInfo.exedownloadscscapi.dll



结果



Slack中提供了以下DLL欺骗路径:



C:\Users\John\AppData\Local\slack\app-4.6.0\WINSTA.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\LINKINFO.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\ntshrui.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\srvcli.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\cscapi.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\KBDUS.DLL


Microsoft团队中提供了以下DLL欺骗路径:



C:\Users\John\AppData\Local\Microsoft\Teams\current\WINSTA.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\LINKINFO.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\ntshrui.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\srvcli.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\cscapi.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\WindowsCodecs.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\TextInputFramework.dll


Visual Studio代码中提供了以下DLL欺骗路径:



C:\Users\John\AppData\Local\Programs\Microsoft VS Code\WINSTA.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\LINKINFO.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\ntshrui.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\srvcli.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\cscapi.dll


此外,由于硬编码的调用,我发现程序使用NetShareEnumNetShareGetInfo提供了覆盖形式的DLL的功能我已经使用Ghidra和PoC验证了此行为。cscapi.dllLoadLibrary



结论



提醒一下,DLL拦截是一种方法,攻击者可以通过该方法来干扰已签名/受信任的应用程序中的代码执行。我创建了一些工具来帮助自动化DLL拦截路径检测。使用此工具,我在Slack,Microsoft Teams和Visual Studio Code中发现了DLL拦截路径。



我注意到这三个应用程序的DLL拦截路径重叠并调查了原因。我强调了我理解这种巧合的方法。我了解了延迟加载DLL的知识,并发现了两个API调用,它们使得可以在调用它们的任何程序中拦截DLL:



  • NetShareEnum 负载 cscapi.dll
  • NetShareGetInfo 负载 cscapi.dll


感谢您抽出宝贵的时间阅读本文,希望您对Windows API,Ghidra,ProcMon,DLL和DLL拦截有所了解。



链接



谢谢同事Daniel Heinsen(@hotnops),Lee Christensen(@tifkin_)和Matt Hand(@matterpreter)向Ghidra / ProcMon提供帮助!






检查公共PoC以用于渗透测试






阅读更多:






All Articles