PrintNightmare分析

admin 2021年12月31日03:56:56PrintNightmare分析已关闭评论148 views字数 13374阅读44分34秒阅读模式

时间线

2021年6月29号:深信服安全研究员在Github上分布了名为《

PrintNightmare (CVE-2021-1675): Remote code execution in Windows Spooler Service》相关POC和漏洞信息

2021年6月30号:安全*研究员@*cube0x0在github上分布了使用Impacket的pyhton EXP。

2021年7月1号:*安全*研究员@cube0x0在github更新了C# Implementation of CVE-2021-1675的EXP

2021年7月2号:微软披露Windows Print Spooler Remote Code Execution VulnerabilityCVE-2021-34527,表示已知该漏洞存在在野利用。该漏洞目前为零日状态,微软暂未发布修复。

...部分安全厂商把在github上披露的《*PrintNightmare (CVE-2021-1675): Remote code execution in Windows Spooler Service*》认为是新的CVE-2021-34527,也有部分厂商认为不是。

个人认为*PrintNightmare (CVE-2021-1675): Remote code execution in Windows Spooler Service》为新的*CVE-2021-34527,所以下面统一称PrintNightmare (CVE-2021-1675): Remote code execution in Windows Spooler Service》为新的CVE-2021-34527。。。。。

本人也是第一次分析漏洞,可能存在错误,希望大家多多包涵。

Print Spooler

Print Spooler是管理打印过程的可执行文件。打印管理涉及检索正确打印机驱动程序的位置、加载该驱动程序、将高级函数调用假脱机到打印作业中、安排打印作业进行打印等。后台处理程序在系统启动时加载并继续运行,直到操作系统关闭。

Print spooler 是一种管理打印过程的软件服务。后台处理程序接受来自计算机的打印作业并确保打印机资源可用。

任何经过身份验证的用户都可以远程连接到域控制器打印后台处理程序服务,并请求更新新的打印作业。

Print Spooler归 SYSTEM 所有

微软一般建议禁用:

<span class="ne-text">域控制器和 Active Directory 管理系统需要禁用打印后台处理程序服务。推荐的方法是使用组策略对象 (GPO)。</span>

如果*启用*Print Spooler 服务*,可以使用一些已知的 AD 凭据向*域控制器的打印服务器请求*新打印作业*更新,并告诉它*向某个系统发送通知。当打印机将通知发送到任意系统时,它需要*针对*系统进行*身份验证。**

因此,我们可以使*Print Spooler* 服务针对任意系统进行身份验证,并且该服务将*在此身份验证中*使用计算机帐户**。

RpcAddPrinterDriver

向服务器添加打印机驱动程序 (RpcAddPrinterDriver),RpcAddPrinterDriver可以在在*打印服务器*上安装打印机驱动程序并链接配置、数据和打印机驱动程序文件。

主要语法为:

<span class="ne-text"> DWORD RpcAddPrinterDriver(</span>

<span class="ne-text">   [in, string, unique] STRING_HANDLE pName,</span>

<span class="ne-text">   [in] DRIVER_CONTAINER* pDriverContainer</span>

<span class="ne-text"> );</span>

*pName ***

<span class="ne-text">此参数是一个指向字符串的指针,该字符串指定该方法所操作的</span>``<span class="ne-text">打印服务器</span>``<span class="ne-text">的名称。这必须是</span>``<span class="ne-text">远程过程调用 (RPC)</span>``<span class="ne-text"> 绑定到的</span>``<span class="ne-text">域名系统 (DNS)</span>``<span class="ne-text">、 </span>``<span class="ne-text">NetBIOS</span>``<span class="ne-text">、 </span>``<span class="ne-text">互联网协议版本 4 (IPv4)</span>``<span class="ne-text">、</span>``<span class="ne-text">互联网协议版本 6 (IPv6)</span>``<span class="ne-text">或</span>``<span class="ne-text">通用命名约定 (UNC)</span>``<span class="ne-text">名称,并且它必须唯一标识网络上的打印服务器。</span>

