深入解析DLL劫持漏洞

 广告位置,咨询qq1101364674

离线阅览:


0×00. 导读2Vz看卫星
DLL劫持是一种古老的技术了,本文是《CVE-2016-0041 Windows 10 PhoneInfo.dll Hijacking Vulnerability》的延伸,介绍了DLL劫持的漏洞原理、漏洞挖掘方法、漏洞利用场景等,同时引入了HaifeiLi关于Chrome/Edge自动下载漏洞的介绍,以及最新版本Edge对DLL注入的缓解措施。本文已在外部发表于乌云知识库,特别感谢tombkeeper在行文思路上的建议。2Vz看卫星
2Vz看卫星
0×01. DLL劫持漏洞介绍2Vz看卫星
1.1 漏洞简介2Vz看卫星
如果在进程尝试加载一个DLL时没有指定DLL的绝对路径,那么Windows会尝试去指定的目录下查找这个DLL;如果攻击者能够控制其中的某一 个目录,并且放一个恶意的DLL文件到这个目录下,这个恶意的DLL便会被进程所加载,从而造成代码执行。这就是所谓的DLL劫持。2Vz看卫星
2Vz看卫星
在Windows XP SP2之前,Windows查找DLL的目录以及对应的顺序如下:2Vz看卫星
1. 进程对应的应用程序所在目录;2Vz看卫星
2. 当前目录(Current Directory);2Vz看卫星
3. 系统目录(通过 GetSystemDirectory 获取);2Vz看卫星
4. 16位系统目录;2Vz看卫星
5. Windows目录(通过 GetWindowsDirectory 获取);2Vz看卫星
6. PATH环境变量中的各个目录;2Vz看卫星
2Vz看卫星
在Windows下,几乎每一种文件类型都会关联一个对应的处理程序,当我们在资源管理器中打开某种特定类型的文件时,与之相关联的处理程序便会被执行,也就是会新建一个进程,进程默认的 Current Directory (当前目录)就是被打开文件所在的目录。在Windows搜索DLL的这些目录中,攻击者最容易控制的当然是 Current Directory 。攻击者可以把恶意的DLL文件和目标文件(如WORD文档)打包在一起,如果受害者进行解压操作,恶意DLL和目标文件就会位于同一个目录,攻击者可以十分方便的实施DLL劫持。2Vz看卫星
2Vz看卫星
由于早期Windows查找DLL文件的顺序并不合理,可以想象DLL劫持漏洞伴随着Windows存在了相当长的时间。然而,在相当长的一段时间 里DLL劫持漏洞并没有受到大家的关注,直到2010年8月,微软发布安全通报2269637,同时网上公布了大量受影响软件的名字,DLL劫持漏洞才开 始进入大家的视野。2Vz看卫星
2Vz看卫星
1.2 漏洞归类2Vz看卫星
DLL劫持漏洞翻译成英文叫做 DLL Hijacking Vulnerability,CWE将其归类为 Untrusted Search Path Vulnerability。如果想要去CVE数据库中搜索DLL劫持漏洞案例,搜索这两个关键词即可。2Vz看卫星
2Vz看卫星
1.3 缓解措施2Vz看卫星
从Windows XP SP2开始,SafeDllSearchMode 默认会被开启。SafeDllSearchMode的开启与否主要影响 Current Directory(当前目录) 在搜索顺序中的位置。开启SafeDllSearchMode后的DLL搜索顺序如下:2Vz看卫星
1. 进程对应的应用程序所在目录;2Vz看卫星
2. 系统目录(通过 GetSystemDirectory 获取);2Vz看卫星
3. 16位系统目录;2Vz看卫星
4. Windows目录(通过 GetWindowsDirectory 获取);2Vz看卫星
5. 当前目录;2Vz看卫星
6. PATH环境变量中的各个目录;2Vz看卫星
2Vz看卫星
启用SafeDllSearchMode之后可以防范大部分DLL劫持,如系统DLL劫持。不过,如果进程尝试加载的DLL并不存在,那么进程仍然会尝试去当前目录加载这个DLL,这是SafeDllSearchMode所无法防范的。不过微软引入了 SetDllDirectory 这个API,给这个API传递一个空字符串就可以将当前目录从DLL搜索顺序中排除掉。2Vz看卫星
2Vz看卫星
Default2Vz看卫星
BOOL WINAPI SetDllDirectory(2Vz看卫星
  _In_opt_ LPCTSTR lpPathName2Vz看卫星
);2Vz看卫星
If the lpPathName parameter is an empty string (""), 2Vz看卫星
the call removes the current directory from the default DLL search order.2Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
52Vz看卫星
BOOL WINAPI SetDllDirectory(2Vz看卫星
  _In_opt_ LPCTSTR lpPathName2Vz看卫星
);2Vz看卫星
If the lpPathName parameter is an empty string (""), 2Vz看卫星
the call removes the current directory from the default DLL search order.2Vz看卫星
1.4 漏洞检查2Vz看卫星
使用Sysinternals工具包中的 Process Monitor(ProcMon)可以十分方便的检测DLL劫持漏洞,只需要设置几个过滤参数即可。2Vz看卫星
1. ProcessName 目标进程的名字;2Vz看卫星
2. Path 文件路径,可以设置为 begins with 当前目录所在路径;2Vz看卫星
3. Result 结果,设置为 NAME NOT FOUND;2Vz看卫星
2Vz看卫星
0×02. DLL劫持漏洞利用场景2Vz看卫星
2.1 针对应用程序安装目录的DLL劫持2Vz看卫星
不管SafeDllSearchMode是否开启,在查找DLL时应用程序本身所在的目录都是最先被搜索的。因此如果能够放一个恶意的DLL文件到程序的安装目录,就可以利用DLL劫持漏洞来执行代码。2Vz看卫星
2Vz看卫星
这种利用场景的要求相对较高,因为大部分程序默认安装到 %ProgramFiles% 或者是 %ProgramFiles(x86)%。这两个目录都需要管理员权限才可以进行写入操作,也就是说在进行DLL劫持之前,要求已经具有代码执行权限。基于这一原因,软件厂商一般不予处理此类问题。2Vz看卫星
2Vz看卫星
这种场景多被一些恶意代码所使用,对常用软件进行DLL劫持可以在一定程度替代自启动功能,同时,利用 白加黑 方式还能逃避安全软件的检测。此外,一些外挂或者破解程序也会采用这种方式进行DLL劫持,例如QQ的一些显IP插件就是通过劫持 msimg32.dll 来实现功能的。2Vz看卫星
2Vz看卫星
2.2 针对文件关联的DLL劫持2Vz看卫星
在Windows下,我们平时使用的各种文件(如MP3音乐、DOC文档、PDF文档、MKV视频等)都有一个与之关联的默认处理软件。当在资源管 理器中打开某种特定类型的文件时,操作系统会自动创建一个进程来处理这个文件,进程对应的程序就是该文件类型关联的默认处理程序,进程的 当前目录 就是被打开文件所在的目录。2Vz看卫星
2Vz看卫星
例如,如果Adobe Acrobat DC关联了.PDF文件类型,那么打开PDF文件时就会自动创建一个Acrobat.exe进程,进程的当前目录(Current Directory)就是PDF文件所在的目录。如果进程尝试加载一个不存在的DLL,根据默认的DLL搜索顺序,进程最终会搜索到PDF文件所在目录(即当前目录),如果该目录下恰好就存在有一个同名的DLL,那么这个DLL就会被进程所加载。这就是所谓的 文件关联型DLL劫持 。2Vz看卫星
2Vz看卫星
相对于 针对应用程序安装目录的DLL劫持,针对文件关联的DLL劫持 的利用条件十分简单,只要放一个恶意的DLL就行了。由于实施这种DLL劫持不需要其他先决条件,许多厂商关注并承认该利用场景下的DLL劫持漏洞。2Vz看卫星
2Vz看卫星
许多流行软件可能仍然存在有这种DLL劫持漏洞:笔者在2015年给12月给Adobe报告了Adobe Acrobat DC 15.009.20077中存在的一个DLL劫持漏洞(CVE-2016-0947),该漏洞由Acrobat.exe进程加载不存在的 updaternotifications.dll所引起。此外,去CVE漏洞库搜索 DLL Hijacking 或者 Untrusted Search Path 也能找到很多案例。2Vz看卫星
2Vz看卫星
2.3 针对安装程序的DLL劫持2Vz看卫星
许多应用程序的安装包程序也存在有DLL劫持漏洞,这种场景与 针对应用程序安装目录的DLL劫持 比较类似,本来也没有什么特殊之处,不过结合后文提到的浏览器自动下载漏洞,其利用条件又变得相对简单了。2Vz看卫星
2Vz看卫星
这里以Notepad++最新的安装包npp.6.9.Installer.exe为例来进行讲解。启动 ProcMon 并设置好过滤器,可以看到npp.6.9.Installer.exe运行后尝试加载了许多DLL,这些都是第一次加载时没有加载成功的。2Vz看卫星
Notepad++安装包npp.6.9.Installer.exe尝试加载但未成功加载的DLL列表2Vz看卫星
2Vz看卫星
仔细观察进程尝试加载这些DLL时产生的调用栈,会发现有的调用栈中存在有 LoadLibrary(Ex),而有的调用栈中却没有。这里选取 Version.dll 和 SHFOLDER.dll 来进行对比说明。npp.6.9.Installer.exe在尝试加载 Version.dll 时产生的调用栈中并没有LoadLibrary(Ex),这是因为DLL并不是被进程动态加载的,而是因为应用程序的导入表直接或者间接导入了这个DLL。在这种利用场景下,伪造DLL的导出表最好与被伪造DLL的导出表完全一致,否则DLL可能无法被进程成功加载(会弹出错误提示消息框)。有一个叫做2Vz看卫星
2Vz看卫星
AheadLib的工具可以十分方便的生成此类DLL的源文件。2Vz看卫星
2Vz看卫星
Default2Vz看卫星
 0   fltmgr.sys      FltAcquirePushLockShared + 0x9072Vz看卫星
 1   fltmgr.sys      FltIsCallbackDataDirty + 0x1f3d2Vz看卫星
 2   fltmgr.sys      FltDeletePushLock + 0x64f2Vz看卫星
 3   ntoskrnl.exe    MmCreateSection + 0x25b12Vz看卫星
 4   ntoskrnl.exe    SeQueryInformationToken + 0xe3e2Vz看卫星
 5   ntoskrnl.exe    ObOpenObjectByName + 0x3062Vz看卫星
 6   ntoskrnl.exe    NtOpenProcessTokenEx + 0x3262Vz看卫星
 7   ntoskrnl.exe    KeSynchronizeExecution + 0x3a232Vz看卫星
 8   ntdll.dll       ZwQueryAttributesFile + 0xa2Vz看卫星
 9   wow64.dll       Wow64EmulateAtlThunk + 0xd2b12Vz看卫星
