CVE-2021-1675

漏洞详情

Windows Print Spooler 特权提升漏洞

补丁

KB5003637:windows10.0-kb5003637-x64_fd175a387e2f07586d85899a75d0bf10120a3c2c.msu

解压补丁

win10(应该是win8后某个时间点后)和win7之流的补丁不一样, 它变小了

  • 方法1 MSDelta
  • 方法2 C:\windows\WinSxS\

获取文件

所需文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
+---1052
| FaxPrinterInstaller.dll
| localspl.dll
| splwow64.exe
| spoolsv.exe
| winprint.dll
| winspool.drv
|
+---867
| FaxPrinterInstaller.dll
| localspl.dll
| splwow64.exe
| spoolsv.exe
| winprint.dll

对比

针对localspl.dll

新增函数

1
2
3
4
5
6
7
8
0000000180042780	GetApprovedPrinterList(ushort const *)	14	47	21
0000000180042840 IsDeviceControlEnabled(ushort const *) 10 50 15
00000001800428F4 IsPrinterApproved(_INIPRINTER *,ushort *) 33 172 53
00000001800486A4 GetSpoolerStringPolicy 16 88 23
00000001800487F8 GetUserSpoolerPolicy 15 75 23
0000000180048924 GetUserSpoolerStringPolicy 17 99 25
0000000180073F6C NCoreLibrary::TAutoHandleHKEY::~TAutoHandleHKEY(void) 3 12 3
00000001800DB130 NCoreLibrary::TAutoHandleHKEY::TAutoHandleHKEY(HKEY__ *) 1 10 0

修改函数

1
2
3
4
5
0.28	0.39	GI--EL-	IsLocalFile
0.84 0.98 GI----- GetSpoolerPolicy
0.94 0.99 GI--E-- PrintingDirectlyToPort
0.95 0.99 GI-JE-- LocalSendRecvBidiData
0.96 0.98 GI-J--- InitializePrintProvidor

对比补丁函数

共五个函数改变

isLocalFile

此函数修改了流程, 增加了首先将 / 替换为 \ 的流程

GetSpoolerPolicy

此函数实际无改变, 一个NCoreLibrary::HResultFromWin32内联了

PrintingDirectlyToPort

增加了IsDeviceControlEnabled判断, 与所有新增函数都有关, 关键字为 “USB”

InitializePrintProvidor

多初始化了几个全局变量, 且在PrintingDirectlyToPort中使用

  • g_pszDCPNonUsbPrint
  • g_pszDCPNoApprovedUsbPolicy
  • g_pszDCPUsbPrinterNotApproved

LocalSendRecvBidiData

做了一些操作 其中有部分判断了 pAction 赋值为 L"GetAll"(BIDI_ACTION_GET_ALL) 或者L"GetFromPortMon"

对于isLocalFile修改的分析

调用链:isLocalFile <-- ValidateDriverInfo <-- InternalAddPrinterDriverEx <-- SplAddPrinterDriverEx <-- localspl.dll
关键字AddPrinterDriverEx, 在powershell中调用Add-PrinterDriver后, 查看调用栈:

1
2
3
4
5
6
7
8
9
10
11
12
13
0:008> kb
RetAddr : Args to Child : Call Site
00007fff`3e0cb8fc : ...... : localspl!IsLocalFile
00007fff`3e0cd2a7 : ...... : localspl!ValidateDriverInfo+0x438
00007fff`3e1096bf : ...... : localspl!InternalAddPrinterDriverEx+0x1f3
00007fff`3e10806e : ...... : localspl!NPackageInstallLocalspl::LegacyInstallPrinterDriverFromPackage+0x71f
00007fff`3e10b637 : ...... : localspl!NPackageInstallLocalspl::InternalInstallPrinterDriverFromPackage+0x66b6
00007fff`3e101955 : ...... : localspl!SplInstallPrinterDriverFromPackage+0x127
00007ff7`a1edd40f : ...... : localspl!NPackageInstallLocalspl::TPackageInstallLocalspl::InstallDriver+0x95
00007ff7`a1eb6096 : ...... : spoolsv!RouterInstallPrinterDriverFromPackage+0x6f
00007ff7`a1eb207a : ...... : spoolsv!YInstallPrinterDriverFromPackage+0x46
00007fff`6da6a0e3 : ...... : spoolsv!RpcInstallPrinterDriverFromPackage+0x4a
......

查看ValidateDriverInfo函数, 发现检查了driver_info.pDriverPathdriver_info.pConfigFile, 其中若isLocalFile检查失败则直接失败退出.
其中isLocalFile中的流程易得判断是否为UNC路径, 即\\PDC-01.xz\c$\path\to\driver, 根据补丁易得修复了类似于//PDC-01.xz\c$\path\to\driver的绕过方法.

参考文档, 尝试后发现管理员权限下可对指定路径dll进行加载, 且无需数字签名.

其中指定路径为系统自带驱动所在路径, 可以使用../绕过.

非管理员权限

安装Generic / Text Only时并不需要管理员权限即可安装, 尝试设置相应结构体为Generic / Text Only对应的文件, 发现AddPrinterDriverEx依然需要管理员权限.

下断回溯后仔细观察发现InstallPrinterDriverFromPackage无需管理权限, 进一步观察发现关键为APD_STILL_INSTALL_WARNING_DRIVER

验证后发现如预期执行, 至此利用成功

新版本修复

除了localspl!IsLocalFile外, winspool!RpcAddPrinterDriverEx亦使用RunningAsLUA判断后去除了dwFileCopyFlags中的APD_STILL_INSTALL_WARNING_DRIVER

也就是说除非绕过RunningAsLUA否则不能以非管理员利用

poc

哈哈 太菜了拿不出手

参考资料

title
title
title
title
title
title
title
title
title