*pDriverContainer ***

<span class="ne-text">该参数是指向 指定</span>``<span class="ne-text">打印机驱动程序</span>``<span class="ne-text"> 信息的</span>``<span class="ne-text">DRIVER_CONTAINER</span>``<span class="ne-text">结构的指针。DRIVER_CONTAINER 结构的</span>``<strong><span class="ne-text">Level</span></strong>``<span class="ne-text">成员的值必须是 0x00000002、0x00000003、0x00000004、0x00000006 或 0x00000008。</span>

*返回值:*

<span class="ne-text">成功返回零 (ERROR_SUCCESS) ,</span>``<span class="ne-text">失败返回</span>``<span class="ne-text">非零 Windows 的错误代码</span>

1.**收到此消息后,服务器必须执行以下指定的验证步骤

  • <span class="ne-text">打印服务器名称参数。</span>
  • <span class="ne-text">DRIVER_CONTAINER 参数。</span>

*2.然后验证参数*

验证该**cVersion 所述的构件**DRIVER_INFO* 结构包含在由指向DRIVER_CONTAINER pDriverContainer* 比0x00000004严格以下。如果此验证失败,则返回 ERROR_PRINTER_DRIVER_BLOCKED。

验证*pDriverContainer 参数 指向的 DRIVER_CONTAINER 中包含的DRIVER_INFO* 结构的**pEnvironment 成员不是“Windows ARM”。如果此验证失败,则返回 ERROR_NOT_SUPPORTED。**

如果打印客户端请求的安装是打印机驱动程序升级,打印服务器应该执行以下额外的验证步骤:

  • <span class="ne-text">验证当前安装的打印机驱动程序不是类打印机驱动程序。</span>
  • <span class="ne-text">验证如果当前安装的打印机驱动程序的驱动程序版本为 0x00000004,则当前安装的打印机驱动程序没有更新的驱动程序日期,或者如果驱动程序日期相同,则当前安装的打印机驱动程序没有更新的制造商 -提供的驱动程序版本号。</span>
  • <span class="ne-text">验证如果当前安装的打印机驱动程序的驱动程序版本为 0x00000004,则打印服务器上没有打印机共享并且也使用当前安装的打印机驱动程序。</span>

如果此验证失败,打印服务器必须返回 ERROR_PRINTER_DRIVER_BLOCKED。

*3.如果参数验证失败*

服务器必须立即使操作失败并向客户端返回一个非零错误响应。否则,服务器必须按如下方式处理消息并向客户端发送响应:

  • <span class="ne-text">将打印机驱动程序文件复制到目的地。如果复制操作失败,服务器必须立即使调用失败并向客户端返回一个非零错误响应。</span>
  • <span class="ne-text">创建打印机驱动程序对象,使用特定于实现的机制来确定打印机驱动程序对象的每个属性的布尔值。</span>``<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/e81cbc09-ab05-4a32-ae4a-8ec57b436c43#Appendix_A_313" data-href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/e81cbc09-ab05-4a32-ae4a-8ec57b436c43#Appendix_A_313" target="_blank" class="ne-link"><span class="ne-text"><313></span></a>
  • <span class="ne-text">如果任何客户端注册了服务器对象更改的通知,则必须向它们广播通知。</span>
  • <span class="ne-text">返回操作的状态。</span>

添加或更新打印机驱动程序

要将*打印机驱动程序 (“OEM 打印机驱动程序”)添加或更新到*打印服务器 (“CORPSERV”),客户端(“TESTCLT”)执行以下步骤。

1.使用*RpcEnumPrinterDrivers*枚举现有的打印机驱动程序。

<span class="ne-text">RpcEnumPrinterDrivers用来枚举安装在指定</span>``<span class="ne-text">打印服务器</span>``<span class="ne-text">上的</span>``<span class="ne-text">打印机驱动</span>``<span class="ne-text">程序。</span>