10   wow64.dll       Wow64SystemServiceEx + 0xd72Vz看卫星
11   wow64cpu.dll    TurboDispatchJumpAddressEnd + 0x2d2Vz看卫星
12   wow64.dll       Wow64SystemServiceEx + 0x1ce2Vz看卫星
13   wow64.dll       Wow64LdrpInitialize + 0x42a2Vz看卫星
14   ntdll.dll       RtlUniform + 0x6e62Vz看卫星
15   ntdll.dll       EtwEventSetInformation + 0x186f82Vz看卫星
16   ntdll.dll       LdrInitializeThunk + 0xe2Vz看卫星
17   ntdll.dll       ZwQueryAttributesFile + 0x122Vz看卫星
18   ntdll.dll       aullrem + 0x1f12Vz看卫星
19   ntdll.dll       aullrem + 0x6cb2Vz看卫星
20   ntdll.dll       aullrem + 0x5652Vz看卫星
21   ntdll.dll       RtlEncodeSystemPointer + 0x4042Vz看卫星
22   ntdll.dll       RtlSetBits + 0xf02Vz看卫星
23   ntdll.dll       RtlSetBits + 0x16b2Vz看卫星
24   ntdll.dll       RtlSetBits + 0x602Vz看卫星
25   ntdll.dll       RtlSetThreadPoolStartFunc + 0x3a12Vz看卫星
26   ntdll.dll       RtlSetUnhandledExceptionFilter + 0x502Vz看卫星
27   ntdll.dll       LdrInitializeThunk + 0x102Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
52Vz看卫星
62Vz看卫星
72Vz看卫星
82Vz看卫星
92Vz看卫星
102Vz看卫星
112Vz看卫星
122Vz看卫星
132Vz看卫星
142Vz看卫星
152Vz看卫星
162Vz看卫星
172Vz看卫星
182Vz看卫星
192Vz看卫星
202Vz看卫星
212Vz看卫星
222Vz看卫星
232Vz看卫星
242Vz看卫星
252Vz看卫星
262Vz看卫星
272Vz看卫星
282Vz看卫星
 0   fltmgr.sys      FltAcquirePushLockShared + 0x9072Vz看卫星
 1   fltmgr.sys      FltIsCallbackDataDirty + 0x1f3d2Vz看卫星
 2   fltmgr.sys      FltDeletePushLock + 0x64f2Vz看卫星
 3   ntoskrnl.exe    MmCreateSection + 0x25b12Vz看卫星
 4   ntoskrnl.exe    SeQueryInformationToken + 0xe3e2Vz看卫星
 5   ntoskrnl.exe    ObOpenObjectByName + 0x3062Vz看卫星
 6   ntoskrnl.exe    NtOpenProcessTokenEx + 0x3262Vz看卫星
 7   ntoskrnl.exe    KeSynchronizeExecution + 0x3a232Vz看卫星
 8   ntdll.dll       ZwQueryAttributesFile + 0xa2Vz看卫星
 9   wow64.dll       Wow64EmulateAtlThunk + 0xd2b12Vz看卫星
