浅析DLL劫持与持久化
DLL 劫持简介
Windows加载DLL的规则
首先会尝试从当前程序所在的目录加载DLL,如果没找到则在Windows系统目录中查找,如果还是没有则会去环境变量中列出的各个目录下查找
DLL 劫持的目的
Execution
常见的白加黑,利用可信任的(最好被微软签名过)可执行程序加载恶意 DLL
Persistence
劫持目标操作系统中已预先安装并且会定期运行的软件所需加载的 DLL
Privilege escalation
如果目标应用程序正以高权限运行,劫持后的恶意代码也会以相应的权限执行
DLL 劫持的方法
1. DLL replacement
用恶意的DLL替换掉合法的DLL,可以将其与 DLL Proxying 结合使用,以确保原DLL的所有功能均保持不变。
2. DLL search order hijacking
当应用程序加载DLL的时候,如果没有带指定DLL的路径,那么程序将会以特定的顺序依次在指定的路径下搜索待加载的DLL。
通过将恶意DLL放在真实DLL之前的搜索位置,就可以劫持搜索顺序,劫持的目录有时候包括目标应用程序的工作目录。
释放一个恶意 DLL 来代替丢失的或者不存在的 要被合法应用程序加载的DLL。
4. DLL redirection
更改DLL搜索的路径,比如通过编辑 %PATH% 环境变量或 .exe.manifest/.exe.local文件以将搜索路径定位到包含恶意DLL的地方。
5. WinSxS DLL replacement
将目标DLL相关的WinSxS文件夹中的合法的DLL替换为恶意DLL。
此方法通常也被称为 DLL side loading。
6. Relative path DLL Hijacking
将合法的应用程序复制(并有选择地重命名)与恶意的DLL一起放入到用户可写的文件夹中。
在使用方法上,它与(带签名的)二进制代理执行 有相似之处。
它的一个变体是(有点矛盾地称为)“bring your own LOLbin”,其中合法的应用程序带有恶意的DLL(而不是从受害者机器上的合法位置复制)。
攻击手法复现
1. Relative path DLL Hijacking + DLL proxy loading + UAC bypass
首先我们要在系统文件夹中找到容易受到攻击的可执行文件
采用的方法可以参考:https://www.wietzebeukema.nl/blog/hijacking-dlls-in-windows
最后汇总的劫持目标罗列在 这里 ,注意,劫持目标不要带参数,最好也不要带弹窗和任何可视化元素
我选定的测试文件: EASPolicyManagerBrokerHost.exe + InprocLogger.dll
然后要创建一个代理DLL,参考这个项目: https://github.com/rek7/dll-hijacking
首先运行 parse.py 生成导出指令写入 definitions.h,原理可以参考:https://itm4n.github.io/dll-proxying/
然后修改项目内的 ./malicious_dll/dllmain.cpp
文件
原代码这里是借助 powershell 反弹 shell,这大段代码我们都删掉,先简单加个弹框试试效果(代码参考下方弹框截图)
修改好代码后使用 Visual Studio 编译生成 malicious_dll.dll
将该代理 DLL 文件复制到测试目录下重命名为 InprocLogger.dll,原文件重命名为 InprocLogger_.dll
然后尝试直接启动 EASPolicyManagerBrokerHost.exe,可以看到,成功弹框
接着我们再进一步修改代码,方便导入任意 shellcode,参考:https://gist.github.com/securitytube/c956348435cc90b8e1f7
下面以计算器弹窗为例,借助 MSF 生成 shellcode:
msfvenom -a x64 -platform windows -p windows/x64/exec cmd="calc.exe" -f raw
将 shellcode 替换进源码
然后,Bingo!
前面每次运行 EASPolicyManagerBrokerHost.exe 都需要手动授权
现在,我们尝试利用 伪造受信任目录 技术绕过 UAC 以更高权限执行 systemreset.exe 并加载恶意 DLL
简单描述下原理,用户可以通过创建文件夹c:\windows \system32\
(注意路径中包含空格)来自动提升该目录内可执行文件的权限
传统方式无法创建带尾随空格的文件夹,但是我们可以通过C语言代码或者VBScript来完成这一工作
我所用到的代码如下:
脚本运行后成功绕过 UAC 并弹出计算器!
注:最新版本win10上好像行不通了,需要其他 bypass UAC 的方式代替,但是公司现在使用的操作系统版本上还存在这一漏洞
踩坑:
parse.py 文件中的 dumpbin.exe 路径要替换成自己电脑中对应的文件路径
2.
parse.py 文件在windows环境运行出现编码错误时,此处替换成 “gbk"
3.
无法导出头文件时,更换目标 DLL
4. 编译和 shellcode 生成过程中架构环境记得对应
Tips:
这里的 Relative path DLL Hijacking 技术可以替换成常见的白加黑
DLL proxy loading 不仅简化了自定义开发 DLL 的步骤,让攻击者专注于 shellcode 的设计,而且也避免了修改原始 DLL 后可能出现的程序崩溃等错误 ,而且这一技术早在几年前就被实战中用于 APT,比如“绿色版”软件,效果非常好
2. 持久化中的应用
接下来尝试将 DLL 劫持应用到持久化的方法中
这里我选择的突破口是我们日常单击右键出现的上下文菜单:
以我们外网 VDI 默认安装的 7-Zip 为例,借助 Autoruns 定位到 DLL 文件
制作代理 DLL 的方式如上所述,然后将 7-zip 程序目录下的 7-zip.dll 更名为 7-zip_.dll,再将我们制作好的 malicious_dll.dll 更名为 7-zip.dll 复制过去
最后需要重启计算机,因为该DLL一旦被激活就仅被加载到内存中一次,它将继续存在于内存中,直到系统重新启动为止
重启后,对文件单击鼠标右键,win + E 打开资源管理器,或者直接使用 7-zip等操作,都会触发 payload
PS: 测试过程中 explorer.exe 崩了几次,实战中可能还需要做一定的修改
防御措施
应用程序加载 DLL 时应该使用绝对路径而不是相对路径
最好的选择是在应用程序加载所有 DLL 之前先进行验证
启动项中涉及的 DLL 也要定期做检查和校验
检测路径中带有空格的文件夹,提高 UAC 模式并设置为“总是通知”,防止 UAC bypass
最后更新于