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

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

2020-7-16 22:45
25009

本文将介绍动态链接库(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是一个包含可被多个程序同时使用的代码和数据的库。(定义源于Microsoft

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

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

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

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

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

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

如果开发者想要从C:\Windows\System32\加载 DLL,但并没有写清楚让程序这么做,那么程序安装目录下的恶意DLL就会优先于System32下的合法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劫持。

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

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

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

重复上述过程:

发现以下针对Microsoft Teams的DLL劫持:

注意:我这里修改了下PowerShell脚本,终止的进程是Teams.exe,启动的进程是Update.exe

重复以上关键步骤,发现针对Visual Studio Code的劫持,如下:

我发现Slack、Microsoft Teams和Visual Studio Code都会出现以下DLL劫持:

我觉得很有趣,尝试挖掘造成此现象的底层原因。

我观察了下Slack加载WINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dllcscapi.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有关。

该结构体可被传递至__delayLoadHelper2,后者会通过LoadLibrary/GetProcAddress加载特定DLL,并且会修正延迟加载导入地址表(IAT)中导入函数的地址。

查找其他对ImgDelayDescr结构体的引用,发现__delayLoadHelper2调用,后者之后调用了ResolveDelayLoadedAPI。为方便理解,我重命名了函数名、类型和变量。

Ghidra中查看__delayLoadHelper2和ResolveDelayLoadedAPI

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

ProcMon中查看__delayLoadHelper2和ResolveDelayLoadedAPI

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

看到有意思的点了吗?shell32.dll加载了LINKINFO.dllLINKINFO.dll加载了ntshrui.dllntshrui.dll最后加载了srvcli.dll。 最后我们看到共有的针对cscapi.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劫持:

Microsoft Teams中,存在以下DLL劫持:

Visual Studio Code中,存在以下DLL劫持:

另外,我发现使用NetShareEnumNetShareGetInfo的程序会引入cscapi.dll劫持,这是由硬编码的LoadLibrary调用导致的,并且我用Ghidra和PoC确认了该结论。

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

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

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

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

原文作者:Justin Bui

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

翻译:看雪翻译小组 SpearMint

校对:看雪翻译小组 OsWalker

 
 
 
 
 
 
 
 
 
 
 

[招生]系统0day安全班,企业级设备固件漏洞挖掘,Linux平台漏洞挖掘!

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