2.如果打印机驱动程序不存在或客户端请求更新打印机驱动程序,那么我们可以使用*RpcAddPrinterDriver* 将驱动程序添加到打印服务器。

  • 客户端确保打印机驱动程序的文件位于服务器可访问的位置。所以,我们可以让客户端可以共享包含文件的本地目录,或使用*SMB)协议*将文件放入服务器上的目录中。
  • 然后客户端分配并填充一个*DRIVER_INFO_2* 结构

DRIVER_INFO_2 结构提供有关打印机驱动程序的信息

<span class="ne-text">pName = L"OEM 打印机驱动程序"; </span>

<span class="ne-text"> pEnvironment = L"Windows NT x86"; /* 驱动程序兼容的环境 */ </span>

<span class="ne-text"> pDriverPath = "\\CORPSERV\C$\DRIVERSTAGING\OEMDRV.DLL"; </span>

<span class="ne-text"> pDataFile = "\\CORPSERV\C$\DRIVERSTAGING\OEMDATA.DLL"; </span>

<span class="ne-text"> pConfigFile = "\\CORPSERV\C$\DRIVERSTAGING\OEMUI.DLL";</span>

  • 客户端分配一个*DRIVER_CONTAINER* driverContainer 结构并初始化然后包含 DRIVER_INFO_2 结构。

<span class="ne-text">DRIVER_CONTAINER 结构通过使用</span>``<strong><span class="ne-text">DRIVER_INFO</span></strong>``<span class="ne-text">结构提供有关</span>``<span class="ne-text">打印机驱动程序</span>``<span class="ne-text">的信息。</span>``<strong><span class="ne-text">DriverInfo</span></strong>``<span class="ne-text">成员指定限定了打印机驱动程序的属性的结构。</span>

  • 客户端调用 RpcAddPrinterDriver。

<span class="ne-text"> RpcAddPrinterDriver( L"\\CORPSERV", &driverContainer );</span>

  • 服务器添加打印机驱动程序并返回 0(成功)。

PrintNightmare分析

CVE-2021-34527 分析

原文中是说通过绕过 RpcAddPrinterDriver 的身份验证。那么可以在打印服务器中安装恶意驱动程序来达到LPE 和 RCE。

在微软文档中我们可以知道RpcAddPrinterDriver中还会额外的验证

PrintNightmare分析

<311>验证为

Windows 服务器检查客户端用户是否具有 SERVER_ACCESS_ADMINISTER 权限。

PrintNightmare分析

<312>验证为:

<span class="ne-text">The parameter validation performed by </span>``<strong><span class="ne-text">RpcAddPrinterDriver</span></strong>``<span class="ne-text"> is not supported by Windows NT 3.1, Windows NT 3.5, Windows NT 3.51, Windows 95, Windows NT 4.0, Windows 98, Windows 2000, Windows Millennium Edition, Windows XP, Windows Server 2003, Windows Vista, Windows Server 2008, Windows 7, or Windows Server 2008 R2.</span>

我们到知道上面整个添加或更新客户端和服务端的交互都是通过RPC来进行,其中我们需要加载安装*驱动程序,那么一定需要*客户端具有SeLoadDriverPrivilege权限。

PrintNightmare分析

那么我们想要在远程服务器添加安装*驱动程序,那么第一步需要绕过*SeLoadDriverPrivilege权限的检查。

按照原文的意思我们可以看一下当客户端需要调用RPC时。那么我们可以使用Process Monitor监视一下

Print Spooler服务在运行中的过程。

设置规则

PrintNightmare分析

可以检测spoolsv.exe的所有

PrintNightmare分析

通过阅读理解漏洞情况,我们可以大概可以定位到这个localspl.dll

PrintNightmare分析

通过查看这个DLL的相关信息我们可以知道:

