Windows Print Spooler服务最新漏洞CVE-2021-34527详细分析
近日,有安全研究員在github上公開了”CVE-2021-1675”的exp PrintNightmare,后經(jīng)驗(yàn)證公開的exp是一個(gè)與CVE-2021-1675不同的漏洞,微軟為其分配了新的編號(hào)CVE-2021-34527。這篇文章記錄了CVE-2021-34527的復(fù)現(xiàn)過程,并對(duì)漏洞成因進(jìn)行了簡(jiǎn)單的分析。
漏洞復(fù)現(xiàn)
【學(xué)習(xí)網(wǎng)絡(luò)安全但不知道怎么開始的來call me】
? 這里記錄域控環(huán)境下使用普通權(quán)限域賬戶實(shí)現(xiàn)RCE反彈nt authority\system shell的過程。下面的漏洞復(fù)現(xiàn)和漏洞分析都是基于Windows server 2019,2021-6補(bǔ)丁的,winver=17763.1999。經(jīng)筆者測(cè)試在無任何補(bǔ)丁的Windows server 2019,winver=17763.107環(huán)境下使用以下步驟也可以復(fù)現(xiàn)RCE。
環(huán)境配置
【學(xué)習(xí)網(wǎng)絡(luò)安全但不知道怎么開始的來call me】
實(shí)現(xiàn)RCE的條件如下:
1.一個(gè)普通權(quán)限的域賬戶,用另一臺(tái)計(jì)算機(jī)使用該域賬戶登錄加入域環(huán)境。其中域賬戶權(quán)限如下
2.域控主機(jī)需要能夠訪問到使用上述配置登錄的計(jì)算機(jī)的一個(gè)共享目錄,在Windows下可以使用smb實(shí)現(xiàn),用管理員權(quán)限的powershell運(yùn)行以下命令即可
mkdir C:\share icacls C:\share\ /T /grant Anonymous` logon:r icacls C:\share\ /T /grant Everyone:r New-SmbShare -Path C:\share -Name share -ReadAccess 'ANONYMOUS LOGON','Everyone' REG ADD "HKLM\System\CurrentControlSet\Services\LanManServer\Parameters" /v NullSessionPipes /t REG_MULTI_SZ /d srvsvc /f REG ADD "HKLM\System\CurrentControlSet\Services\LanManServer\Parameters" /v NullSessionShares /t REG_MULTI_SZ /d share /f REG ADD "HKLM\System\CurrentControlSet\Control\Lsa" /v EveryoneIncludesAnonymous /t REG_DWORD /d 1 /f REG ADD "HKLM\System\CurrentControlSet\Control\Lsa" /v RestrictAnonymous /t REG_DWORD /d 0 /f運(yùn)行完命令重啟生效。
復(fù)現(xiàn)
【學(xué)習(xí)網(wǎng)絡(luò)安全但不知道怎么開始的來call me】
? GitHub上有2個(gè)公開的exp,python版本的https://github.com/cube0x0/CVE-2021-1675 和C++版本的https://github.com/afwu/PrintNightmare ,其中C++版本的是從Zhiniang Peng (@edwardzpeng) & Xuefeng Li (@lxf02942370)公開的exp fork來的。
? 這兩個(gè)版本的exp原理都是一樣的,也都是可用的,其中python版本的exp需要按照說明文檔安裝exp作者的impacket庫,其余不需要修改任何東西。
pip3 uninstall impacket git clone https://github.com/cube0x0/impacket cd impacket python3 ./setup.py install? c++版本的exp需要把第112行UNIDRV.DLL的路徑修改為域控主機(jī)對(duì)應(yīng)的路徑,如筆者這里對(duì)應(yīng)的路徑應(yīng)修改為:
//info.pDriverPath = (LPWSTR)L"C:\Windows\System32\DriverStore\FileRepository\ntprint.inf_amd64_19a3fe50fa9a21b6\Amd64\UNIDRV.DLL";
info.pDriverPath = (LPWSTR)L"C:\Windows\System32\DriverStore\FileRepository\ntprint.inf_amd64_83aa9aebf5dffc96\Amd64\UNIDRV.DLL";
其余不需要修改任何東西,使用vs編譯即可。
? python版本exp命令及RCE截圖:
? c++版本exp命令及RCE截圖:
漏洞分析
【學(xué)習(xí)網(wǎng)絡(luò)安全但不知道怎么開始的來call me】
漏洞根源
? 漏洞的關(guān)鍵在于localspl!SplAddPrinterDriverEx中調(diào)用InternalAddPrinterDriverEx加載驅(qū)動(dòng)前的驗(yàn)證ValidateObjectAccess是可以被跳過的。如下localspl!SplAddPrinterDriverEx中的匯編代碼為存在漏洞可以導(dǎo)致ValidateObjectAccess被繞過的代碼。
其中esi為dwFileCopyFlags,是一個(gè)調(diào)用者可控的參數(shù),bt esi,0xf 將esi中偏移0xf的比特位保存到CF標(biāo)志位,即CF標(biāo)志位與esi的0x10比特位相同,dwFileCopyFlags=0x8014時(shí)CF=1。cmovnb ebx, [rsp+58h+arg_30] 即mov if not below,cmovnb會(huì)檢測(cè)CF標(biāo)志位是否為0且當(dāng)CF為0時(shí)進(jìn)行移位操作,此時(shí)[rsp+0x90]=1,CF=1不會(huì)將ebx賦值為1。調(diào)試現(xiàn)場(chǎng)如下
由于ebx=0,jz short loc_180085F64 會(huì)跳轉(zhuǎn)到InternalAddPrinterDriverEx處執(zhí)行后續(xù)復(fù)制并加載驅(qū)動(dòng)的操作,跳過了0x180085F57處ValidateObjectAccess的檢測(cè)。
InternalAddPrinterDriverEx
? RpcAddPrinterDriverEx會(huì)在spoolsv!RpcAddPrinterDriverEx處解析,調(diào)用到localspl!LocalAddPrinterDriverEx處的回調(diào),并最終由于localspl!SplAddPrinterDriverEx處的驗(yàn)證ValidateObjectAccess無效導(dǎo)致可以調(diào)用到localspl!InternalAddPrinterDriverEx加載驅(qū)動(dòng)并執(zhí)行。
? 調(diào)用到localspl!SplAddPrinterDriverEx時(shí)的棧回溯如下
0:009> k# Child-SP RetAddr Call Site 00 0000001f`7f83e938 00007ffc`fb225852 localspl!SplAddPrinterDriverEx 01 0000001f`7f83e940 00007ff6`6c23ba9f localspl!LocalAddPrinterDriverEx+0xa2 02 0000001f`7f83e990 00007ff6`6c215ffe spoolsv!AddPrinterDriverExW+0x6f 03 0000001f`7f83e9d0 00007ff6`6c212c71 spoolsv!YAddPrinterDriverEx+0x2ce 04 0000001f`7f83ea10 00007ffd`027184a3 spoolsv!RpcAddPrinterDriverEx+0x181 ...? 2021-6的補(bǔ)丁中在spoolsv!RpcAddPrinterDriverEx中調(diào)用YAddPrinterDriverEx加載驅(qū)動(dòng)前加了幾處校驗(yàn),如下右為補(bǔ)丁后的spoolsv.exe。補(bǔ)丁后YIsElevated、RunningAsLUA分別校驗(yàn)了當(dāng)前用戶的token和LUA權(quán)限,這兩處校驗(yàn)在RCE中可以通過IPC被繞過;YIsElevationRequired檢驗(yàn)了HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint\NoWarningNoElevationOnInstall 的注冊(cè)表項(xiàng),但是筆者在2021-6全補(bǔ)丁的Windows server和Windows10系統(tǒng)上均未發(fā)現(xiàn)有該注冊(cè)表項(xiàng),所以這個(gè)緩解在目前來看也是無效的。(這兩處緩解可能是針對(duì)Yunhai Zhang和ZhiPeng Huo提供的CVE-2021-1675的poc)
? 隨后由于spoolsv!AddPrinterDriverExW調(diào)用到localspl!LocalAddPrinterDriverEx處的回調(diào),又由于上述分析的localspl!SplAddPrinterDriverEx中驗(yàn)證無效進(jìn)入localspl!InternalAddPrinterDriverEx的流程。
? localspl!InternalAddPrinterDriverEx主要進(jìn)行了如下操作,其中
%spooler%=C:\Windows\System32\spool\
1.ValidateDriverInfo進(jìn)行驅(qū)動(dòng)簽名等的檢查 2.CreateInternalDriverFileArray創(chuàng)建spooler目錄下的驅(qū)動(dòng)文件,即%spooler%\drivers\x64 3.GetPrintDriverVersion、CheckFilePlatform檢查驅(qū)動(dòng)版本和驅(qū)動(dòng)運(yùn)行平臺(tái) 4.SplIsCompatibleDriver進(jìn)行驅(qū)動(dòng)版本和驅(qū)動(dòng)兼容性檢查,驅(qū)動(dòng)版本號(hào)只能為3 5.CreateVersionDirectory使用提供的驅(qū)動(dòng)版本號(hào),創(chuàng)建spooler目錄下驅(qū)動(dòng)版本號(hào)目錄,由于驅(qū)動(dòng)版本號(hào)只能為3,最終目錄為%spooler%\drivers\x64\3 6.CopyFilesToFinalDirectory創(chuàng)建%spooler%\3目錄下New、Old文件夾,創(chuàng)建New、Old目錄下的臨時(shí)目錄,如%spooler%\drivers\x64\3\Old\1、%spooler%\drivers\x64\3\Old\2;并將上傳的驅(qū)動(dòng)移動(dòng)到臨時(shí)目錄下 7.WaitRequiredForDriverUnload加載6中臨時(shí)目錄下的驅(qū)動(dòng),路徑如%spooler%\drivers\x64\3\old\1\xx.dllValidateDriverInfo
? localspl!ValidateDriverInfo在如下代碼會(huì)校驗(yàn)加載驅(qū)動(dòng)的簽名,可以使用0x8000的dwFileCopyFlags繞過,0x8000即RpcAddPrinterDriverEx 的API文檔中提到的APD_INSTALL_WARNED_DRIVER,翻譯過來即強(qiáng)制加載驅(qū)動(dòng)。
CreateInternalDriverFileArray
? localspl!CreateInternalDriverFileArray中會(huì)使用如下代碼根據(jù)RpcAddPrinterDriverEx 的dwFileCopyFlags參數(shù)生成CreateFile的參數(shù),a5=1會(huì)使用%spooler%目錄下路徑做為CreateFile的參數(shù);RCE利用時(shí)我們上傳的驅(qū)動(dòng)此時(shí)是在一個(gè)UNC路徑下,如筆者本地為\192.168.18.153\share\rev.dll ,所以這里需要構(gòu)造dwFileCopyFlags&0x10=1使spooler使用我們的UNC路徑。
其中a5參數(shù)從localspl!LocalAddPrinterDriverEx這里傳入,
SplIsCompatibleDriver
? localspl!SplIsCompatibleDriver會(huì)檢查將要加載的驅(qū)動(dòng)的版本號(hào),版本號(hào)v117只能為3
其中v117會(huì)在localspl!InternalAddPrinterDriverEx這里校驗(yàn)兩次,v117==2和v117>3都會(huì)導(dǎo)致驅(qū)動(dòng)加載失敗。
? localspl!SplIsCompatibleDriver檢查驅(qū)動(dòng)兼容性時(shí)會(huì)調(diào)用到ntprint!PSetupIsCompatibleDriver,最終會(huì)調(diào)用到如下代碼,其中a6=v117為驅(qū)動(dòng)版本號(hào),當(dāng)v117<=2時(shí)返回0會(huì)導(dǎo)致驅(qū)動(dòng)加載失敗。
綜上,當(dāng)v117==2、v117>3、v117<=2時(shí)均會(huì)最終導(dǎo)致驅(qū)動(dòng)加載失敗,v117只能為3。
CopyFilesToFinalDirectory
? localspl!CopyFilesToFinalDirectory主要是創(chuàng)建%spooler%\drivers\x64\3\New、%spooler%\drivers\x64\3\Old,并創(chuàng)建臨時(shí)目錄如
%spooler%\drivers\x64\3\Old\1,將UNIDRV.DLL、kernelbase.dll、rev.dll依次從C:\Windows\System32\spool\drivers\x64\3\New、C:\Windows\System32\spool\drivers\x64\3里使用MoveFileExW移動(dòng)到%spooler%\drivers\x64\3\Old\1里。
最終在localspl!CompleteDriverUpgrade里更新所加載驅(qū)動(dòng)的信息并加載上述臨時(shí)目錄下的驅(qū)動(dòng)。
總結(jié)
【學(xué)習(xí)網(wǎng)絡(luò)安全但不知道怎么開始的來call me】
? 據(jù)Zhiniang Peng (@edwardzpeng) & Xuefeng Li (@lxf02942370)在最初公開的exp README里描述,spooler的漏洞最初用于10年前的震網(wǎng)(Stuxnet)攻擊,10年間spooler模塊也被披露了許多漏洞,但不知是因?yàn)槲④浹a(bǔ)丁修復(fù)的不徹底還是spooler模塊本身實(shí)現(xiàn)起來的復(fù)雜性導(dǎo)致了CVE-2021-1675和CVE-2021-34527的出現(xiàn)。微軟已于2021.7.7發(fā)布了一個(gè)緊急安全更新補(bǔ)丁,希望微軟的這個(gè)補(bǔ)丁能使spooler更安全一些吧;p
【兄弟們,跟我一起來rua它】
總結(jié)
以上是生活随笔為你收集整理的Windows Print Spooler服务最新漏洞CVE-2021-34527详细分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows Hello 可绕过漏洞进
- 下一篇: 网络即服务(NaaS)是什么???