10   wow64.dll       Wow64SystemServiceEx + 0xd72Vz看卫星
11   wow64cpu.dll    TurboDispatchJumpAddressEnd + 0x2d2Vz看卫星
12   wow64.dll       Wow64SystemServiceEx + 0x1ce2Vz看卫星
13   wow64.dll       Wow64LdrpInitialize + 0x42a2Vz看卫星
14   ntdll.dll       RtlUniform + 0x6e62Vz看卫星
15   ntdll.dll       EtwEventSetInformation + 0x186f82Vz看卫星
16   ntdll.dll       LdrInitializeThunk + 0xe2Vz看卫星
17   ntdll.dll       ZwQueryAttributesFile + 0x122Vz看卫星
18   ntdll.dll       aullrem + 0x1f12Vz看卫星
19   ntdll.dll       aullrem + 0x6cb2Vz看卫星
20   ntdll.dll       aullrem + 0x5652Vz看卫星
21   ntdll.dll       RtlEncodeSystemPointer + 0x4042Vz看卫星
22   ntdll.dll       RtlSetBits + 0xf02Vz看卫星
23   ntdll.dll       RtlSetBits + 0x16b2Vz看卫星
24   ntdll.dll       RtlSetBits + 0x602Vz看卫星
25   ntdll.dll       RtlSetThreadPoolStartFunc + 0x3a12Vz看卫星
26   ntdll.dll       RtlSetUnhandledExceptionFilter + 0x502Vz看卫星
27   ntdll.dll       LdrInitializeThunk + 0x102Vz看卫星
npp.6.9.Installer.exe在尝试加载 SHFOLDER.dll 时产生的调用栈中存在有 LoadLibrary(Ex),说明这个DLL是被进程所动态加载的。在这种利用场景下,伪造的DLL文件不需要存在任何导出函数即可被成功加载,即使加载后进程内部出错,也是在DLL被成功加载之后的事情。2Vz看卫星
2Vz看卫星
Default2Vz看卫星
 0   fltmgr.sys         FltAcquirePushLockShared + 0x9072Vz看卫星
 1   fltmgr.sys         FltIsCallbackDataDirty + 0x1f3d2Vz看卫星
 2   fltmgr.sys         FltDeletePushLock + 0x64f2Vz看卫星
 3   ntoskrnl.exe       MmCreateSection + 0x25b12Vz看卫星
 4   ntoskrnl.exe       SeQueryInformationToken + 0xe3e2Vz看卫星
 5   ntoskrnl.exe       ObOpenObjectByName + 0x3062Vz看卫星
 6   ntoskrnl.exe       NtOpenProcessTokenEx + 0x3262Vz看卫星
 7   ntoskrnl.exe       KeSynchronizeExecution + 0x3a232Vz看卫星
 8   ntdll.dll          ZwQueryAttributesFile + 0xa2Vz看卫星
 9   wow64.dll          Wow64EmulateAtlThunk + 0xd2b12Vz看卫星