PrintNightmare分析

Localspl.dll

Local print provider. Handles all print jobs directed to printers that are managed from the local server.

处理定向到从本地服务器管理的打印机的所有打印作业。

<a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/print/introduction-to-print-providers" data-href="https://docs.microsoft.com/en-us/windows-hardware/drivers/print/introduction-to-print-providers" target="_blank" class="ne-link"><span class="ne-text">https://docs.microsoft.com/en-us/windows-hardware/drivers/print/introduction-to-print-providers</span></a>

同时也实现了打印提供程序定义的整套功能。

<a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/print/local-print-provider" data-href="https://docs.microsoft.com/en-us/windows-hardware/drivers/print/local-print-provider" target="_blank" class="ne-link"><span class="ne-text">https://docs.microsoft.com/en-us/windows-hardware/drivers/print/local-print-provider</span></a>

我们在查看这个整套功能中可以清楚看到:

<a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/print/functions-defined-by-print-providers" data-href="https://docs.microsoft.com/en-us/windows-hardware/drivers/print/functions-defined-by-print-providers" target="_blank" class="ne-link"><span class="ne-text">https://docs.microsoft.com/en-us/windows-hardware/drivers/print/functions-defined-by-print-providers</span></a>

PrintNightmare分析

那么我们可以重点关注一下这个DLL

AddPrinterDriver <span class="ne-text">添加打印机驱动程序 将指定打印机的驱动程序文件添加到指定服务器。  </span>

在其它网站上我们可以查到

PrintNightmare分析

只有一个DLL会链接这个DLL,好吧。

重点看一下导出的函数列表

PrintNightmare分析

这里有个SplAddPrinterDriverEx ,听名字可以大概知道他的作用

直接提取c:windowssysytem32localspl_dll使用IDA打开然后追踪SplAddPrinterDriverEx。

PrintNightmare分析

可以看到a4的值是可控的,ValidateObjectAccess 是 Spooler Service 的常规安全检查,那么普通用户可以绕过安全检查并添加驱动程序。

PrintNightmare分析

从微软文档中我们可以看到 print spooler *远程系统上引用或从远程系统复制和*将打印机驱动程序或其他插件作为本地系统调用时的一些安全措施

<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-prsod/340e969b-3243-4116-bf79-47c45bb40264" data-href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-prsod/340e969b-3243-4116-bf79-47c45bb40264" target="_blank" class="ne-link"><span class="ne-text">https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-prsod/340e969b-3243-4116-bf79-47c45bb40264</span></a>

Windows 实现可以执行以下一项或多项操作:

  • <span class="ne-text">限制非管理用户安装打印机驱动程序。</span>
  • <span class="ne-text">检查打印机驱动程序的数字签名。</span>
  • <span class="ne-text">在下载此类组件或首次执行该组件之前,提示用户同意。</span>

上面的则可以绕过这些安全措施来使用非管理用户安装没有签名的打印机驱动程序

PrintNightmare分析

然后返回InternalAddPrinterDriverEx中

我们在漏洞原文中可以看到作者描述了文件复制的情况

PrintNightmare分析

同样我们在InternalAddPrinterDriverEx中也找到了相关文件复制操作

PrintNightmare分析

跟进一下CopyFilesToFinalDirectory

PrintNightmare分析

  • <span class="ne-text">C:WindowsSystem32spooldriversx643</span>
  • <span class="ne-text">C:WindowsSystem32spooldriversx643old</span>
  • <span class="ne-text">C:WindowsSystem32spooldriversx643new</span>

PrintNightmare分析

结合漏洞原文我们可以知道复制pDataFile ,pConfigFile ,pDriverPath之后的文件夹为: C:WindowsSystem32spooldriversx643new

然后再复制到 C:WindowsSystem32spooldriversx643中

并加载 C:WindowsSystem32spooldriversx643 [*pDataFile]和 C:WindowsSystem32 spooldriversx643[*pDriverPath] 进入 Spooler 服务中。

