发布于2022年11月8日2年前 0x00 前言 最近来自SensePost的Chris Le Roy开发了一个工具:Rattler,可以用来自动识别DLL中是否存在预加载漏洞(也可以理解为DLL劫持漏洞,这是本文使用的术语)。虽然DLL劫持漏洞已经不是什么新技术了,最早可以追溯到2010年,但是我对自动化很感兴趣,所以对它做了进一步的研究。 本文将阐明DLL劫持漏洞的原理,分析实例,测试自动化工具Rattler,分享经验,并测试一个带有该漏洞的软件——Explorer套件安装包。 注: 套件安装包包含CFF资源管理器,这是免费的,常用于编辑PE文件格式。最近一次更新是在2012年11月18日,是一个比较小的工具。 对于分析PE文件格式,建议使用作者的另一个更专业的工具:Cerbero Profiler。 克里斯罗伊介绍了拉特勒的博客地址: https://sense post . com/blog/2016/rattler识别并利用dll预加载漏洞/ Chris Roy还介绍了开普敦河畔的Rattler,简要介绍如下: http://www.bsidescapetown.co.za/speaker/chris-le-roy/ 0x01 简介 DLL劫持漏洞根源 程序在调用DLL时没有指定DLL的完整路径。 SafeDllSearchMode 从WindowsXPSP2开始,默认情况下会打开SafeDllSearchMode。SafeDllSearchMode的存在是为了防止XP时代就存在的DLL劫持漏洞。 注: 强制关闭SafeDllSearchMode的方法: 创建注册表项 HKEY _ LOCAL _ MACHINE \ System \ current Control set \ Control \ Session Manager \ SafeDllSearchMode 将值设置为0 当程序调用DLL时,如果没有指定DLL的完整路径,系统将按照固定的搜索顺序搜索DLL。 如果打开了SafeDllSearchMode,程序将依次从以下位置查找DLL文件: 从中加载应用程序的目录 系统目录 16位系统目录 Windows目录 当前目录 PATH环境变量中列出的目录 如果关闭,请从以下位置查找DLL文件: 从中加载应用程序的目录 当前目录 系统目录 16位系统目录 Windows目录 PATH环境变量中列出的目录 参见: https://msdn . Microsoft . com/en-us/library/ms 682586(vs . 85)。aspx KnownDLLs 注册表位置: HKEY _ LOCAL _ MACHINE \ SYSTEM \ current Control set \ Control \ Session Manager \ known dlls KnownDLLs注册表项包含一系列常见的系统dll,如usp10.dll、lpk.dll、shell32.dll和user32.dll。 注: 如果您创建了注册表项 HKEY _ LOCAL _ MACHINE \ SYSTEM \ current Control set \ Control \ Session Manager \ excludefromnowndlls 并指定特定的dll名称,这可以使KnownDLLs列表中同名的dll保护无效。 修改后需要重启才能生效。 SafeDllSearchMode+KnownDLLs 两者的结合可以用来防止系统dll的劫持。 注: 系统dll指的是排除ExcludeFromKnownDlls项后KnownDLLs注册表项下包含的dll列表。 如果被调用的dll是“不常见”的,即没有出现在Knowndlls列表中,那么不管SafeDllSearchMode是否打开,DLL搜索的第一顺序都是程序的当前目录,这里存在一个DLL劫持漏洞: 预先在程序的同级目录中放置一个同名的dll,在启动的过程中会先加载,实现劫持。 注: 这里所说的DLL劫持漏洞并没有被微软直接修复。个人认为原因如下: 1.这是一个开发者的错误,改成绝对路径就可以避免这个问题。 2.利用该漏洞的前提是攻击者能够将文件放在同一个目录中,这意味着系统已被攻破。 3.如果直接修复,可能会影响到老版本的程序,兼容性不好。 注: 这篇文章对澄清上述顺序有很大帮助: http://www.freebuf.com/articles/78807.html 0x02 利用实例 接下来,编写一个DLL劫持漏洞的示例来演示如何利用它。 测试dll: 使用dll模板,具体代码省略,加载成功后会弹出计算器。 测试程序的C代码如下: #include 'stdafx.h ' #包括 int main() { HMODULE hdll lib=LoadLibrary(_ T(' kernel 32 . dll ')); 中频(hDllLib) { FARPROC FP fun=GetProcAddress(hDllLib,' GetVersion '); DWORD dw version=(* fpFun)(); DWORD dwWindowsMajorVersion=(DWORD)(LOBYTE(LOWORD(dw version))); DWORD dwWindowsMinorVersion=(DWORD)(hi byte(LOWORD(dw version))); printf('版本:%d,%d \n ',dwWindowsMajorVersion,dwWindowsMinorVersion); 免费图书馆(hDllLib); } h module hdlllib 2=LoadLibrary(_ T(' cryptsp . dll ')); free library(hdlllib 2); 返回0; } 程序通过LoadLibrary分别调用Kernel32.dll和CRYPTSP.dll。 实际测试: 将测试dll重命名为Kernel32.dll,放在程序的同一个目录下,如图运行。 因为Kernel32.dll出现在KnownDLLs列表中,所以程序的同一个目录中的Kernel32.dll不会被加载。 然后将测试dll重命名为CRYPTSP.dll,放在程序的同一个目录下,如图运行。 因为CRYPTSP.dll不在KnownDLLs列表中,所以加载程序同目录下的CRYPTSP.dll,计算器弹出成功。 0x03 实际利用 本节通过实例介绍如何使用进程监视器查找程序中的DLL劫持漏洞。测试示例是Chris Le Roy在他介绍Rattler的博客中提到的NDP461-KB3102438-Web.exe。 博客地址如下: https://sense post . com/blog/2016/rattler识别并利用dll预加载漏洞/ NDP461-KB3102438-Web.exe的下载地址: http://www.microsoft.com/zh-cn/download/details.aspx?id=49981134 B2 bb 0-86 C1-fe9f-d523-281 faef 41695=1fa 43d 42b-25 b5-4a 42-fe9b-1634 f 450 F5 ee=True 使用过程监视器进行以下设置: 包括以下过滤器: 操作是创建文件 操作是LoadImage 路径包含。偏光镜 路径包含。动态链接库 路径包含。drv 路径包含。可执行程序的扩展名 路径包含。ocx 路径包含。可控硅整流器(Silicon Controlled Rectifier) 路径包含。[计]系统复制命令(system的简写) 排除以下过滤器: 过程名称是procmon.exe 过程名称是Procmon64.exe 进程名为System 操作从IRP_MJ_开始 操作从FASTIO_开始 结果就是成功 路径以pagefile.sys结尾 参考地址: https://msdn.microsoft.com/library/ff919712 注: 设置排除结果为成功后,只显示名称未找到项,即只查看未成功加载的dll项,即未包含在KnownDLLs列表中的dll名称可用于查找易受攻击dll的路径。 画 NDP461-KB3102438-Web.exe启动后,检查过程监视器,如图所示 可以看到NDP461-KB3102438-Web.exe在启动时会加载CRYPTSP.dll,同时会显示NAME NOT FOUND,表示找不到文件,加载失败。 现在将测试dll重命名为CRYPTSP.dll,并将其放在NDP461-KB3102438-Web.exe的同一个目录中。 打开过程监视器,设置过滤器,删除排除结果成功项目,再次启动NDP461-KB3102438-Web.exe并记录。 下图显示C:\test\CRYPTSP。dll已经加载成功,结果成功,DLL劫持成功。 如下图,程序在执行过程中成功弹出计算器。 0x04 程序自动化实现 通过进程监视器检查DLL劫持漏洞是一种直接的方法。但是对于较大的程序来说,加载的dll数量较大,手动查找不太现实,也很费力。所以如果能通过程序实现上述过程,效率就能大大提高,这就是Rattler解决的问题。 项目地址: https://github.com/sensepost/rattler 思路: 枚举进程调用的dll列表,并解析dll的名称。 将测试dll重命名为列表中的dll名称。 再次启动程序,检查流程calc.exe是否创建成功。如果成功了,说明存在漏洞;否则,它不存在。 实际测试: 用Visual Studio编译Rattler 把payload.dll放在同一级目录中。 payload.dll中的下载地址: https://github . com/sense post/rattler/releases/download/v 1.0/payload . dll 在管理员权限的cmd下运行命令: Rattler.exeNDP461-KB3102438-Web.exe 1 注: 因为NDP461-KB3102438-Web.exe需要管理员权限才能运行,所以cmd也需要管理员权限。 如下图所示,自动查找预加载漏洞的dll列表。 注: 在反复启动该过程的过程中,calc.exe没有正常关机,所以得到的结果比实际的多。 补充: 的下载NDP461-KB3102438-Web.exe通常位于Downloads文件夹下,所以只要事先把CRYPTSP.dll放在这个目录下,用户下载运行NDP461-KB3102438-Web.exe时就可以加载CRYPTSP.dll了。 同时,安装NDP461-KB3102438-Web.exe需要管理员权限,所以此时,CRYPTSP.dll也获得了管理员权限。 0x05 验证测试 掌握这个方法后,再测试其他程序,比如CFF资源管理器的安装包资源管理器套件。 下载地址: http://www.ntcore.com/exsuite.php 还可以使用进程监视器来查看启动过程中CFF浏览器的安装包ExplorerSuite.exe的运行情况。 如图,找到ExplorerSuite.exe启动时加载的dll列表。 经过实际测试,重命名payload.dll为apphelp.dll或dwmapi.dll可以触发有效载荷和弹出计算器。 自动化程序测试: 如图,获取有劫持漏洞的dll列表。 注: 在重复启动该过程的过程中,calc.exe是常闭的,因此获得的结果是准确的。 0x06 防御 1、开发者需要注意的问题: 调用第三方DLL时,使用LoadLibrary API加载DLL时会使用绝对路径。类似的情况还有其他API如LoadLibrary EX、CreateProcess、ShellExecute等。所有需要使用的dll都放在应用程序所在的目录下,而不是放在系统目录或其他目录下。 调用系统DLL时使用绝对路径。 当程序启动时,调用API SetDllDirectory(L " ")从DLL加载序列中移除当前目录。 补充: 从Windows 7的KB2533623补丁开始,微软更新了三个新的API来解决DLL劫持问题:SetDefaultDLldirectories、AddDllDirectory和RemoveDllDirectory,可以有效避免DLL劫持问题。 但是这些API只能在Windows7和Server2008上用KB2533623补丁。 查看详情: https://support.microsoft.com/zh-cn/kb/2533623 2、用户需要注意的问题: 注意浏览器下载目录中是否有可疑的dll,防止其劫持下载的安装程序。 对于“不可信”的程序,建议使用进程监视器或Rattler来检查DLL劫持漏洞。 0x07 小结 在研究DLL劫持漏洞原理的过程中,我走了一段很短的弯路。一些材料提到 如果进程试图加载的DLL不存在,该进程仍将尝试加载当前目录中的DLL,这是SafeDllSearchMode无法阻止的。 这使我产生了以下问题: 这里所说的“不存在的dll”指的是什么dll?系统中不存在的Dll?但是,CRYPTSP.dll是默认包含的dll。 “SafeDllSearchMode无法阻止”DLL劫持到底是什么意思?DLL劫持有很多种吗?有多少? 幸运的是,这些问题最终得到了解决。希望这篇文章也能帮助到有同样疑惑的人。 使用DLL劫持漏洞自动识别工具Rattler测试常用工具,可以快速找出存在的漏洞位置,高效便捷,值得测试。 留下回复
创建帐户或登录后发表意见