10   wow64.dll          Wow64SystemServiceEx + 0xd72Vz看卫星
11   wow64cpu.dll       TurboDispatchJumpAddressEnd + 0x2d2Vz看卫星
12   wow64.dll          Wow64SystemServiceEx + 0x1ce2Vz看卫星
13   wow64.dll          Wow64LdrpInitialize + 0x42a2Vz看卫星
14   ntdll.dll          RtlUniform + 0x6e62Vz看卫星
15   ntdll.dll          EtwEventSetInformation + 0x186f82Vz看卫星
16   ntdll.dll          LdrInitializeThunk + 0xe2Vz看卫星
17   ntdll.dll          ZwQueryAttributesFile + 0x122Vz看卫星
18   ntdll.dll          aullrem + 0x1f12Vz看卫星
19   ntdll.dll          aullrem + 0x6cb2Vz看卫星
20   ntdll.dll          aullrem + 0x5652Vz看卫星
21   ntdll.dll          RtlLookupAtomInAtomTable + 0x35a2Vz看卫星
22   ntdll.dll          RtlUlonglongByteSwap + 0x6712Vz看卫星
23   KernelBase.dll     LoadLibraryExW + 0x2432Vz看卫星
24   KernelBase.dll     LoadLibraryExA + 0x262Vz看卫星
25   kernel32.dll       LoadLibraryA + 0x312Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
52Vz看卫星
62Vz看卫星
72Vz看卫星
82Vz看卫星
92Vz看卫星
102Vz看卫星
112Vz看卫星
122Vz看卫星
132Vz看卫星
142Vz看卫星
152Vz看卫星
162Vz看卫星
172Vz看卫星
182Vz看卫星
192Vz看卫星
202Vz看卫星
212Vz看卫星
222Vz看卫星
232Vz看卫星
242Vz看卫星
252Vz看卫星
262Vz看卫星
 0   fltmgr.sys         FltAcquirePushLockShared + 0x9072Vz看卫星
 1   fltmgr.sys         FltIsCallbackDataDirty + 0x1f3d2Vz看卫星
 2   fltmgr.sys         FltDeletePushLock + 0x64f2Vz看卫星
 3   ntoskrnl.exe       MmCreateSection + 0x25b12Vz看卫星
 4   ntoskrnl.exe       SeQueryInformationToken + 0xe3e2Vz看卫星
 5   ntoskrnl.exe       ObOpenObjectByName + 0x3062Vz看卫星
 6   ntoskrnl.exe       NtOpenProcessTokenEx + 0x3262Vz看卫星
 7   ntoskrnl.exe       KeSynchronizeExecution + 0x3a232Vz看卫星
 8   ntdll.dll          ZwQueryAttributesFile + 0xa2Vz看卫星
 9   wow64.dll          Wow64EmulateAtlThunk + 0xd2b12Vz看卫星
10   wow64.dll          Wow64SystemServiceEx + 0xd72Vz看卫星
11   wow64cpu.dll       TurboDispatchJumpAddressEnd + 0x2d2Vz看卫星
12   wow64.dll          Wow64SystemServiceEx + 0x1ce2Vz看卫星
13   wow64.dll          Wow64LdrpInitialize + 0x42a2Vz看卫星
14   ntdll.dll          RtlUniform + 0x6e62Vz看卫星
15   ntdll.dll          EtwEventSetInformation + 0x186f82Vz看卫星
16   ntdll.dll          LdrInitializeThunk + 0xe2Vz看卫星
17   ntdll.dll          ZwQueryAttributesFile + 0x122Vz看卫星
18   ntdll.dll          aullrem + 0x1f12Vz看卫星
19   ntdll.dll          aullrem + 0x6cb2Vz看卫星
20   ntdll.dll          aullrem + 0x5652Vz看卫星
21   ntdll.dll          RtlLookupAtomInAtomTable + 0x35a2Vz看卫星
22   ntdll.dll          RtlUlonglongByteSwap + 0x6712Vz看卫星
23   KernelBase.dll     LoadLibraryExW + 0x2432Vz看卫星
24   KernelBase.dll     LoadLibraryExA + 0x262Vz看卫星
25   kernel32.dll       LoadLibraryA + 0x312Vz看卫星
2.4 Microsoft Edge与Google Chrome的自动下载漏洞2Vz看卫星
通过 iframe 可以触发 Microsoft Edge 和 Google Chrome 的自动下载功能,这一特性被@HaifeiLi认为是一个安全漏洞,其在Twitter上发表了很多关于该漏洞的推文,甚至抱怨Chrome和Edge团队忽视这个漏洞的存在。在HaifefiLi的 长期呼吁下,Chrome最终在48.0.2564.82版本中修复了这个漏洞,而截至笔者撰文时Edge似乎仍然没有修复该漏洞。Edge浏览器的默认下载目录为2Vz看卫星
2Vz看卫星
Default2Vz看卫星
C:\Users\Username\Downloads2Vz看卫星
12Vz看卫星
C:\Users\Username\Downloads2Vz看卫星
通过Edge下载 的文件默认都会保存在这个目录下。可以利用Edge的自动下载漏洞下载一个恶意的DLL文件(如Version.dll)到这个目录下,然后利用页面超时 自动跳转功能让Edge跳转到正常页面来诱导用户下载一个正常的安装文件,当用户运行安装程序时恶意的DLL文件便会被进程加载。2Vz看卫星
2Vz看卫星
测试浏览器自动下载漏洞的HTML测试代码如下所示:2Vz看卫星
2Vz看卫星
Default2Vz看卫星
<html>2Vz看卫星
    <head>2Vz看卫星
        <title>Windows Update</title>2Vz看卫星
    </head>2Vz看卫星
    <body>2Vz看卫星
        <iframe src="evil.dll"></iframe>2Vz看卫星
        <script>2Vz看卫星
            setTimeout( function () {2Vz看卫星
                            window.location = "https://get.adobe.com/reader"2Vz看卫星
                        }, 5000);2Vz看卫星
        </script>2Vz看卫星
    </body>2Vz看卫星