在Process中我们可以更为清晰地看到这一过程:

我们可以在

DRIVER_INFO_2 结构提供有关打印机驱动程序的信息

<span class="ne-text">pName = L"OEM 打印机驱动程序"; </span>

<span class="ne-text"> pEnvironment = L"Windows NT x86"; /* 驱动程序兼容的环境 */ </span>

<span class="ne-text"> pDriverPath = "\\CORPSERV\C$\DRIVERSTAGING\OEMDRV.DLL"; </span>

<span class="ne-text"> pDataFile = "\\CORPSERV\C$\DRIVERSTAGING\OEMDATA.DLL"; </span>

<span class="ne-text"> pConfigFile = "\\CORPSERV\C$\DRIVERSTAGING\OEMUI.DLL";</span>

这里定义好<span class="ne-text">pDriverPath,pDataFile,pConfigFile</span>这3个DLL的值/路径。

*Process中可以看到读取了*DRIVER_INFO_2 结构中的3跟DLL

PrintNightmare分析

我们可以看一下堆栈,然后在ida中追一下,

PrintNightmare分析

PrintNightmare分析

按照漏洞原文的意思,这里我们可以重点关注一下这3个DLL的路径判断

<span class="ne-text">pDataFile =</span>

<span class="ne-text">pConfigFile =</span>

<span class="ne-text">pDriverPath=</span>

PrintNightmare分析

这里不多描述。建议有兴趣的同学自己去找一下。

然后具体看一下复制文件的过程

PrintNightmare分析

PrintNightmare分析

PrintNightmare分析

PrintNightmare分析

需要使用驱动程序升级的备份功能,旧版本将备份到 C:WindowsSystem32spooldriversx643old1 文件夹中。

PrintNightmare分析

最后就是加载我们的任意DLL进入 Spooler 服务中,这样就完成了漏洞利用。

PrintNightmare分析

