Windows DLL劫持 – 作者:May0x61

#Windows DLL劫持#

译文声明

本文是翻译文章,文章原作者Wietze,文章来源:www.wietzebeukema.nl

原文地址:https://www.wietzebeukema.nl/blog/hijacking-dlls-in-windows

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

DLL劫持是一种流行的执行恶意payload的技术。这篇文章列举了Windows 10(1909)上将近300个容易受DLL劫持影响可执行文件,同时展示了如何使用几行VBScript绕过UAC以提升的权限执行某些劫持的DLL。

##DLL劫持##

首先,让我们弄清定义。从最广泛的意义上讲,DLL劫持是欺骗合法(受信任)的应用程序以加载任意DLL。诸如DLL搜索顺序劫持,DLL加载顺序劫持,DLL Spoofing,DLL Injection和DLL Side-Loading等术语经常被误认为是相同的。这些术语充其量只能描述DLL劫持的特定情况,但通常被互换使用,因此通常情况下使用不正确。概括地说,DLL劫持更为准确,因为DLL劫持始终涉及从合法DLL中接管DLL。

已经发现攻击者为了不同的原因以不同的方式使用DLL劫持。动机包括执行:通过受信任的可执行文件执行恶意代码可能不太会引起报警,在某些情况下甚至绕过应用程序白名单功能,例如AppLocker[[1]](https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/applocker/applocker-overview)),以获得持久性(如果目标应用程序已预先安装并定期运行,恶意代码也会正常运行)和特权提升(如果目标应用程序在提升的权限下运行,那么恶意代码也会运行)。

DLL劫持有多种方法可供选择,成功的方法取决于如何配置应用程序以加载其所需的DLL。可能的方法包括:

