郑重声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,如果您不同意请关闭该页面!任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!

DLL劫持

DLL劫持一直深受黑客们的喜欢,利用此技术可以实现启动木马后门,游戏外挂插件的注入,绕过UAC等操作。

全文约定:全文中系统盘所在的位置默认为C盘

DLL加载顺序

DLL是以文件的形式存在在硬盘中,那么应用程序又是如何索引所需的DLL呢?其实,Microsoft已在此处完整记录了DLL搜索顺序。

微软的DLL劫持分为三个阶段

  • 无保护阶段:Windows XP SP2之前
  • 保护阶段:Windows XP SP2之后,Windows 7之前
  • 进一步保护阶段:Windows 7之后

Windows XP SP2之前

  1. 进程对应的应用程序所在目录;
  2. 加载 DLL 时所在的当前目录;
  3. 系统目录即 SYSTEM32 目录(通过 GetSystemDirectory 获取);
  4. 16位系统目录即 SYSTEM 目录;
  5. Windows目录(通过 GetWindowsDirectory 获取);
  6. PATH环境变量中的各个目录;

Windows XP SP2之后

微软为了防止DLL劫持漏洞的产生,在XP SP2之后,添加了一个SafeDllSearchMode的注册表属性。注册表路径如下:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SafeDllSearchMode

当SafeDllSearchMode的值设置为1,即安全DLL搜索模式开启时,查找DLL的目录顺序如下:

  1. 应用程序所在目录;
  2. 系统目录SYSTEM32 目录;
  3. 16位系统目录即SYSTEM 目录。该项只是为了向前兼容的处理,可以不考虑;
  4. Windows目录。通常是C:\Windows
  5. 加载 DLL 时所在的当前目录;
  6. 环境变量PATH中所有目录。需要注意的是,这里不包括App Paths注册表项指定的应用程序路径。

PS:"安全DLL查找模式"默认是启用的

Windows 7之后

微软为了更进一步的防御系统的DLL被劫持,将一些容易被劫持的系统DLL写进了一个注册表项中,那么凡是此项下的DLL文件就会被禁止从EXE自身所在的目录下调用,而只能从系统目录即SYSTEM32目录下调用。注册表路径如下:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs

Windows 10中的如下

image-20200921151524382

如何寻找DLL劫持

劫持系统DLL

要分析一个应用程序是否存在劫持系统DLL的漏洞,需要这么几个步骤

  • 启动应用程序
  • 使用Process Explorer等类似软件查看该应用程序启动后加载的动态链接库。
  • 从该应用程序已经加载的DLL列表中,查找在上述“KnownDLLs注册表项”中不存在的DLL。
  • 编写从上一步获取到的DLL的劫持DLL。
  • 将编写好的劫持DLL放到该应用程序目录下,重新启动该应用程序,检测是否劫持成功。

如果对以上步骤都没问题还是没有实现劫持的话,具体可能有一下情况

  • DLL不在KnownDLLs注册表中但是已经被微软做了保护,比如ntdll.dll等系统核心dll
  • 宿主进程在调用LoadLibrary函数时使用了“绝对路径”
  • 宿主进程对调用的DLL进行了校检,比如文件MD5、HASH等值
  • 宿主调用DLL时使用了SetDllDirectory函数把当前目录从DLL的搜索顺序列表中删除

劫持应用DLL

劫持这个DLL就方便多了,只要宿主没有对自己的DLL做校检的话就可以进行劫持替换

手动寻找

由于Windows 10做了很多限制,我们使用Windows 7来测试会方便很多,如果是新的Windows 7系统需要打个补丁,不然用不了Process Monitor

https://www.microsoft.com/en-us/download/confirmation.aspx?id=46148

利用NDP461-KB3102438-Web.exe程序进行进行测试

#微软下载地址
http://www.microsoft.com/zh-cn/download/details.aspx?id=49981&134b2bb0-86c1-fe9f-d523-281faef41695=1&fa43d42b-25b5-4a42-fe9b-1634f450f5ee=True
#备用下载地址
XXX

然后使用Process Monitor做如下设置

Include the following filters:
Operation is CreateFile
Operation is LoadImage
Path contains .cpl
Path contains .dll
Path contains .drv
Path contains .exe
Path contains .ocx
Path contains .scr
Path contains .sys

Exclude the following filters:
Process Name is procmon.exe
Process Name is Procmon64.exe
Process Name is System
Process Name is not NDP461-KB3102438-Web.exe //这个是你要测试的进程
Operation begins with IRP_MJ_
Operation begins with FASTIO_
Result is SUCCESS
Path ends with pagefile.sys

设置Exclude Result is SUCCESS后会只显示NAME NOT FOUND项,也就是只查看未成功加载的dll项,即KnownDLLs的列表中不包含的dll名称,可用于查找存在漏洞的dll路径

image-20201113145850843

可以看到NDP461-KB3102438-Web.exe在启动的过程中会加载下图中框起来的DLL,并且DLL的路径和这个进程在相同文件夹,同时显示NAME NOT FOUND,表示无法找到该文件,加载失败,这就说明这几个DLL是可以进行劫持的

image-20201113150057290

劫持测试

既然发现了劫持的DLL,我们就可以进程初步演示了,搞一个执行计算器的DLL然后把它改名为CRYPTSP.dll,接着运行程序即可达到劫持的作用

image-20201113151256951

实战化利用

如果动手过的小伙伴可以发现,如果我们吧CRYPTSP.dll的名称改成VERSION.dll的时候用来劫持的话,会发现报错。

image-20201113151835798

主要的原因是测试DLL只有一个加载的时候执行计算器的函数,而并没有劫持目标上面的所有导出函数,所以当我们找到了一个可以劫持的DLL的时候,需要用脚本一键生成劫持cpp文件后进行编译,以下是对系统中的twain_32的一键生成方式的演示

image-20201113152556376

导出后我们就可以把免杀代码放到这个位置然后编译即可

image-20201113152811232

参考文章

https://github.com/sensepost/rattler
https://3gstudent.github.io/DLL%E5%8A%AB%E6%8C%81%E6%BC%8F%E6%B4%9E%E8%87%AA%E5%8A%A8%E5%8C%96%E8%AF%86%E5%88%AB%E5%B7%A5%E5%85%B7Rattler%E6%B5%8B%E8%AF%95/