如果在远程RCE中我们把pConfigFile`设置为UNC(Universal Naming Convention)地址就可以了。

注意:

  1. <span class="ne-text">创建的smb服务允许匿名访问。</span>
  2. <span class="ne-text">验证使用普通域用户的用户名和密码。</span>
  3. <span class="ne-text">需要在域环境内。</span>

理论上说影响所有运行有打印机服务的windows机器。

CVE-2021-34527 复现

目前公开的EXP主要有:

C++

<a href="https://github.com/hayasec/PrintNightmare" data-href="https://github.com/hayasec/PrintNightmare" target="_blank" class="ne-link"><span class="ne-text">https://github.com/hayasec/PrintNightmare</span></a>

python/C#

<a href="https://github.com/cube0x0/CVE-2021-1675" data-href="https://github.com/cube0x0/CVE-2021-1675" target="_blank" class="ne-link"><span class="ne-text">https://github.com/cube0x0/CVE-2021-1675</span></a>

以及本地提权的

<a href="https://github.com/hlldz/CVE-2021-1675-LPE" data-href="https://github.com/hlldz/CVE-2021-1675-LPE" target="_blank" class="ne-link"><span class="ne-text">https://github.com/hlldz/CVE-2021-1675-LPE</span></a>

1.本地提权复现

使用的是

<a href="https://github.com/hlldz/CVE-2021-1675-LPE" data-href="https://github.com/hlldz/CVE-2021-1675-LPE" target="_blank" class="ne-link"><span class="ne-text">https://github.com/hlldz/CVE-2021-1675-LPE</span></a>

环境为:

PrintNightmare分析

复现不难,因为spoolsv.exe是x64的,所以我们这里使用Cobalt Strike的是x64的dll。

PrintNightmare分析

执行漏洞利用时,需要将 DLL 路径作为漏洞利用的第一个参数。就可以了!

<span class="ne-text">CVE-2021-1675-LPE.exe PAYLOAD_DLL_PATH</span>

PrintNightmare分析

PrintNightmare分析

2.远程RCE复现

使用的是

<span class="ne-text">https://github.com/cube0x0/CVE-2021-1675<br/></span>

环境为:

攻击主机:WIN10 域普通用户 text 域内主机

PrintNightmare分析

攻击主机:windows server 2019 域控(DC

PrintNightmare分析

按照<span class="ne-text"> </span><a href="https://github.com/cube0x0/CVE-2021-1675" data-href="https://github.com/cube0x0/CVE-2021-1675" target="_blank" class="ne-link"><span class="ne-text">https://github.com/cube0x0/CVE-2021-1675</span></a> 的smb设置方法,在域内一台主机上提供匿名访问权限的共享文件

PrintNightmare分析

把恶意的DLL放进分享目录并允许匿名访问,在域控或目标主机上必须能直接获取到文件。

否则:

<span class="ne-text">报错 </span>``<strong><span class="ne-text">Error: code: 0x5 - rpc_s_access_denied</span></strong>``<span class="ne-text"> 说明smb还不能匿名访问</span>

PrintNightmare分析

这里使用的是C#版本的EXP来进行演示利用

PrintNightmare分析

在DC对应的文件夹中,我们可以看到

PrintNightmare分析

可以看到Cobalt Strike成功上线

PrintNightmare分析

防御方法

微软建议

*确定 Print Spooler 服务是否正在运行*

运行以下命令:

<span class="ne-text">Get-Service -Name Spooler</span>

如果 Print Spooler 正在运行或该服务未设置为禁用,请选择以下选项之一以禁用 Print Spooler 服务,或通过组策略禁用入站远程打印:

*选项 1 - 禁用 Print Spooler 服务*

如果禁用 Print Spooler 服务适合您的企业,请使用以下 PowerShell 命令:

<span class="ne-text">Stop-Service -Name Spooler -Force</span>

<span class="ne-text">Set-Service -Name Spooler -StartupType Disabled</span>

*选项 2 - 通过组策略禁用入站远程打印*

还可以通过组策略配置设置:

计算机配置/管理模板/打印机

禁用“允许打印后台处理程序接受客户端连接:”策略以阻止远程攻击。

限制 ACL

为驱动程序目录和所有子目录添加拒绝规则,防止 SYSTEM 帐户修改其内容。

<span class="ne-text">$Path = "C:WindowsSystem32spooldrivers"</span>

<span class="ne-text">$Acl = (Get-Item $Path).GetAccessControl('Access')</span>

<span class="ne-text">$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule("System", "Modify", "ContainerInherit, ObjectInherit", "None", "Deny")</span>

<span class="ne-text">$Acl.AddAccessRule($Ar)</span>

<span class="ne-text">Set-Acl $Path $Acl</span>

检测方法

<span class="ne-text">EventID = '11' and Image like 'spoolsv.exe' and TargetFilename like 'C:WindowsSystem32spooldriversx643'</span>

<span class="ne-text">EventID      316 </span>

<span class="ne-text">Message    INFO 316 NT AUTHORITYSYSTEM 已添加或更新 Windows x64 Version-3 的打印机驱动程序 1234。文件:- UNIDRV.DLL, kernelbase.dll, 123.dll。无需用户操作。</span>

id:李木

参考:

https://github.com/afwu/PrintNightmare

https://github.com/cube0x0/CVE-2021-1675

https://github.com/evilashz/CVE-2021-1675-LPE-EXP

相关推荐: Code Security Guide -Thinkphp3.2开发

一、Thinkphp安装基础 1.1安装ThinkPHP Thinkphp ->MVC结构 ->model(数据库) ->view(显示) ->comtrol(逻辑结构控制) Thinkphp 版本:3.2.3,解开压缩包之后,准备好我…

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月31日03:56:56
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   PrintNightmare分析https://cn-sec.com/archives/692010.html