远程关闭漏洞——使用 Wininit.exe 的远程 DoS 攻击
编辑和内容补充:Tricia Howard
执行摘要
Akamai 研究人员 Stiv Kupchik 在 Microsoft 的 Wininit.exe 中发现了一个新的拒绝服务 (DoS) 漏洞,其 CVE 编号为 CVE-2022-44707,CVSS 评分为 6.5。
本着负责任的态度,我们已经在 8 月将此漏洞披露给 MSRC,他们随后在 2022 年 12 月的 Patch Tuesday中修复了此漏洞。
利用此漏洞,攻击者可以借助缓存机制绕过安全检查,并与远程 Windows 设备上的关闭机制交互,从而获得停止或发起关闭的控制权。
此漏洞会影响 Windows 8/Server 2012 及以上的、所有未安装补丁的 Windows 版本,所以请务必及时安装补丁。
简介
在先前名为 《冷硬缓存》的博文中,我们曾预告说将会为大家介绍使用我们的 RPC 工具包发现的更多 RPC 漏洞,这篇博文就是为此而撰写。在今天的这一期“RPC 诡计”中,我们的主角是 Wininit。
Wininit 是一种 Windows 关键进程,在 Windows 操作系统的启动和关闭中发挥着关键作用(关键到一旦它崩溃,整个系统都会崩溃)。因此它公开了多个用来实现关闭功能的 RPC 接口,部分接口 甚至有文档记录。我们发现的漏洞存在于 WindowsShutdown 接口中。
WindowsShutdown 接口是什么?
WindowsShutdown 是 Wininit 公开的数个 RPC 接口之一。它负责关闭进程——作用与 Wininit 的其他 PRC 接口一样,是不是有点意外?该接口的 UUID 是 d95afe70-a6d5-4259-822e-2c84da1ddb0d。它归入 MS-RSP (远程关闭协议),具有如下功能:
从公开的 IDL 文件中,我们可以看到 只有 WsdrInitiateShutdown 和 WsdrAbortShutdown 有文档记录。我们是否应该关注没有文档记录的函数(从没有人问过研究人员这个问题)?为了回答这个问题,我们先来看一下这个接口的安全回调。
安全回调
回调首先会检查传输协议,并且仅允许 ALPC 或 TCP 连接。随后它会检查身份验证级别,仅允许 RPC_C_AUTHN_LEVEL_PKT_PRIVACY 。如果所调用的函数不是 WsdrCheckForHiberboot,系统会检查远程调用方用户的令牌。为此,系统会将该令牌与 SECURITY_NETWORK_RID这个广为人知的 SID(在 WinInit 初始化过程中创建,保存在一个全局变量中)进行比较。安全回调完全不会限制对 WsdrCheckForHiberboot 的调用。
该 RCP 接口已注册默认缓存行为,所以理论上来说,如果我们能成功调用 WsdrCheckForHiberboot,就能借助缓存的成功结果,在后续对 WsdrInitiateShutdown 和 WsdrAbortShutdown进行调用时绕过 SID 检查。
那么我们需要做些什么来调用 WsdrCheckForHiberboot?
WsdrCheckForHiberboot
我们并不关心这个函数的功能究竟是什么,也不关心 hiberboot 是什么意思(不过为了满足大家的好奇心,这是 Windows 的一种快速启动机制),但我们需要了解它的正确调用方法。我们要在 IDL 文件中正确定义该函数,以便为其编译客户端。虽然这个函数并没有相应的文档记录,我们还是可以观察一下 advapi CheckForHiberboot,这是我们找到的 WsdrCheckForHiberbootRPC 客户端中,唯一配有文档记录的一个。它只需要两个参数:一个布尔指针,一个布尔值。
我们可以使用这些参数复现该函数定义,并编译一个 IDL 文件和程序。但这里还缺少一点东西。在使用我们的客户端远程调用此函数时,RPC 运行时返回了一个 PRC 存根错误,这让我们知道,对函数的调用不正确。
好在我们不用盲目猜测,还有一种更合适的方法,只是要麻烦一些。在 RPC 接口存根中,有一个名为 ProcFormatString的字段。它大体上就是一个很长的二进制字符串,描述了该接口的所有函数公开的参数类型及返回值。在封送和取消封送函数调用(也就是在我们第一次尝试时,返回了 RPC 存根错误的进程)时,RPC 运行时会用到这个字段。在花了一番功夫人工解析这个二进制字符串之后,我们最终发现,该函数还要求提供另外一个参数,这个参数的类型是 wchar_t*。下面这张图片展示了 WsdrCheckForHiberboot 的 ProcFormatString中的代码段,我们针对其中每个部分添加了自己的注释:
在函数定义中添加这个新发现的参数之后,我们终于成功了! CheckForHiberboot 成功返回了结果,可以继续调用 WsdrInitiateShutdown 和 WsdrAbortShutdown了。
再补充几句……
我们最想立刻实现的就是使用缓存攻击调用 WsdrInitiateShutdown 并实现远程关闭。这次没有涉及到任何猜测。我们不但在 IDL 文件中找到了函数定义的记录,还在 advapi 函数 InitiateShutdownA下找到了该函数预期获得的标记的记录。利用 SHUTDOWN_GRACE_OVERRIDE、SHUTDOWN_HYBRID 和 SHUTDOWN_FORCE_OTHERS 标记组合,我们就能实现立即强制关闭。
这样就完成了攻击链,我们绕过了安全回调及其 SID 检查,还实现了远程关闭。从技术上来说,这属于特权升级(允许任意通过身份验证的用户远程调用 WsdrInitiateShutdown,而非仅限 SECURITY_NETWORK_RID下允许的用户调用)。我们只能使用此接口实现关闭,所以这个漏洞分类为 DoS 漏洞。
检测
我们提供了 OSQuery,用于检测未安装补丁(因此受此漏洞影响)的 Wininit.exe 版本。 Akamai Guardicore Segmentation 客户可以将 Insight 功能与此查询结合使用来搜索易受攻击的资产。
WITH product_version AS (
WITH os_minor AS (
WITH os_major AS (
SELECT substr(product_version, 0, instr(product_version, ".")) as os_major, substr(product_version, instr(product_version, ".")+1) as no_os_major_substr
FROM file
WHERE path = "c:\windows\system32\wininit.exe"
)
SELECT substr(no_os_major_substr, instr(no_os_major_substr, ".")+1) as no_os_minor_substr, substr(no_os_major_substr, 0, instr(no_os_major_substr, ".")) as os_minor, os_major
FROM os_major
)
SELECT
CAST(substr(no_os_minor_substr, instr(no_os_minor_substr, ".")+1) AS INTEGER) AS product_minor,
CAST(substr(no_os_minor_substr, 0, instr(no_os_minor_substr, ".")) AS INTEGER) AS product_major,
CAST(os_minor AS INTEGER) AS os_minor,
CAST(os_major AS INTEGER) AS os_major
FROM os_minor
)
SELECT
CASE
WHEN NOT ((os_major = 6 AND os_minor = 3) OR (os_major = 6 AND os_minor = 2) OR (os_major = 10 AND os_minor = 0))
THEN "not supported"
WHEN os_major = 6 AND os_minor = 3 AND product_major = 9600 AND product_minor >= 20716 THEN "patched"
WHEN os_major = 6 AND os_minor = 2 AND product_major = 9200 AND product_minor >= 24011 THEN "patched"
WHEN (
(product_major = 14393 AND product_minor >= 5582)
OR
(product_major = 10240 AND product_minor >= 19624)
OR
(product_major = 19041 AND product_minor >= 1620)
OR
(product_major = 22621 AND product_minor >= 963)
OR
(product_major = 22000 AND product_minor >= 1335)
OR
(product_major = 20348 AND product_minor >= 1366)
OR
(product_major = 17763 AND product_minor >= 3770)
)
THEN
"patched"
ELSE
"not patched"
总结
虽然这个漏洞不那么关键(它 只是 远程关闭,甚至不是未经授权的远程关闭),但体现出了 MS-PRC 固有的破坏潜力,因为 Windows 操作系统的大多数关键服务都内置这一接口。此外,不同于其他类型的漏洞,RPC 几乎不需要花心思去猜测——所有信息都摆在明面上(二进制文件中),您要做的只是找到解读方法。
我们坚持广泛研究 MS-RPC的初衷就是探寻利用这些关键函数漏洞的可能性。虽然这个接口的使用广泛,但从整体来看,相关研究相当不充分。类似于本文涉及到的这种漏洞展示了此类工作的必要性,我们希望将来看到其他研究人员就 MS-RPC 开展研究。
本着负责任的态度,我们已经在 8 月末将此漏洞披露给 MSRC,他们随后在 2022 年 12 月的 Patch Tuesday 中修复了此漏洞。