Windows Print Spooler服务最新漏洞CVE-2021-34527详细分析
近日,有安全研究員在github上公開了”CVE-2021-1675”的exp PrintNightmare,后經(jīng)驗證公開的exp是一個與CVE-2021-1675不同的漏洞,微軟為其分配了新的編號CVE-2021-34527。這篇文章記錄了CVE-2021-34527的復(fù)現(xiàn)過程,并對漏洞成因進行了簡單的分析。
漏洞復(fù)現(xiàn)
【學(xué)習(xí)網(wǎng)絡(luò)安全但不知道怎么開始的來call me】
? 這里記錄域控環(huán)境下使用普通權(quán)限域賬戶實現(xiàn)RCE反彈nt authority\system shell的過程。下面的漏洞復(fù)現(xiàn)和漏洞分析都是基于Windows server 2019,2021-6補丁的,winver=17763.1999。經(jīng)筆者測試在無任何補丁的Windows server 2019,winver=17763.107環(huán)境下使用以下步驟也可以復(fù)現(xiàn)RCE。
環(huán)境配置
【學(xué)習(xí)網(wǎng)絡(luò)安全但不知道怎么開始的來call me】
實現(xiàn)RCE的條件如下:
1.一個普通權(quán)限的域賬戶,用另一臺計算機使用該域賬戶登錄加入域環(huán)境。其中域賬戶權(quán)限如下
2.域控主機需要能夠訪問到使用上述配置登錄的計算機的一個共享目錄,在Windows下可以使用smb實現(xiàn),用管理員權(quán)限的powershell運行以下命令即可
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運行完命令重啟生效。
復(fù)現(xiàn)
【學(xué)習(xí)網(wǎng)絡(luò)安全但不知道怎么開始的來call me】
? GitHub上有2個公開的exp,python版本的https://github.com/cube0x0/CVE-2021-1675 和C++版本的https://github.com/afwu/PrintNightmare ,其中C++版本的是從Zhiniang Peng (@edwardzpeng) & Xuefeng Li (@lxf02942370)公開的exp fork來的。
? 這兩個版本的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的路徑修改為域控主機對應(yīng)的路徑,如筆者這里對應(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ū)動前的驗證ValidateObjectAccess是可以被跳過的。如下localspl!SplAddPrinterDriverEx中的匯編代碼為存在漏洞可以導(dǎo)致ValidateObjectAccess被繞過的代碼。
其中esi為dwFileCopyFlags,是一個調(diào)用者可控的參數(shù),bt esi,0xf 將esi中偏移0xf的比特位保存到CF標志位,即CF標志位與esi的0x10比特位相同,dwFileCopyFlags=0x8014時CF=1。cmovnb ebx, [rsp+58h+arg_30] 即mov if not below,cmovnb會檢測CF標志位是否為0且當CF為0時進行移位操作,此時[rsp+0x90]=1,CF=1不會將ebx賦值為1。調(diào)試現(xiàn)場如下
由于ebx=0,jz short loc_180085F64 會跳轉(zhuǎn)到InternalAddPrinterDriverEx處執(zhí)行后續(xù)復(fù)制并加載驅(qū)動的操作,跳過了0x180085F57處ValidateObjectAccess的檢測。
InternalAddPrinterDriverEx
? RpcAddPrinterDriverEx會在spoolsv!RpcAddPrinterDriverEx處解析,調(diào)用到localspl!LocalAddPrinterDriverEx處的回調(diào),并最終由于localspl!SplAddPrinterDriverEx處的驗證ValidateObjectAccess無效導(dǎo)致可以調(diào)用到localspl!InternalAddPrinterDriverEx加載驅(qū)動并執(zhí)行。
? 調(diào)用到localspl!SplAddPrinterDriverEx時的?;厮萑缦?/p> 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的補丁中在spoolsv!RpcAddPrinterDriverEx中調(diào)用YAddPrinterDriverEx加載驅(qū)動前加了幾處校驗,如下右為補丁后的spoolsv.exe。補丁后YIsElevated、RunningAsLUA分別校驗了當前用戶的token和LUA權(quán)限,這兩處校驗在RCE中可以通過IPC被繞過;YIsElevationRequired檢驗了HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint\NoWarningNoElevationOnInstall 的注冊表項,但是筆者在2021-6全補丁的Windows server和Windows10系統(tǒng)上均未發(fā)現(xiàn)有該注冊表項,所以這個緩解在目前來看也是無效的。(這兩處緩解可能是針對Yunhai Zhang和ZhiPeng Huo提供的CVE-2021-1675的poc)
? 隨后由于spoolsv!AddPrinterDriverExW調(diào)用到localspl!LocalAddPrinterDriverEx處的回調(diào),又由于上述分析的localspl!SplAddPrinterDriverEx中驗證無效進入localspl!InternalAddPrinterDriverEx的流程。
? localspl!InternalAddPrinterDriverEx主要進行了如下操作,其中
%spooler%=C:\Windows\System32\spool\
1.ValidateDriverInfo進行驅(qū)動簽名等的檢查 2.CreateInternalDriverFileArray創(chuàng)建spooler目錄下的驅(qū)動文件,即%spooler%\drivers\x64 3.GetPrintDriverVersion、CheckFilePlatform檢查驅(qū)動版本和驅(qū)動運行平臺 4.SplIsCompatibleDriver進行驅(qū)動版本和驅(qū)動兼容性檢查,驅(qū)動版本號只能為3 5.CreateVersionDirectory使用提供的驅(qū)動版本號,創(chuàng)建spooler目錄下驅(qū)動版本號目錄,由于驅(qū)動版本號只能為3,最終目錄為%spooler%\drivers\x64\3 6.CopyFilesToFinalDirectory創(chuàng)建%spooler%\3目錄下New、Old文件夾,創(chuàng)建New、Old目錄下的臨時目錄,如%spooler%\drivers\x64\3\Old\1、%spooler%\drivers\x64\3\Old\2;并將上傳的驅(qū)動移動到臨時目錄下 7.WaitRequiredForDriverUnload加載6中臨時目錄下的驅(qū)動,路徑如%spooler%\drivers\x64\3\old\1\xx.dllValidateDriverInfo
? localspl!ValidateDriverInfo在如下代碼會校驗加載驅(qū)動的簽名,可以使用0x8000的dwFileCopyFlags繞過,0x8000即RpcAddPrinterDriverEx 的API文檔中提到的APD_INSTALL_WARNED_DRIVER,翻譯過來即強制加載驅(qū)動。
CreateInternalDriverFileArray
? localspl!CreateInternalDriverFileArray中會使用如下代碼根據(jù)RpcAddPrinterDriverEx 的dwFileCopyFlags參數(shù)生成CreateFile的參數(shù),a5=1會使用%spooler%目錄下路徑做為CreateFile的參數(shù);RCE利用時我們上傳的驅(qū)動此時是在一個UNC路徑下,如筆者本地為\192.168.18.153\share\rev.dll ,所以這里需要構(gòu)造dwFileCopyFlags&0x10=1使spooler使用我們的UNC路徑。
其中a5參數(shù)從localspl!LocalAddPrinterDriverEx這里傳入,
SplIsCompatibleDriver
? localspl!SplIsCompatibleDriver會檢查將要加載的驅(qū)動的版本號,版本號v117只能為3
其中v117會在localspl!InternalAddPrinterDriverEx這里校驗兩次,v117==2和v117>3都會導(dǎo)致驅(qū)動加載失敗。
? localspl!SplIsCompatibleDriver檢查驅(qū)動兼容性時會調(diào)用到ntprint!PSetupIsCompatibleDriver,最終會調(diào)用到如下代碼,其中a6=v117為驅(qū)動版本號,當v117<=2時返回0會導(dǎo)致驅(qū)動加載失敗。
綜上,當v117==2、v117>3、v117<=2時均會最終導(dǎo)致驅(qū)動加載失敗,v117只能為3。
CopyFilesToFinalDirectory
? localspl!CopyFilesToFinalDirectory主要是創(chuàng)建%spooler%\drivers\x64\3\New、%spooler%\drivers\x64\3\Old,并創(chuàng)建臨時目錄如
%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移動到%spooler%\drivers\x64\3\Old\1里。
最終在localspl!CompleteDriverUpgrade里更新所加載驅(qū)動的信息并加載上述臨時目錄下的驅(qū)動。
總結(jié)
【學(xué)習(xí)網(wǎng)絡(luò)安全但不知道怎么開始的來call me】
? 據(jù)Zhiniang Peng (@edwardzpeng) & Xuefeng Li (@lxf02942370)在最初公開的exp README里描述,spooler的漏洞最初用于10年前的震網(wǎng)(Stuxnet)攻擊,10年間spooler模塊也被披露了許多漏洞,但不知是因為微軟補丁修復(fù)的不徹底還是spooler模塊本身實現(xiàn)起來的復(fù)雜性導(dǎo)致了CVE-2021-1675和CVE-2021-34527的出現(xiàn)。微軟已于2021.7.7發(fā)布了一個緊急安全更新補丁,希望微軟的這個補丁能使spooler更安全一些吧;p
【兄弟們,跟我一起來rua它】
總結(jié)
以上是生活随笔為你收集整理的Windows Print Spooler服务最新漏洞CVE-2021-34527详细分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows Hello 可绕过漏洞进
- 下一篇: java信息管理系统总结_java实现科