</html>2Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
52Vz看卫星
62Vz看卫星
72Vz看卫星
82Vz看卫星
92Vz看卫星
102Vz看卫星
112Vz看卫星
122Vz看卫星
132Vz看卫星
<html>2Vz看卫星
    <head>2Vz看卫星
        <title>Windows Update</title>2Vz看卫星
    </head>2Vz看卫星
    <body>2Vz看卫星
        <iframe src="evil.dll"></iframe>2Vz看卫星
        <script>2Vz看卫星
            setTimeout( function () {2Vz看卫星
                            window.location = "https://get.adobe.com/reader"2Vz看卫星
                        }, 5000);2Vz看卫星
        </script>2Vz看卫星
    </body>2Vz看卫星
</html>2Vz看卫星
在Windows 10下使用Edge打开这个HTML页面,可以看到DLL文件被自动下载到了本地的下载目录中。不过由于DLL没有有效的数字签名,所以Edge会提示这个文件可能存在风险。2Vz看卫星
Windows Edge浏览器自动下载漏洞2Vz看卫星
2Vz看卫星
如果DLL文件具有有效的数字签名,那么Edge就不会这样提示了。在最新版本的Google Chrome(48.0.2564.116 m)上测试发现,不管DLL是否具有有效的数字签名,DLL文件下载之后都需要用户手工确认才会保存,否则会被删除。Chrome和Edge的测试结果汇 总如下:2Vz看卫星
Chrome和Edge自动下载测试结果汇总2Vz看卫星
2Vz看卫星
浏览器的自动下载漏洞还是十分危险的,攻击者甚至只需要诱导用户下载一个恶意的DLL,以后用户在下载目录中执行各种程序时都有可能加载这个DLL。此外,安装程序一般都会请求管理员权限,对于恶意的DLL来说管理员权限似乎是与生俱来的。2Vz看卫星
2Vz看卫星
0×03. 非典型漏洞CVE-2016-0041分析2Vz看卫星
微软安全公告MS16-014中的描述表明其修复了一个CVE-ID为CVE-2016-0041的 DLL劫持漏洞。漏洞详情为:Windows 10下的 URLMON.dll 文件存在加载 phoneinfo.dll 的代码,而Windows 10本身并不携带这个 phoneinfo.dll 文件,并且在查找DLL时使用的是标准的目录搜索顺序,所以这里会导致DLL劫持漏洞。这个漏洞的独特之处在于其存在于操作系统本身,所以在 Windows 10下,只要是调用了 URLMON.dll 中能够触发漏洞代码的API的软件都会受到这个漏洞的影响。笔者在2015年底也发现了也发现了这个漏洞,同时确认Foxit Reader 7.2.8.1124受到该漏洞的影响,并将其报告给了Foxit Software。2Vz看卫星
2Vz看卫星
3.1 漏洞分析2Vz看卫星
在发现这个漏洞时,笔者发现网上很少有关于 phoneinfo.dll 文件的介绍,只有 @tombkeeper 在 Sexrets of LoadLibrary 中提到了这个文件。TK指出 IE11 running on Windows 10 TP 9926 会尝试加载 phoneinfo.dll,而IE的当前目录就是桌面,所以如果放一个 phoneinfo.dll 到桌面上的话,在启动IE时这个DLL便会被加载。2Vz看卫星
2Vz看卫星
Greg Linares 在 SRT-VR-24DEC2015 中指出 Windows10 的 URLMON.dll 中存在两处加载 phoneinfo.dll 的地方,可能是DLL文件的版本不一样,笔者找到的代码与之存在一些细微差异。笔者在分析 11.0.10240.16384 版本的 URLMON.dll 时找到的反汇编代码如下所示:2Vz看卫星
2Vz看卫星
下面的代码位于BuildUserAgentStringMobileHelper中:2Vz看卫星
2Vz看卫星
Default2Vz看卫星
.text:1A4636A1 loc_1A4636A1: 2Vz看卫星
.text:1A4636A1                 mov     eax, pfnQueryPhoneInformation2Vz看卫星
.text:1A4636A6                 mov     [ebp+pszValue], 02Vz看卫星
.text:1A4636AD                 mov     [ebp+szSrc], eax2Vz看卫星
.text:1A4636B3                 test    eax, eax         ; 判断eax寄存器的值是否为02Vz看卫星
.text:1A4636B5                 jnz     loc_1A48FC97     ; 如果不为0则跳转2Vz看卫星
.text:1A4636BB                 push    eax              ; dwFlags = 02Vz看卫星
.text:1A4636BC                 push    eax              ; hFile   = 02Vz看卫星
.text:1A4636BD                 push    offset aPhoneinfo_dll ; "phoneinfo.dll"2Vz看卫星
.text:1A4636C2                 call    ds:__imp__LoadLibraryExW@12 ; LoadLibraryExW(x,x,x)2Vz看卫星
.text:1A4636C8                 test    eax, eax2Vz看卫星
.text:1A4636CA                 jnz     loc_1A48FC782Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
52Vz看卫星
62Vz看卫星
72Vz看卫星
82Vz看卫星
92Vz看卫星
102Vz看卫星
112Vz看卫星
122Vz看卫星
.text:1A4636A1 loc_1A4636A1: 2Vz看卫星
.text:1A4636A1                 mov     eax, pfnQueryPhoneInformation2Vz看卫星
.text:1A4636A6                 mov     [ebp+pszValue], 02Vz看卫星
.text:1A4636AD                 mov     [ebp+szSrc], eax2Vz看卫星
.text:1A4636B3                 test    eax, eax         ; 判断eax寄存器的值是否为02Vz看卫星
.text:1A4636B5                 jnz     loc_1A48FC97     ; 如果不为0则跳转2Vz看卫星
.text:1A4636BB                 push    eax              ; dwFlags = 02Vz看卫星
.text:1A4636BC                 push    eax              ; hFile   = 02Vz看卫星
.text:1A4636BD                 push    offset aPhoneinfo_dll ; "phoneinfo.dll"2Vz看卫星
.text:1A4636C2                 call    ds:__imp__LoadLibraryExW@12 ; LoadLibraryExW(x,x,x)2Vz看卫星
.text:1A4636C8                 test    eax, eax2Vz看卫星
.text:1A4636CA                 jnz     loc_1A48FC782Vz看卫星
下面的代码位于_QueryPhoneInformationA中:2Vz看卫星
2Vz看卫星
Default2Vz看卫星
.text:1A461B93                 mov     edi, pfnQueryPhoneInformation2Vz看卫星
.text:1A461B99                 mov     byte ptr [ebx], 02Vz看卫星
.text:1A461B9C                 test    edi, edi2Vz看卫星
.text:1A461B9E                 jnz     loc_1A48EE562Vz看卫星
.text:1A461BA4                 push    edi             ; dwFlags2Vz看卫星
.text:1A461BA5                 push    edi             ; hFile2Vz看卫星
.text:1A461BA6                 push    offset aPhoneinfo_dll ; "phoneinfo.dll"2Vz看卫星
.text:1A461BAB                 call    ds:__imp__LoadLibraryExW@12 ; LoadLibraryExW(x,x,x)2Vz看卫星
.text:1A461BB1                 test    eax, eax2Vz看卫星
.text:1A461BB3                 jnz     loc_1A48EE342Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
52Vz看卫星
62Vz看卫星
72Vz看卫星
82Vz看卫星
92Vz看卫星
102Vz看卫星
.text:1A461B93                 mov     edi, pfnQueryPhoneInformation2Vz看卫星
.text:1A461B99                 mov     byte ptr [ebx], 02Vz看卫星
.text:1A461B9C                 test    edi, edi2Vz看卫星
.text:1A461B9E                 jnz     loc_1A48EE562Vz看卫星
.text:1A461BA4                 push    edi             ; dwFlags2Vz看卫星
.text:1A461BA5                 push    edi             ; hFile2Vz看卫星
.text:1A461BA6                 push    offset aPhoneinfo_dll ; "phoneinfo.dll"2Vz看卫星
.text:1A461BAB                 call    ds:__imp__LoadLibraryExW@12 ; LoadLibraryExW(x,x,x)2Vz看卫星
.text:1A461BB1                 test    eax, eax2Vz看卫星
.text:1A461BB3                 jnz     loc_1A48EE342Vz看卫星
这里加载 phoneinfo.dll 的代码为 LoadLibraryExW(“phoneinfo.dll”, NULL, 0)。因为这里 dwFlags 的值为0,所以使用标准的DLL搜索顺序;由于Windows 10上并不存在 phoneinfo.dll 这个文件,所以进程最终会尝试加载当前目录下的DLL。2Vz看卫星
2Vz看卫星
这里简单分析一下受该漏洞影响的Foxit Reader。当在Windows 10下打开一个PDF文件时,进程 FoxitReader.exe 会加载当前目录下的 phoneinfo.dll 文件,对应的调用栈如下所示:2Vz看卫星
2Vz看卫星
Default2Vz看卫星
16   KernelBase.dll     LoadLibraryExW + 0x1242Vz看卫星
17   urlmon.dll         Ordinal523 + 0x6f12Vz看卫星
18   urlmon.dll         Ordinal492 + 0x9412Vz看卫星
19   urlmon.dll         Ordinal492 + 0x1652Vz看卫星
20   urlmon.dll         Ordinal445 + 0x2e02Vz看卫星
21   urlmon.dll         RegisterFormatEnumerator + 0xe22Vz看卫星
22   urlmon.dll         UrlMkGetSessionOption + 0xcf2Vz看卫星
23   FoxitReader.exe    CertFreeCertificateChainEngine + 0x72fbef2Vz看卫星
24   FoxitReader.exe    CertFreeCertificateChainEngine + 0x70bbc22Vz看卫星
25   FoxitReader.exe    CertFreeCertificateChainEngine + 0x70f61e2Vz看卫星
26   FoxitReader.exe    CertFreeCertificateChainEngine + 0x6f9f9c2Vz看卫星
27   user32.dll         Ordinal2535 + 0x832Vz看卫星
28   user32.dll         GetScrollInfo + 0x1e82Vz看卫星
29   user32.dll         DispatchMessageW + 0x28d2Vz看卫星
30   user32.dll         DispatchMessageW + 0x102Vz看卫星
31   FoxitReader.exe    FoxitReader.exe + 0x2d1f1b2Vz看卫星
32   FoxitReader.exe    FoxitReader.exe + 0x2da62d2Vz看卫星
33   FoxitReader.exe    FoxitReader.exe + 0x882a362Vz看卫星
34   FoxitReader.exe    FoxitReader.exe + 0x1866d12Vz看卫星
35   FoxitReader.exe    FoxitReader.exe + 0x1732862Vz看卫星
36   FoxitReader.exe    FoxitReader.exe + 0x1735632Vz看卫星
37   FoxitReader.exe    FoxitReader.exe + 0x21483f2Vz看卫星
38   FoxitReader.exe    FoxitReader.exe + 0x2177262Vz看卫星
39   FoxitReader.exe    FoxitReader.exe + 0x1e49222Vz看卫星
40   FoxitReader.exe    FoxitReader.exe + 0x1f4aba2Vz看卫星
41   FoxitReader.exe    FoxitReader.exe + 0x1e8d6a2Vz看卫星
42   FoxitReader.exe    FoxitReader.exe + 0x1eb5622Vz看卫星
43   FoxitReader.exe    CertFreeCertificateChainEngine + 0x91e56c2Vz看卫星
44   FoxitReader.exe    FoxitReader.exe + 0x46cd8e2Vz看卫星
45   kernel32.dll       BaseThreadInitThunk + 0x242Vz看卫星
46   ntdll.dll          RtlInitializeCriticalSectionAndSpinCount + 0x29e2Vz看卫星
47   ntdll.dll          RtlInitializeCriticalSectionAndSpinCount + 0x26d2Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
52Vz看卫星
62Vz看卫星
72Vz看卫星
82Vz看卫星
92Vz看卫星
102Vz看卫星
112Vz看卫星
122Vz看卫星
132Vz看卫星
142Vz看卫星
152Vz看卫星
162Vz看卫星
172Vz看卫星
182Vz看卫星
192Vz看卫星
202Vz看卫星
212Vz看卫星
222Vz看卫星
232Vz看卫星
242Vz看卫星
252Vz看卫星
262Vz看卫星
272Vz看卫星
282Vz看卫星
292Vz看卫星
302Vz看卫星
312Vz看卫星
322Vz看卫星
16   KernelBase.dll     LoadLibraryExW + 0x1242Vz看卫星
17   urlmon.dll         Ordinal523 + 0x6f12Vz看卫星
18   urlmon.dll         Ordinal492 + 0x9412Vz看卫星
19   urlmon.dll         Ordinal492 + 0x1652Vz看卫星
20   urlmon.dll         Ordinal445 + 0x2e02Vz看卫星
21   urlmon.dll         RegisterFormatEnumerator + 0xe22Vz看卫星
22   urlmon.dll         UrlMkGetSessionOption + 0xcf2Vz看卫星
23   FoxitReader.exe    CertFreeCertificateChainEngine + 0x72fbef2Vz看卫星
24   FoxitReader.exe    CertFreeCertificateChainEngine + 0x70bbc22Vz看卫星
25   FoxitReader.exe    CertFreeCertificateChainEngine + 0x70f61e2Vz看卫星
26   FoxitReader.exe    CertFreeCertificateChainEngine + 0x6f9f9c2Vz看卫星
27   user32.dll         Ordinal2535 + 0x832Vz看卫星
28   user32.dll         GetScrollInfo + 0x1e82Vz看卫星
29   user32.dll         DispatchMessageW + 0x28d2Vz看卫星
30   user32.dll         DispatchMessageW + 0x102Vz看卫星
31   FoxitReader.exe    FoxitReader.exe + 0x2d1f1b2Vz看卫星
32   FoxitReader.exe    FoxitReader.exe + 0x2da62d2Vz看卫星
33   FoxitReader.exe    FoxitReader.exe + 0x882a362Vz看卫星
34   FoxitReader.exe    FoxitReader.exe + 0x1866d12Vz看卫星
35   FoxitReader.exe    FoxitReader.exe + 0x1732862Vz看卫星
36   FoxitReader.exe    FoxitReader.exe + 0x1735632Vz看卫星
37   FoxitReader.exe    FoxitReader.exe + 0x21483f2Vz看卫星
38   FoxitReader.exe    FoxitReader.exe + 0x2177262Vz看卫星
39   FoxitReader.exe    FoxitReader.exe + 0x1e49222Vz看卫星
40   FoxitReader.exe    FoxitReader.exe + 0x1f4aba2Vz看卫星
41   FoxitReader.exe    FoxitReader.exe + 0x1e8d6a2Vz看卫星
42   FoxitReader.exe    FoxitReader.exe + 0x1eb5622Vz看卫星
43   FoxitReader.exe    CertFreeCertificateChainEngine + 0x91e56c2Vz看卫星
44   FoxitReader.exe    FoxitReader.exe + 0x46cd8e2Vz看卫星
45   kernel32.dll       BaseThreadInitThunk + 0x242Vz看卫星
46   ntdll.dll          RtlInitializeCriticalSectionAndSpinCount + 0x29e2Vz看卫星
47   ntdll.dll          RtlInitializeCriticalSectionAndSpinCount + 0x26d2Vz看卫星
结合IDA或者Windbg进行分析,可以知道这里的调用路径为:2Vz看卫星
2Vz看卫星
Default2Vz看卫星
UrlMkGetSessionOption2Vz看卫星
└--> GetUserAgentString2Vz看卫星
     └--> GetUserAgentStringForMode2Vz看卫星
          └--> InitUserAgentGlobals2Vz看卫星
               └--> BuildUserAgentStringMobileHelper2Vz看卫星
                    └-->LoadLibraryExW2Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
