CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析

admin 2025年2月16日00:40:39评论31 views字数 5667阅读18分53秒阅读模式

CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析

本文为看雪论坛优秀‍‍‍文章
看雪论坛作者ID:蝶澈——

漏洞简介

2022 年 2 月,微软修补了 CVE-2022-21999 漏洞。Windows Print Spooler 存在权限提升漏洞,经过身份认证的本地攻击者可通过在目标系统上运行特制程序来利用此漏洞,成功利用此漏洞的攻击者可在目标系统上以 SYSTEM 权限执行任意代码。漏洞公开当天,国外安全研究员在网上公开了此漏洞的细节及 PoC,此漏洞为 CVE-2020-1030 漏洞补丁的绕过。经验证,此 PoC 可在 Windows 主机上稳定利用。
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析
通过阅读 CVE-2020-1030 技术文章(https://www.accenture.com/us-en/blogs/cyber-defense/discovering-exploiting-shutting-down-dangerous-windows-print-spooler-vulnerability),我们可以得知:
a. 可通过配置 copyfile 下的 module 值来指定 Point and Print dll,使 Spooler 自动加载这个库,但这个库的路径存在一定限制。

b. Spooler 会尝试从系统目录、Spooler 驱动程序目录、环境和驱动程序版本等目录去加载 Point and Print DLL,加载 Point and Print DLL 时,Spooler 会搜索以下路径:
i. **%SYSTEMROOT%\System32**ii. **%SYSTEMROOT%\System32\spool\drivers\<ENVIRONMENT>\<DRIVERVERSION>**
c. 通过在打印机上配置SpoolDirectory属性可创建任意且可写的目录,利用这点来创建任意用户可写的 ii. 目录。
d. 利用 a. 先后加载 AppVTerminator.dll、目标.dll。其中,加载 AppVTerminator.dll 是为了在配置SpoolDirectory后可以终止 Spooler,等待 Spooler 重启并创建相应目录后将目标 DLL 写入该目录,然后 a. 利用加载该 DLL。

漏洞分析

建议先看一下这两篇相关研究文章:
https://www.accenture.com/us-en/blogs/cyber-defense/discovering-exploiting-shutting-down-dangerous-windows-print-spooler-vulnerability
https://research.ifcr.dk/spoolfool-windows-print-spooler-privilege-escalation-cve-2022-22718-bf7752b68d81
由于 CVE-2020-1030 漏洞的 PoC 已公开,我们以 CVE-2020-1030 漏洞为基础开始对新的漏洞进行分析。微软在修补 CVE-2020-1030 漏洞时加入了一些安全验证,使用 CVE-2020-1030 的 PoC 已经无法将 SpoolDirectory 直接设置为 C:WindowsSystem32spooldriversx644 了,SplSetPrinterDataEx 函数中已添加了通过 IsValidSpoolDirectory 函数校验即将要设置的 SpoolDirectory 的路径的逻辑。
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析
IsValidSpoolDirectory 函数通过调用 AdjustFileName 函数将路径转换为规范路径,然后检查当前用户是否可以以GENERIC_WRITE访问权限打开或创建目标目录,最终检查目录的链接数是否不大于 1,如果校验通过则返回 True。由于我们对 C:WindowsSystem32spooldriversx644 没有可写权限所以校验失败。
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析
根据公开的技术文章,下面我们将使用重解析点绕过 IsValidSpoolDirectory 函数的校验成功设置 SpoolDirectory。我们先将 SpoolDirectory 设置为当前用户可操作的路径,如 C:UserstestAppDataLocalTemptesttest4,这样就通过 IsValidSpoolDirectory 函数的校验成功设置 SpoolDirectory。
然后再创建重解析点,将 C:UserstestAppDataLocalTemptesttest 链接到 C:WindowsSystem32spooldriversx64,等待 Spooler 创建 Everyone 具有可写权限的目录 C:WindowsSystem32spooldriversx644。
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析
Print Spooler 需要重启才能初始化 SpoolDirectory 指定的目录,也就是 C:UserstestAppDataLocalTemptesttest4 -> C:WindowsSystem32spooldriversx644。通过配置 Point and Print dll 为 AppVTerminator.dll 来停止 Print Spooler ,等待它重启调用 BuildPrinterInfo 函数(另外,调用 EnumPrinters 函数可加速调用 BuildPrinterInfo)来设置目标文件夹。
但在这里又出现一次校验,在 BuildPrinterInfo 函数调用 CreateEverybodySecurityDescriptor、GetSecurityDescriptorDacl、SetSecurityInfo 等函数为目标路径设置 Everyone 可以访问的安全描述符之前,会调用 IsPathALink 和 IsModuleFilePathAllowed 函数进行校验。
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析
如下图所示,IsModuleFilePathAllowed 函数会判断要目标路径是否在 SystemDirectory 或 DriverDirectory 路径下,如果满足条件就返回 True。其中,SystemDirectory 为 C:Windowssystem32,DriverDirectory 为 C:Windowssystem32spoolDRIVERSx64。
Print Spooler 在设置目录前需要保证要目标不在系统目录或驱动目录中,满足条件才会去设置目录。由于我们想要创建的目录是 C:WindowsSystem32spooldriversx644,并不满足条件,也就不能通过 IsModuleFilePathAllowed 函数处的校验。
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析
为了绕过此处的限制,我们将 SpoolDirectory 设置为 UNC 路径,即 \localhostC$UserstestAppDataLocalTemptesttest4,而不是 C:WindowsSystem32spooldriversx644。
这样在IsModuleFilePathAllowed 函数中校验的路径就是 UNClocalhostC$WindowsSystem32spooldriversx64printersx644,而不是 C:WindowsSystem32spooldriversx644,就不能通过 _wcsnicmp 函数和 SystemDirectory 或 DriverDirectory 匹配上,从而绕过这个判断。
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析
当我们有权限向 C:WindowsSystem32spooldriversx644 写入之后,将想要加载的 DLL 复制到该目录,然后通过 SetPrinterDataEx 函数配置 Point and Print dll 为 目标 DLL。Print Spooler 服务会调用 localspl!SplSetPrinterDataEx 函数进行处理,最终会在 SplLoadLibraryTheCopyFileModule 函数中调用 LoadLibraryW 函数来加载相应模块,在调用 LoadLibraryW 函数之前会通过 IsModuleFilePathAllowed 函数来判断目标 DLL 是否在 C:Windowssystem32、C:Windowssystem32spoolDRIVERSx64 以及 C:Windowssystem32spoolDRIVERSx644 目录下。
// SplSetPrinterDataEx         if ( !v11      && !wcsncmp(pKeyName, L"CopyFiles\", 0xAui64)      && !(*(_DWORD *)(*((_QWORD *)hPrinter + 0x15) + 168i64) & 0x4000000) )    {      SplCopyFileEvent(hPrinter, pKeyName);    }// SplCopyFileEvent    if ( !(unsigned int)SplGetPrinterDataEx(                          hPrinter,                          v7,                          L"Module",                          (unsigned int *)&v20,                          (unsigned __int8 *)pszModule,                          v19,                          &v19)      && v20 == 1 )    {      v3 = CreateFullyQualifiedNameFromPSpool(hPrinter, &v18);      if ( v3 )      {        v10 = SplLoadLibraryTheCopyFileModule((__int64)hPrinter, pszModule);// SplLoadLibraryTheCopyFileModule        if ( (unsigned int)GetDriverDirectory(&DriverDirectory, MaxLength, pIniEnvironment, 0i64, pIniSpooler) )        {          if ( !(unsigned int)MakeCanonicalPath(pszModule, &LibFileName)            || !(unsigned int)IsModuleFilePathAllowed(&LibFileName, &DriverDirectory)            || (hModule = LoadLibraryW(&LibFileName)) == 0i64 )          {            if ( (unsigned int)GetIniDriverAndDirForThisMachineEx(                                 *(_QWORD *)(hPrinter + 0x40),                                 MaxLength,                                 &IniDriverAndDir,                                 (struct _INIDRIVER **)&hPrinter,                                 pIniEnvironment) )            {              v12 = StringCchCopyW(&IniDriverModulePath, 0x104i64, &IniDriverAndDir);//                                              // 0:004> du beddc0   //IniDriverAndDir                                              // 00000000`00beddc0  "C:Windowssystem32spoolDRIVER"                                              // 00000000`00bede00  "Sx644"              v6 = StatusFromHResult(v12);              if ( !v6 )              {                v13 = StringCchCatW(&IniDriverModulePath, 0x104i64, pszModule);                v6 = StatusFromHResult(v13);                if ( !v6 )                {                  if ( (unsigned int)MakeCanonicalPath(&IniDriverModulePath, &LibFileName) )                  {                    if ( (unsigned int)IsModuleFilePathAllowed(&LibFileName, &IniDriverAndDir) )                    {                      hModule = LoadLibraryExW(&LibFileName, 0i64, v6 + 8);                      if ( !hModule )                        v6 = GetLastError();                    }                  }                }
IsModuleFilePathAllowed 函数中判断目标是否在 C:WindowsSystem32 目录或 DriverDirectory/IniDriverAndDir 目录或子目录下,所以我们可以利用漏洞在 C:Windowssystem32spoolDRIVERSx64 目录下创建可写任意文件夹(如 C:Windowssystem32spoolDRIVERSx645 ),然后将目标 DLL 复制过去并利用 Point and Print 来加载,如下图所示:
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析

补丁分析

以下为补丁前后版本的修改情况,BuildPrinterInfo 函数发生了变化。
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析
补丁前,在 BuildPrinterInfo 函数中会先尝试创建目标目录,同时共享 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE 权限(即 FILE_SHARE_VALID_FLAGS),成功执行后获得句柄(hObject)。
如果创建失败的话会尝试以 FILE_SHARE_VALID_FLAGS 权限打开该目录,如果当前用户没有相应权限也会打开失败。在通过IsPathALink 函数及 IsModuleFilePathAllowed 函数校验之后,会调用 SetSecurityInfo(hObject, SE_FILE_OBJECT, 4u, 0i64, 0i64, pDacl, 0i64) 函数来设置该目录。
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析
补丁后的 BuildPrinterInfo 函数只是尝试以 FILE_SHARE_READ 权限打开目标目录,并且删掉了之前使用 CreateEverybodySecurityDescriptor、GetSecurityDescriptorDacl、SetSecurityInfo 等函数为目标路径设置 Everyone 读写访问、执行等所有可能的访问权限,也就是不会再去创建新的 SpoolDirectory 了,也不会修改原本目录的权限。
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析

CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析

看雪ID:蝶澈——

https://bbs.pediy.com/user-home-701197.htm

*本文由看雪论坛 蝶澈—— 原创,转载请注明来自看雪社区
CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析

# 

原文始发于微信公众号(看雪学苑):CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月16日00:40:39
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析https://cn-sec.com/archives/905024.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息