**(1)DLL替换**:使用恶意的DLL替换合法的DLL,可以将其与DLL代理[[2]](https://kevinalmansa.github.io/application%20security/DLL-Proxying/)组合使用,以确保原始DLL的所有功能保持不变。

**(2)DLL搜索顺序劫持**:在不带路径的应用程序指定的DLL中,以特定顺序在固定位置搜索[[3]](https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order)。通过将恶意的DLL放在实际DLL之前的搜索位置,劫持了搜索顺序。有时这包括目标应用程序的工作目录。

**(3)Phantom DLL劫持**:

Phantom DLL劫持:使用恶意的DLL来代替合法应用程序尝试加载的丢失或不存在的DLL[[4]](http://www.hexacorn.com/blog/2013/12/08/beyond-good-ol-run-key-part-5/)。

**(4)DLL重定向**:通过编辑改变DLL被搜索的位置,例如%PATH%环境变量,或.exe.manifest/.exe.local文件,以包括含有恶意DLL[[5]](https://docs.microsoft.com/en-gb/windows/win32/sbscs/application-manifests)[ [6]](https://docs.microsoft.com/en-gb/windows/win32/dlls/dynamic-link-library-redirection)。

**(5)WinSxS DLL替换**:用目标DLL的相关WinSxS文件夹中的恶意DLL替换合法的DLL。通常称为DLL Side-Loading[[7]](https://www.fireeye.com/content/dam/fireeye-www/global/en/current-threats/pdfs/rpt-dll-sideloading.pdf)。

**(6)相对路径DLL劫持**:复制(或重命名)合法应用程序到恶意DLL旁的用户可写的文件夹,使用方式类似于(签名)二进制代理执行[[8]](https://attack.mitre.org/techniques/T1218/),这有时候被称为“bring your own LOLbin”[[9]](https://www.microsoft.com/security/blog/2019/09/26/bring-your-own-lolbin-multi-stage-fileless-nodersok-campaign-delivers-rare-node-js-based-malware/)。

##查找易受攻击的可执行文件##

这项工作最大的挑战是找到可以在默认用户权限下被利用的易受攻击的可执行文件。在Windows上定位预安装的系统可执行文件时,通常不包括上一节的第一种方法,而方法2和3中符合条件的任何文件夹都必须是用户可写的,方法4和5中的文件和文件夹也应该是用户可写的,通常情况下没有这么好的条件。

这就只剩下第六种方法,这是最弱的一种,本文其余部分将重点讨论。尽管通常不适合获得持久性或特权升级,但经常在实际攻击中看到它。就拿OceanLotus/APT32,在2019年年底已被发现使用合法rekeywiz.exe启动恶意的duser.dll[[10](https://twitter.com/0xCARNAGE/status/1203882560176218113), [11](https://any.run/report/f08ccc040c8d8db60f30a6d1026aa6523e97c6cf52b1b30f083a830a0a65a3a9/3abfc241-3ab0-4016-acbb-040b44199d52)]。在这种情况下,恶意软件会嵌入到合法软件并将其丢弃到磁盘上,采用“bring your own LOLbin”方法(另一种实现方法是从\system32\文件夹中复制合法可执行文件,前提是该可执行文件还未修补)。

为防止此技术在新版本上利用成功,需要确定容易受到此类DLL劫持的可执行文件。这将为红队成员提供新的手段,但更重要的是,它将使威胁猎手和防御者能够采取适当措施进行侦查和预防。

##方法##

为了集中精力,将分析的可执行路径限定为c:\windows\system32\。在Windows 10 v1909实例上,该路径总共包含616个可执行文件,如果仅考虑已签名的应用程序,则包括613个可执行文件。

为了监视每个进程加载哪些DLL,我们将使用众所周知的Procmon[[12]](https://docs.microsoft.com/en-us/sysinternals/downloads/procmon)工具。该方法的步骤是:(1)将受信任的可执行文件复制到用户可写的位置;(2)运行复制的可执行文件;(3)使用Procmon识别在用户可写位置中寻找的DLL。

![](https://www.wietzebeukema.nl/assets/2020-06-22-procmon.png)

*使用Procmon查看winsat.exe副本在c:\users\wietze\downloads\路径加载的dll列表。*

这使我们能够识别每个应用程序查询的所有DLL,它们将是所有潜在的可劫持DLL对象。但是并不能自动遵循所有这些都已加载(并因此执行)的情况。找出正确加载了哪些DLL的最可靠方法是编译我们自己的DLL版本,并在成功加载后将其写入唯一文件。如果我们随后对所有目标可执行文件和DLL重复上述方法,则可以收集到一个**,告诉我们已确认哪些DLL容易受到DLL劫持。

编译现有DLL的自定义版本比听起来更具挑战性,因为如果缺少程序或入口点,许多可执行文件将无法加载此类DLL。诸如DLL Export Viewer[[13]](https://www.nirsoft.net/utils/dll_export_viewer.html)之类的工具可用于枚举所有外部函数名称和合法DLL的序数,以确保我们编译的DLL遵循相同的格式,将最大程度地成功加载它。

![](https://www.wietzebeukema.nl/assets/2020-06-22-dxgi-dll-c-code.jpg)

*自己的dxgi.dll版本的示例C代码,该文件显示在winsat.exe的Procmon记录中。*

总结来说,采用的方法是:

![](https://www.wietzebeukema.nl/assets/2020-06-22-approach.svg)

可以在GitHub[[14]](https://www.github.com/wietze/windows-dll-hijacking/)上找到具有更详尽的技术说明的完整代码。

##确定DLL劫持的候选对象##

下表列Windows 10 v1909的c:\windows\system32中易受“相对路径DLL劫持”影响所有可执行文件。每个可执行文件的旁边是一个或多个可以被劫持的DLL,以及被调用的DLL的过程。如前一节所述,这些不仅仅是理论上的目标,它们已经过测试并确认是有效的。该列表包括287个可执行文件和263个唯一的DLL。

[https://github.com/wietze/windows-dll-hijacking/blob/master/dll_hijacking_candidates.csv)](https://github.com/wietze/windows-dll-hijacking/blob/master/dll_hijacking_candidates.csv“dll_hijacking_candidates.csv”)

一些警告:

– 通过简单地运行每个可执行文件即可执行测试,而无需指定任何参数,也无需进一步的用户交互。这就解释了为什么清单中没有经过充分记录的xwizard.exe的DLL劫持[[15]](http://www.hexacorn.com/blog/2017/07/31/the-wizard-of-x-oppa-plugx-style/),因为它需要两个(任意)参数才能起作用。

– 有些应用程序带有GUI,或者执行了其他二进制文件的可视元素。这还包括错误消息:可能缺少必需的DLL,并且被劫持的DLL显然缺少原始功能。攻击者不太可能针对此类应用程序做DLL劫持。

– 未考虑使用C++编写原始版本的DLL。完整列表的CSV版本可在GitHub[[14]](https://www.github.com/wietze/windows-dll-hijacking/)上找到。

##结合UAC绕过技术##

找到所有这些可执行文件后,最多使我们能够通过受信任的程序执行代码。但是,如果结合UAC绕过技术一起使用,也有可能获得提升的权限。

Windows Vista中引入了用户帐户控制(UAC)[[16]](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works)作为一项安全功能,它要求用户通过提示进行确认,然后才能将以普通特权运行的进程提升为更高特权。在用户抱怨执行任意任务时UAC提示泛滥之后,Microsoft 在Windows 7中引入了自动提升功能,如果它们位于受信任的目录(例如c:\windows\system32)中,它将自动提升某些进程的权限。

考虑到这一点,您可以尝试通过使用标记为自动提升的可执行文件来尝试以提升的特权运行任意代码,该可执行文件也容易受到DLL劫持的影响。如上一节所述,大约有35种此类可执行文件。要解决的问题是受信任的目录:自动提升可执行文件和自定义DLL都必须位于受信任的目录中,但是这些都不是用户可写的。

关于绕过UAC有一些出色的研究,我最喜欢的技术之一是使用尾随空格来模拟受信任的目录[[17]](https://medium.com/tenable-techblog/uac-bypass-by-mocking-trusted-directories-24a96675f6e)。我建议阅读完整的博客文章,但这归结为用户能够创建并且自动提升权限,并放置在可执行文件信任的位置。

这是否是一个适当的安全漏洞,尚有待商榷,Microsoft辩称并非安全漏洞[[18]](https://msdn.microsoft.com/en-us/library/cc751383.aspx),但这至少是一个缺陷,因为大多数(非企业)Windows计算机默认都使用“管理员帐户”。

无论哪种方式,这都为我们提供了一种极好的方法,通过它可以使DLL劫持更加强大。请注意,带有尾随空格的文件夹无法在Windows上通过传统方式创建。您可以像原始研究人员一样,编译一些C语言来完成此操作,但事实证明,VBScript实际上也可以为我们完成此操作。以下概念验证表明,仅需几行代码,您就可以使它起作用:

Set oFSO = CreateObject(“Scripting.FileSystemObject”)

Set wshshell = wscript.createobject(“WScript.Shell”)

‘ Get target binary and payload

WScript.StdOut.Write(“System32 binary: “)

strBinary = WScript.StdIn.ReadLine()

WScript.StdOut.Write(“Path to your DLL: “)

strDLL = WScript.StdIn.ReadLine()

‘ Create folders

Const target = “c:\windows \”

target_sys32 = (target & “system32\”)

target_binary = (target_sys32 & strBinary)

If Not oFSO.FolderExists(target) Then oFSO.CreateFolder target End If

If Not oFSO.FolderExists(target_sys32) Then oFSO.CreateFolder target_sys32 End If

‘ Copy legit binary and evil DLL

oFSO.CopyFile (“c:\windows\system32\” & strBinary), target_binary

oFSO.CopyFile strDLL, target_sys32

‘ Run, Forrest, Run!

wshshell.Run(“””” & target_binary & “”””)

‘ Clean files

WScript.StdOut.Write(“Clean up? (press enter to continue)”)

WScript.StdIn.ReadLine()

wshshell.Run(“powershell /c “”rm -r “”””\\?\” & target & “”””””””) ‘Deletion using VBScript is problematic, use PowerShell instead

下面的屏幕截图显示了脚本的执行情况。

![](https://www.wietzebeukema.nl/assets/2020-06-22-winsat-dxgi-uac-bypass.jpg)

*示例显示了合法的winsat.exe从模拟的受信任目录加载了恶意dxgi.dll之后,没有得到任何UAC提示后,提升了权限。*

在CSV表中,在第一列中标记了自动提升成功的所有可执行文件/DLL组合。超过160种可能的组合,有很多选择。

##预防和发现##

一种防止DLL劫持发生的简单方法是使应用程序始终使用绝对路径而不是相对路径。尽管某些应用程序(尤其是可移植的应用程序)并非总是能够做到这一点,但是位于\system32\同一文件夹中并依赖于这些DLL的应用程序没有其他借口。更好的选择(似乎只有很少的Windows可执行文件可以这样做)是在加载所有DLL之前先对其进行验证(例如通过检查其签名),这将在很大程度上消除该问题。

但是,正如我们所看到的,攻击者仍然可以使用被利用的合法/受信任应用程序的旧版本。因此,即使每个应用程序从现在开始在加载它们之前开始检查其DLL,我们仍然必须处理此问题。

因此,让我们专注于检测。可以从意外路径中寻找创建或加载前面提到的任何DLL的途径,尤其是在诸如的临时位置%appdata%。毕竟,可以更改加载DLL的(合法)应用程序的名称,但是DLL的文件名始终是固定的。可以在此处找到一个示例Sigma规则[[19]](https://github.com/wietze/windows-dll-hijacking/blob/master/possible_windows_dll_hijacking.yml),它成功检测到我们的DLL劫持,尽管如您所见,它的伸缩性不是很好,并且很容易出现误报。通过查找意外位置中是否存在Microsoft签名的二进制文件,通过此类Microsoft签名的二进制文件(无论位置如何)从意外位置加载DLL,可以采用更通用的方法。

最后,通过查找/windows/文件夹中或该空格中结尾的任何文件夹中的任何行为,可以轻松可靠地检测到已证明的UAC旁路技术。如前所述,带有空格结尾的Windows文件夹无法通过常规方式创建,因此应该很少,并且总是可疑的。将您的UAC模式设置为“始终通知”(比默认值高)将阻止此方法和其他类似的UAC绕过技术的利用。

来源:freebuf.com 2020-12-14 23:44:19 by: May0x61

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论