52Vz看卫星
62Vz看卫星
UrlMkGetSessionOption2Vz看卫星
└--> GetUserAgentString2Vz看卫星
     └--> GetUserAgentStringForMode2Vz看卫星
          └--> InitUserAgentGlobals2Vz看卫星
               └--> BuildUserAgentStringMobileHelper2Vz看卫星
                    └-->LoadLibraryExW2Vz看卫星
即Foxit Reader因为调用了URLMON.dll中的UrlMkGetSessionOption函数,导致其受到DLL劫持漏洞的影响。在IDA中使用交叉引用功能进行回溯,可以找到其他能够触发该漏洞的路径,Greg Linares 给出了另外两个路径:2Vz看卫星
2Vz看卫星
路径1:2Vz看卫星
2Vz看卫星
Default2Vz看卫星
┌-----------------------------------------------------┐2Vz看卫星
│        CINetHttpEdge::SetOptionUserAgent            │2Vz看卫星
│          CINetHttp::SetOptionUserAgent              │2Vz看卫星
│ CIEBrowserModeFilter::collectCacheEntryInfoCallback │2Vz看卫星
└-----------------------------------------------------┘2Vz看卫星
└--> MapBrowserEmulationStateToUserAgent (Ordinal 445)2Vz看卫星
     └--> InitUserAgentGlobals (Ordinal 492)2Vz看卫星
          └--> BuildUserAgentStringMobileHelper2Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
