首页
社区
课程
招聘
[翻译]DLL劫持自动化检测
2020-7-16 22:45 20359

[翻译]DLL劫持自动化检测

2020-7-16 22:45
20359

DLL劫持自动化检测

简介

本文将介绍动态链接库(DLL)搜索顺序劫持的概念,以及如何实现在Windows上的持久化攻击。MITRE ATT&CK对DLL搜索顺序劫持的描述详见DLL Search Order Hijacking (T1038)

 

DLL劫持对攻击者很有用,原因有很多,但本文会重点介绍与开机自启程序结合使用时的持久化攻击。例如,由于Slack和Microsoft Teams开机自启(默认情况下),因此,只要用户登录,这些应用程序中的DLL劫持将允许攻击者能够持久访问攻击目标。

 

在介绍DLL、DLL搜索顺序和DLL劫持的概念后,我会阐述DLL劫持自动化检测的过程https://github.com/slyd0g/DLLHijackTest。本文将涉及Slack、Microsoft Teams以及Visual Studio Code相关的DLL劫持检测。

 

最后,我注意到很多DLL劫持会同时作用于多个程序。我调查了底层原因,发现调用某些位于C:\Windows\System32\下的Windows API的程序容易成为DLL劫持的目标。

 

这里我要感谢我的同事,Josiah Massari (@Airzero24)。是他最早发现的这些DLL劫持案例并解释其方法和原理,促成了我将检测做成自动化。

DLL是什么

