PrintNightmare漏洞仍未终结
发布日期 2024年10月5日
更新日期 2024年10月5日
作者 itm4n
阅读时间 13分钟
初始设置
首先确定起点条件,即初始的Point and Print配置:
- 策略"将打印机驱动安装限制为管理员"已禁用。此变更是必需的,否则无论其他(包)Point and Print设置如何配置,只有管理员可以安装打印机驱动(自KB5005652起的默认行为)。
- 策略"仅使用包Point and Print"已启用。虽非严格必需,但此策略确保我们只能安装已签名的包感知打印机驱动。
- 策略"包Point and Print - 批准的服务"已启用,且prt01.foundation.local是唯一授权的打印服务器。这是本场景中最重要的设置。
在此条件下,如我之前文章所述,尝试从其他服务器安装打印机驱动会失败,错误代码为0x800704ec,即ERROR_ACCESS_DISABLED_BY_POLICY,符合预期。
(不太)明显的缺陷
在KB5005652文章中,可以读到"没有等同于将RestrictDriverInstallationToAdministrators设置为1的缓解措施组合"。对我而言,这有点像在说"我们出于某种原因限制了打印机驱动的安装权限给管理员;你可以忽略此警告,但风险自负",却没有详细说明这些原因或解释这些风险是什么。
尽管如此,我相当确信"包Point and Print - 批准的服务"策略通过确保只有此设置中列出的服务器可用于安装打印机驱动,能有效防止PnP配置的滥用。
但我从未想过,仅通过伪造批准服务器列表中的某个服务器名称,就可以绕过此策略。然而,事实如此,DNS欺骗这种最基本的网络攻击就足以规避此保护。
DNS欺骗,你说什么?
为了在实验室中更方便测试,我没有设置自定义DNS服务器,而是在我的"受害"域加入机器的主机文件中添加了一个条目。此条目强制将prt01.foundation.local解析为我恶意打印服务器的IP地址,而不是域控制器提供的IP地址。
192.168.177.123 prt01.foundation.local prt01
在重现了前一篇文章中描述的漏洞利用步骤,并将恶意打印服务器的IP地址替换为欺骗名称后,我仍然收到错误,但状态码不同:0x80070709,即ERROR_INVALID_PRINTER_NAME。
我已经知道导致此错误的原因,但为了演示,我选择使用Wireshark以正确方式调试此问题。从恶意打印服务器的角度,我们观察到以下情况。
客户端/服务器交互完全通过DCE/RPC(至少在此阶段)进行,并在AsyncOpenPrinter RPC调用处停止。然而,解析器仅显示加密数据。请注意,这是CVE-2021-1678补丁的结果,该补丁在通过网络连接到打印后台处理程序服务时强制执行"数据包隐私"RPC身份验证级别,以防止NTLM中继攻击。
如Clément Notin (@cnotin)在博客文章《在Wireshark中解密Kerberos/NTLM"加密存根数据"》中所述,我们可以通过配置NTLMSSP协议并设置用于验证打印服务器的明文NT密码来解决此问题。
结果,Wireshark现在能够解码NTLM相关数据,从而检查RPC加密存根数据的内容。以下是最终结果,显示了RPC请求和响应的并排视图。
此输出非常清晰。客户端希望打开打印机\prt01.foundation.local\ACIDDAMAGE,我们的服务器回复错误代码0x00000709("无效打印机名称")。看起来我们的(不太)恶意服务器对其实际身份有点过于诚实。在主机文件中添加欺骗服务器名称的条目应能解决问题。
完成此操作后,进行了另一次打印机安装尝试,但失败并出现另一个错误代码:0x80070006 (ERROR_INVALID_HANDLE)。这个错误更让我困惑,因为我可以看到打印机驱动从我的打印服务器下载。我甚至尝试使用新安装的Windows机器重放攻击,但以相同方式失败。
无论如何,打印机安装只是达到目的的手段。我们真正关心的是易受攻击的打印机驱动的安装。使用Get-PrinterDriver cmdlet快速检查显示它确实已安装。我们成功绕过了 supposedly 安全的PnP配置。
解决方案1:UNC强化访问
如前所述,Windows使用DCE/RPC与远程打印服务器通信,但这并非唯一的通信方式。它还使用SMB通过print$共享下载驱动包。
因此,在Active Directory环境中,人们可能认为强制执行UNC路径强化就足以防止此类攻击。让我们仔细看看...
UNC路径强化,也称为"UNC强化访问",最初是作为安全功能添加的,通过强制执行相互身份验证和完整性来防止对域控制器的NETLOGON和SYSVOL共享的中间人攻击(参见MS15-011:组策略中的漏洞可能允许远程代码执行和MS15-011 & MS15-014:强化组策略)。这就是为什么Active Directory强化指南通常建议将\\SYSVOL和\\NETLOGON设置为强化UNC路径(参见此处)。
以下屏幕截图显示了如何使用部署在客户端机器上的GPO来强化路径\prt01.foundation.local*的访问。
更新客户端的组策略并再次尝试攻击后,打印机安装现在失败,错误为0x800704ec,即ERROR_ACCESS_DISABLED_BY_POLICY。
快速查看Wireshark确认客户端未能建立SMB会话,并立即关闭连接。
但现在宣布胜利还为时过早。要理解原因,我们需要考虑下载打印机驱动之前的RPC流量。
如上方屏幕截图所示,客户端实际上通过RPC过程RpcAsyncGetPrinterDriverPackagePath检索打印机驱动包路径,最终调用内部函数RouterGetPrinterDriverPackagePath。
如果此过程返回客户端用于下载包的UNC路径,我们应能将其替换为本地路径以绕过UNC路径强化配置。为了测试此理论,我选择使用Frida并挂钩函数PrvRouterGetPrinterDriverPackagePath。
函数RouterGetPrinterDriverPackagePath由spoolsv.exe导出,公共符号为PrvRouterGetPrinterDriverPackagePath。
不出所料,此函数确实返回了print$共享上打印机驱动包的UNC路径。因此,接下来我将CAB文件复制到目标机器,并使用以下Frida脚本将打印服务器返回的UNC路径替换为此文件的本地路径。
var pszDriverPackageCab
var cchDriverPackageCab
const fakePackagePath = "C:\\Test\\lmud1o40.inf_amd64_b2faa2ece3fcef36.cab"
var PrvRouterGetPrinterDriverPackagePath = Module.findExportByName("spoolsv.exe", "PrvRouterGetPrinterDriverPackagePath")Interceptor.attach(PrvRouterGetPrinterDriverPackagePath, {onEnter: function (args) {pszDriverPackageCab = args[4]cchDriverPackageCab = args[5]},onLeave: function (result) {if (cchDriverPackageCab.toInt32() !== 0) {// We should check the buffer size, but that's ok for the poc.console.log("\nWriting new printer driver package path...")pszDriverPackageCab.writeUtf16String(fakePackagePath)}}
});
它起作用了!尽管我们之前看到了错误代码0x80070006,但打印机驱动再次成功安装!
总之,在此场景中,仅凭UNC强化访问不足以防止中间人攻击。
解决方案2:命名管道上的RPC + UNC强化访问
Windows打印服务器可以通过RPC over TCP和RPC over SMB(通过命名管道)访问。然而,在最近的更新中,Microsoft宣布从Windows 11 22H2开始这将改变。
此更新的结果是,使用RPC over命名管道(即over SMB)仍然可用,但默认禁用。因此,后台处理程序仅侦听通过RPC over TCP的传入连接,命名管道spoolss不可用。
我不知道是什么促使了此更改,但这很不幸,因为我保护后台处理程序免受中间人攻击的下一个想法是在之前的UNC强化访问之外,强制执行RPC over SMB。然而,此更新还带来了新的设置来配置和修改此默认行为,因此让我们测试一下。
最值得注意的是,我们可以配置策略"RPC连接设置"并选择"RPC over命名管道"作为传出RPC连接要使用的协议。
我的域控制器当前运行Windows Server 2022 21H2,因此新的管理模板不可用。我必须从此链接下载并安装最新的可用模板。
由于我的攻击机器运行Windows 11 23H2,它受到此更改的影响,因此我的打印后台处理程序仅期望通过RPC over TCP的连接。要重新启用RPC over SMB,我们可以配置本地组策略,或使用以下命令。
REM RPC over named pipes = 0x03
REM RPC over TCP = 0x05
REM RPC over named pipes and TCP = 0x07
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Printers\RPC" /v "RpcProtocols" /t REG_DWORD /d 0x7 /f
REM Restart the Print Spooler service
net stop spooler
net start spooler
REM Check whether the named pipe 'spoolss' exists
powershell "[IO.File]::GetAttributes('\\.\pipe\spoolss')"
它没有起作用。更准确地说,它没有按我预期的方式工作。客户端机器确实尝试使用RPC over SMB通信,并且由于配置了UNC路径强化,这失败了,这是预期行为。但随后,它回退到RPC over TCP,从而使策略完全无用,至少对于我的想法而言。
解决方案3:打印驱动排除列表
如果你读了标题并认为"这听起来是个坏主意",你完全正确,但我想快速提一下。
在浏览与打印机相关的现有策略时,我找到了这个。我更喜欢类似"允许列表"的东西,而不是"阻止列表",但我想总比没有好。
因此,我阅读了描述并看到:"排除列表中的条目由驱动程序的INF文件和/或主驱动DLL文件的SHA256哈希[...]和文件名组成"。
尽管从安全角度来看此描述看起来很糟糕,我还是尝试了一下。我将LMUD1o40.inf和UNIDRV.DLL的SHA256哈希添加到排除列表,但它没有起作用。它没有阻止易受攻击的打印机驱动的安装。
我不知道我做错了什么。描述确实提到了"文件哈希",而不是Authenticode指纹。因此,这表明此策略容易出错,除了从安全角度无用之外,因为如果是有签名的可执行文件,人们可以轻松修改文件使其哈希更改而不使其Authenticode签名失效。尽管如此,我不认为此策略曾用于安全目的。相反,它可能旨在提供一种阻止不兼容驱动的方法。
而且,显然,即使此策略旨在作为安全功能,它从设计上就有缺陷,因为它基于"阻止列表"而非"允许列表"。因此,与已知易受攻击的内核驱动类似,你将不得不维护此列表,而不是只允许你正在使用的驱动,这对于打印机驱动而言似乎比典型内核驱动更易于管理。
结论
这就是本次更新的内容。我必须承认我已经没有主意了,并且认为花更多时间搜索可能提供虚假安全感的潜在危险配置没有附加价值。
关键要点是,Microsoft KB文章KB5005652 - 管理新的Point and Print默认驱动安装行为(CVE-2021-34481)中看似无害的陈述"没有等同于将Restrict Driver Installation To Administrators设置为1的缓解措施组合"实际上应被字面理解。确实,如果你允许低权限用户以某种方式安装打印机驱动,你就无法保护Point and Print配置。
我好奇地想看看,Microsoft去年12月宣布的新Windows Protected Print(WPP)模式在大规模采用后是否会以及如何解决此问题。与此同时,系统管理员应确保他们不禁用旨在防范CVE-2021-34481的新打印机驱动限制。尽管对某些组织来说可能是一项艰巨的任务,但管理旧版打印机的最安全方法似乎是在客户端工作站上预安装其驱动包,或者如果需要,使用GPO和安装脚本部署它们。
最后但同样重要的是,我要感谢@parzel(与modzero合作)和@laxa(与Synacktiv合作),他们都在几周内让我注意到此绕过,并参与了头脑风暴过程,以帮助寻找和探索替代缓解措施。向他们致以崇高的敬意!
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
公众号二维码