52Vz看卫星
62Vz看卫星
72Vz看卫星
82Vz看卫星
┌-----------------------------------------------------┐2Vz看卫星
│        CINetHttpEdge::SetOptionUserAgent            │2Vz看卫星
│          CINetHttp::SetOptionUserAgent              │2Vz看卫星
│ CIEBrowserModeFilter::collectCacheEntryInfoCallback │2Vz看卫星
└-----------------------------------------------------┘2Vz看卫星
└--> MapBrowserEmulationStateToUserAgent (Ordinal 445)2Vz看卫星
     └--> InitUserAgentGlobals (Ordinal 492)2Vz看卫星
          └--> BuildUserAgentStringMobileHelper2Vz看卫星
路径2:2Vz看卫星
2Vz看卫星
Default2Vz看卫星
┌-------------------------------------┐2Vz看卫星
│ ObtainUserAgentString (Ordinal 211) │2Vz看卫星
│         GetUserAgentString          │2Vz看卫星
└-------------------------------------┘2Vz看卫星
└--> InitUserAgentGlobals (Ordinal 492)2Vz看卫星
     └--> BuildUserAgentStringMobileHelper2Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
52Vz看卫星
62Vz看卫星
┌-------------------------------------┐2Vz看卫星
│ ObtainUserAgentString (Ordinal 211) │2Vz看卫星
│         GetUserAgentString          │2Vz看卫星
└-------------------------------------┘2Vz看卫星
└--> InitUserAgentGlobals (Ordinal 492)2Vz看卫星
     └--> BuildUserAgentStringMobileHelper2Vz看卫星