DLL是一个包含可被多个程序同时使用的代码和数据的库。(定义源于Microsoft

 

Windows程序可以调用LoadLibrary*系列函数来使用DLL中的功能。程序可以引用自定义的DLL,也可以引用System32中Windows自带的DLL。开发者可以加载System32中的DLL,使其程序使用Windows的现成功能,而不必重新造轮子。

 

例如,开发者需要发起HTTP请求时,可以使用WinHTTP库(winhttp.dll),而无需用原始套接字开发并实现HTTP功能。

DLL搜索顺序和劫持

由于DLL也是存储在磁盘上的文件,那么程序是如何知道从哪里加载DLL的呢?Microsoft在详细记录了DLL搜索顺序。

 

自Windows XP SP2起,安全DLL搜索模式默认开启(HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode)。当安全模式启用时,搜索顺序如下:

  1. 程序安装目录。
  2. 系统目录。使用GetSystemDirectory获取该目录路径。
  3. 16位系统目录。没有函数可以获取该目录路径,但该目录会被搜索。
  4. Windows目录。使用GetWindowsDirectory获取该目录路径。
  5. 当前目录。
  6. PATH环境变量中的目录。注意,这不包括App Paths注册表键指定的程序路径。App Paths键不会参与DLL搜索路径的计算。

系统可包含动态链接库(DLL)的多个版本。程序可通过指定完整路径或使用比如manifest的其他机制来控制加载特定的DLL。(定义源于Microsoft

 

如果程序没有加载指定的DLL,Windows会默认执行上述的DLL搜索流程。DLL搜索的第一顺位,即程序的安装目录,是攻击者最感兴趣的。

 

如果开发者想要从C:\Windows\System32\加载 DLL,但并没有写清楚让程序这么做,那么程序安装目录下的恶意DLL就会优先于System32下的合法DLL被加载。这里恶意DLL指的是DLL劫持,攻击者用来在受信/签名程序中加载恶意代码。

DLL劫持持久化利用

当目标程序/服务启动并且恶意DLL被植入到了关键位置,DLL劫持即可用于持久化攻击。我的同事@Airzero24,发现了Microsoft OneDrive、 Microsoft Teams、以及Slack中针对userenv.dll的劫持。

 

这类程序被盯上的原因是,他们默认都会随着Windows开机启动。任务管理器中可以看到:

 

开机启动的WIndows程序

 

为了验证DLL劫持,我写了一段运行Cobalt Strike Beacon的DLL shellcode,命名为userenv.dll,并且复制到目标程序的安装目录。运行程序,我看到肉鸡上线了。

 

通过DLL劫持运行Cobalt Strike Beacon

 

查看Process Explorer,可以确认恶意DLL确实被目标程序加载了。

 

Process Explorer中显示恶意DLL被加载

DLL劫持自动化检测

确认先前已知的DLL劫持之后,我想看看是否可以找到其他的DLL劫持。

 

测试代码在此:https://github.com/slyd0g/DLLHijackTest

案例研究:Slack

首先,运行Process Monitor(ProcMon),过滤规则如下:

  • Process Nameslack.exe
  • Result包含NOT FOUND
  • Path.dll结尾

ProcMon过滤规则

 

接下来,运行Slack,留意Slack搜索但无法找到的DLL。

 

用ProcMon找到的疑似DLL劫持

 

从ProcMon中导出数据,方便用PowerShell处理。

 

用当前加载shellcode的DLL,我无法轻易找出被Slack加载的DLL的名字。我写了一个新的使用了GetModuleHandleExGetModuleFileNameDLL的DLL,输出加载DLL的名字到文本文件

 

接下来就是解析CSV得到DLL路径列表,遍历路径列表,把我的测试DLL复制到特定路径,运行目标进程,退出目标进程,删除测试DLL。如果测试DLL被成功加载,其文件名会写入结果文件。

 

上述步骤完成后,会得到一个有效DLL劫持的列表。

 

在我的DLLHijackTest项目中的PowerShell脚本可以处理所有步骤。脚本的输入参数有:ProcMon生成的CSV文件的路径,恶意DLL的路径,目标程序的路径,以及其他你想要传递给目标程序的参数。

 

Get-PotentialDLLHijack

 

Get-PotentialDLLHijack.ps1

 

几分钟后,打开“恶意”DLL中指定的文本文件,发现以下针对Slack的DLL劫持:

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 Teams的DLL劫持:

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劫持

我观察了下Slack加载WINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dllcscapi.dll的栈轨迹。

延迟加载DLL

我注意到当WINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dllcscapi.dll被加载时栈轨迹存在共性。

 

Code.exe加载WINSTA.dll时的栈轨迹

 

Teams.exe加载LINKINFO.dll时的栈轨迹

 

Slack加载ntshrui.dll时的栈轨迹

 

栈轨迹都调用了_tailMerge_<dllname>_dlldelayLoadHelper2,之后还调用了LdrResolveDelayLoadedAPI。三个程序都出现了这种情况。

 

我认为这种情况与延迟加载DLL有关。当WINSTA.dll被加载时,从栈轨迹可以看到,wtsapi32.dll导致了延迟加载。

 

Ghidra中打开wtsapi32.dll,设置Search -> For Strings -> Filter: WINSTA.dll。双击查找的结果会看到其内存地址。

 

wtsapi32.dll中“WINSTA.dll”字符串

 

右键点击内存地址,可以找到对该地址的引用。

 

WINSTA.dll引用

 

我们看到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中查看__delayLoadHelper2和ResolveDelayLoadedAPI

 

很好!这与我们之前在Slack加载WINSTA.dll时在ProcMon中看到的栈轨迹一致。

 

ProcMon中查看__delayLoadHelper2和ResolveDelayLoadedAPI

 

WINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dll的行为是一致的,每个延迟加载的DLL间主要的不同点是“父级”DLL。在三个程序中:

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

看到有意思的点了吗?shell32.dll加载了LINKINFO.dllLINKINFO.dll加载了ntshrui.dllntshrui.dll最后加载了srvcli.dll。 最后我们看到共有的针对cscapi.dll的劫持。

NetShareGetInfo和NetShareEnum中的DLL劫持

观察Slack加载cscapi.dll的栈轨迹,看到调用了LoadLibraryExW,后者似乎来源于srvcli.dll

 

加载cscapi.dll时的栈轨迹

 

Ghidra中打开srvcli.dll,设置Search -> For Strings -> Filter: cscapi.dll。双击查找的结果并跟踪引用,找到LoadLibrary调用。

 

cscapi.dll中srvcli.dll调用LoadLibrary

 

重命名包含LoadLibrary的函数,跟踪引用可以看到两个函数地址:

NetShareEnum调用cscapi.dll

 

NetShareGetInfo调用cscapi.dll

 

我使用调用NetShareEnumNetShareGetInfo的PoC程序验证了该过程:

 

NetShareEnum.exe调用cscapi.dll

 

NetShareGetInfo.exe调用cscapi.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 Teams中,存在以下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 Code中,存在以下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的程序会引入cscapi.dll劫持,这是由硬编码的LoadLibrary调用导致的,并且我用Ghidra和PoC确认了该结论。

结论

简要回顾下,DLL劫持是攻击者在签名/受信的程序中执行代码的一种方法。我开发了自动检测DLL劫持的工具。利用此工具,我发现了Slack、Microsoft Teams和Visual Studio Code中的DLL劫持。

 

我注意到这三个程序存在共有DLL劫持的情况,并调查了根本原因。我重点介绍了研究的方法,并了解了延迟加载DLL,以及定位到了两个API调用,这两个API会引入DLL劫持到调用它们的程序中:

  • NetShareEnum加载cscapi.dll
  • NetShareGetInfo加载cscapi.dll

感谢花时间阅读本文,希望你能学到一些关于Windows API、Ghidra、ProcMon、DLL和DLL劫持的知识!

参考资料

感谢我的同事Daniel Heinsen(@hotnops), Lee Christensen(@tifkin_), and Matt Hand(@matterpreter)给我提供的帮助。

  1. https://github.com/slyd0g/DLLHijackTest
  2. https://attack.mitre.org/techniques/T1038/
  3. https://support.microsoft.com/en-us/help/815065/what-is-a-dll
  4. https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order
  5. https://msrc-blog.microsoft.com/2018/04/04/triaging-a-dll-planting-vulnerability/
  6. https://stackoverflow.com/questions/3573475/how-does-the-import-library-work-details
  7. https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/build/reference/understanding-the-helper-function.md
  8. https://docs.microsoft.com/en-us/cpp/build/reference/linker-support-for-delay-loaded-dlls
  9. https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/february/inside-windows-win32-portable-executable-file-format-in-detail

原文作者:Justin Bui

 

原文链接:https://posts.specterops.io/automating-dll-hijack-discovery-81c4295904b0

 

翻译:看雪翻译小组 SpearMint

 

校对:看雪翻译小组 OsWalker


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
点赞2
打赏
分享
最新回复 (4)
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
phpnec 2020-7-17 16:02
2
0
雪    币: 23
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
毫曹 2020-7-20 00:39
3
0
...........
终于有人提到 OneDrive 了,这个可以劫持的有好几个.
此外这个位置User权限就可以写.
而且,他的启动属性也是User就可以改....
我是不是说多了?
雪    币: 22
活跃值: (423)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
靴子 2020-7-20 10:58
4
0
雪    币: 2095
活跃值: (344)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
icesnowwise 2020-12-25 15:08
5
0
毫曹 ........... 终于有人提到 OneDrive 了,这个可以劫持的有好几个. 此外这个位置User权限就可以写. 而且,他的启动属性也是User就可以改.... 我是不是说多了?
劫持的太多了,onedrive这个还不算什么,国内杀软默认都会优化OneDrive的自启动,不适合用于持久化
游客
登录 | 注册 方可回帖
返回