Greg Linares 同时也指出了他们发现的其他受该漏洞影响的软件:2Vz看卫星
1. Internet Explorer 没有命令行参数的情况下(例如双击并打开IE);2Vz看卫星
2. Skype 启动的时候;2Vz看卫星
3. OneDrive 同步以及更新的时候(无需用户交互);2Vz看卫星
4. Visual Studio 2015 微软账户更新或者同步的时候;2Vz看卫星
2Vz看卫星
3.2 补丁分析2Vz看卫星
更新后的URLMON.dll文件在调用 LoadLibraryEx 加载 phoneinfo.dll 时将 dwFlags 参数值指定为 0×800,即 LOAD_LIBRARY_SEARCH_SYSTEM32,表示只搜索 System32 目录。对应的代码为LoadLibraryExW(L”phoneinfo.dll”, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32),反汇编代码如下:2Vz看卫星
2Vz看卫星
Default2Vz看卫星
.text:1A46386B                 push    800h            ; dwFlags2Vz看卫星
.text:1A463870                 push    eax             ; hFile2Vz看卫星
.text:1A463871                 push    offset aPhoneinfo_dll ; "phoneinfo.dll"2Vz看卫星
.text:1A463876                 call    ds:__imp__LoadLibraryExW@12 ; LoadLibraryExW(x,x,x)2Vz看卫星
12Vz看卫星
22Vz看卫星
32Vz看卫星
42Vz看卫星
.text:1A46386B                 push    800h            ; dwFlags2Vz看卫星
.text:1A463870                 push    eax             ; hFile2Vz看卫星
.text:1A463871                 push    offset aPhoneinfo_dll ; "phoneinfo.dll"2Vz看卫星
.text:1A463876                 call    ds:__imp__LoadLibraryExW@12 ; LoadLibraryExW(x,x,x)2Vz看卫星
0×04. DLL劫持漏洞缓解措施2Vz看卫星
DLL劫持漏洞在未来可能仍然会影响着许多软件或者操作系统组件,亦或是与其他漏洞相结合以衍生出新的攻击方法。尽管目前没有一个完美的方法(No Silver Bullet)可以防止软件受到DLL劫持漏洞的影响,但是开发人员仍然可以采取各种措施来缓解DLL劫持漏洞带来的影响。2Vz看卫星
2Vz看卫星
4.1 基本缓解措施2Vz看卫星
1. 在加载DLL时尽量使用DLL的绝对路径;2Vz看卫星
2. 调用SetDllDirectory(L””)把 当前目录 从DLL搜索目录中排除;2Vz看卫星
3. 使用 LoadLibraryEx 加载DLL时,指定 LOAD_LIBRARY_SEARCH_ 系列标志;2Vz看卫星
2Vz看卫星
此外,进程也可以尝试去验证DLL的合法性,例如是否具有自家的合法数字签名、是否是合法的系统DLL文件等。2Vz看卫星
2Vz看卫星
4.2 Windows Edge缓解措施2Vz看卫星
最新版本的Edge提供了一种对抗DLL劫持(注入)的缓解措施:只有拥有微软签名以及WHQL(Windows Hardware Quality Lab)签名的DLL模块才会被Edge加载,而且这套机制是在操作系统内核中实现的。