概念說明
1、UAF漏洞
UAF漏洞全稱是use after free,free是指函數(shù)是在堆上動(dòng)態(tài)分配空間后不再使用該數(shù)據(jù)從而被回收。但是由于程序員的一些不適當(dāng)?shù)牟僮鳎瑫?huì)導(dǎo)致攻擊者能夠操控已經(jīng)被釋放的區(qū)域,從而執(zhí)行一些byte codes。
利用uaf漏洞主要是注意幾點(diǎn):
1)在free()函數(shù)被調(diào)用回收buffer之后,指向該地址的指針是否被重置。
2)后續(xù)是否存在malloc()函數(shù)可以將新申請(qǐng)分配的空間分配到之前被free()回收的buffer區(qū)域。
3)利用沒有被重置的指針進(jìn)行攻擊
2、數(shù)據(jù)結(jié)構(gòu)
我們先了解一下相關(guān)結(jié)構(gòu)體的定義,參考自NT4.0的源碼dcobj.hxx#L97、dcobj.hxx#L236、dcobj.hxx#L1282、dcobj.hxx#L1686,另外HDC猶如其名,handle to device context,圖形設(shè)備信息對(duì)象的句柄。
3、C++ namespace(命名空間)關(guān)鍵字
在C++中,您可能會(huì)寫一個(gè)名為xyz()的函數(shù),在另一個(gè)可用的庫中也存在一個(gè)相同的函數(shù)xyz()。這樣,編譯器就無法判斷您所使用的是哪一個(gè) xyz()函數(shù)。因此,引入了命名空間這個(gè)概念,專門用于解決上面的問題,它可作為附加信息來區(qū)分不同庫中相同名稱的函數(shù)、類、變量等。使用了命名空間即定義了上下文。本質(zhì)上,命名空間就是定義了一個(gè)范圍。
定義命名空間:namespace namespace_name {
// 代碼聲明
}
引用命名空間中的變量:name::code; // code 可以是變量或函數(shù)
漏洞背景
2021年10月12日,卡巴斯基博客公開披露了在8月下旬捕獲到的Windows內(nèi)核提權(quán)0day漏洞的相關(guān)信息。該漏洞與Windows窗口管理和圖形化設(shè)備接口相關(guān)(Win32kfull.sys)。通過該漏洞可以讓普通權(quán)限用戶提權(quán)到system權(quán)限。
漏洞現(xiàn)狀
以下版本均受影響。卡巴斯基已經(jīng)發(fā)現(xiàn)在野利用,且官方已發(fā)布補(bǔ)丁,請(qǐng)及時(shí)安裝相關(guān)補(bǔ)丁。
Windows Server, version2004/20H2(Server Core Installation)
Windows 10 Version1607/1809/1909/2004/20H2/21H1
Windows 7 for 32/64-bit Systems Service Pack 1
Windows Server 2008/2012/2016/2019/2022
Windows 11 for ARM64-based Systems
Windows 11 for x64-based Systems
Windows 8.1 for 32/64-bit systems
Windows RT 8.1
漏洞成因
win32kfull的NtGdiResetDC()函數(shù)中存在一個(gè)use after free漏洞,攻擊者可以利用該漏洞將權(quán)限提升到NT AUTHORITY\SYSTEM的權(quán)限。
由于此函數(shù)調(diào)用hdcOpenDCW(),該函數(shù)執(zhí)行用戶模式回調(diào),因此存在該缺陷。在此回調(diào)期間,攻擊者可以使用與之前相同的句柄再次調(diào)用NtGdiResetDC()函數(shù),這將導(dǎo)致該句柄引用的PDC對(duì)象被釋放。
關(guān)于對(duì)象被釋放這一點(diǎn),在微軟官方的文章中提到:“調(diào)用CreateDC的線程擁有創(chuàng)建的HDC。當(dāng)這個(gè)線程被銷毀時(shí),HDC不再有效。因此,如果您創(chuàng)建HDC并將其傳遞給另一個(gè)線程,然后退出第一個(gè)線程,第二個(gè)線程將無法使用HDC。”
然后,攻擊者可以用自己的對(duì)象替換句柄引用的內(nèi)存,然后將執(zhí)行傳遞回原始NtGdiResetDC()調(diào)用,該調(diào)用現(xiàn)在將在沒有適當(dāng)驗(yàn)證的情況下使用攻擊者的對(duì)象。這可以允許攻擊者操縱內(nèi)核的狀態(tài),并結(jié)合其他利用技術(shù),以NT AUTHORITY\SYSTEM的身份獲得代碼執(zhí)行。
在win32kfull!NtGdiResetDC中調(diào)用了win32kfull!GreResetDCInternal:
在win32kfull!GreResetDCInternal中調(diào)用了用戶態(tài)的win32kbase!hdcOpenDCW:
在win32kfull!GreResetDCInternal的85行,v11+0xAB8可以設(shè)置為我們想要執(zhí)行的函數(shù),同時(shí)v11+0x708和(new_dcobj[0] + 6) + 0x708i64兩個(gè)入?yún)⒌闹悼梢栽谟脩魬B(tài)函數(shù)中被修改。內(nèi)核函數(shù)接受兩個(gè)用戶態(tài)的參數(shù),因此可以利用此漏洞造成任意地址讀寫。
漏洞利用
根據(jù)卡巴斯基的揭露,在執(zhí)行ResetDC的回調(diào)函數(shù)時(shí),對(duì)相同的句柄再次調(diào)用ResetDC,即可觸發(fā)漏洞。利用此漏洞需要使用GDI palette對(duì)象和一個(gè)內(nèi)核函數(shù)達(dá)到任意地址讀寫。可以利用NtQuerySystemInformation和EnumDeviceDrivers去泄露內(nèi)核模塊地址,最終可以進(jìn)行權(quán)限提升。為了便于理解,下文將結(jié)合exp的內(nèi)容進(jìn)行說明。
步驟0、獲取exp自身的token對(duì)象地址
準(zhǔn)備后續(xù)提權(quán)所需的信息。先獲取exp自身的token、特權(quán)信息在內(nèi)核中的地址等信息。
獲取exp自身的token方法如下:
進(jìn)而篩選出PoolFlag=“ThNm”的堆。
安裝Windows WDK后會(huì)自動(dòng)生成一個(gè)pooltag.txt。pooltag.txt里有poolflag相對(duì)應(yīng)的內(nèi)容。如下圖所示,不同的poolfalg標(biāo)志代表了不同的數(shù)據(jù)類型。
步驟1、hook對(duì)應(yīng)的函數(shù)
在下圖736行中,調(diào)用SetupUsermodeCallbackHook()函數(shù)來hook可用打印機(jī)驅(qū)動(dòng)的回調(diào)表。
hook步驟:
1、枚舉可用打印機(jī)并獲取驅(qū)動(dòng)信息。
2、遍歷每個(gè)驅(qū)動(dòng),如果找到目標(biāo)函數(shù)則修改回調(diào)表。
步驟2、創(chuàng)建一個(gè)全局的DC對(duì)象并保存其句柄
步驟3、調(diào)用ResetDC函數(shù)
調(diào)用ResetDC函數(shù),并向其傳遞全局DC的句柄。ResetDC函數(shù)執(zhí)行系統(tǒng)調(diào)用NtDgiResetDC及其內(nèi)部函數(shù)GreResetDCInternal并取得傳入的HDC所對(duì)應(yīng)的PDC對(duì)象,然后會(huì)調(diào)用hdcOpenDCW函數(shù)。
步驟4、執(zhí)行hook函數(shù)
??malloc()函數(shù)存在一個(gè)特性是會(huì)將新申請(qǐng)分配的空間分配到之前被free()回收的buffer區(qū)域。
??free()函數(shù)不會(huì)處理申請(qǐng)的內(nèi)存空間的內(nèi)容。所以數(shù)據(jù)會(huì)被保留下來。
調(diào)用ResetDC函數(shù)后會(huì)執(zhí)行回調(diào)函數(shù),由于已經(jīng)hook對(duì)應(yīng)的回調(diào)函數(shù),所以代碼流程進(jìn)入HOOK函數(shù)。
如上圖所示191行,再次執(zhí)行ResetDC函數(shù)并傳入全局的HDC值,由于第188行已經(jīng)把globals::should_trigger設(shè)為true,所以會(huì)按照正常的流程執(zhí)行。
此時(shí)在GreResetDCInternal函數(shù)內(nèi)會(huì)對(duì)該值對(duì)應(yīng)的PDC對(duì)象進(jìn)行釋放,造成該對(duì)象結(jié)構(gòu)的錯(cuò)誤。
步驟5、第二次ResetDC調(diào)用完成
完成調(diào)用后繼續(xù)運(yùn)行到下圖所示的70行。
對(duì)應(yīng)的匯編代碼如下:
_guard_dispatch_icall_nop的操作是jmp rax:
向上查看,可以看到rax=*(rbx+0xAD0):
而RBX寄存器的值則是使用由用戶層傳入的HDC創(chuàng)建的DCOBJ對(duì)象的指針。此時(shí),所對(duì)應(yīng)的PDC對(duì)象已經(jīng)在第四步的過程中被釋放掉了,但是由于未對(duì)該對(duì)象進(jìn)行判斷,此時(shí)可以進(jìn)行任意內(nèi)核函數(shù)的調(diào)用。整個(gè)過程如下圖所示:
由于前期已經(jīng)設(shè)置token的0x40位置的Privileges,從而給winlogon進(jìn)程添加SE_DEBUG_PRIVILEGE權(quán)限。
通過獲取TheadName從而來泄露其內(nèi)核地址空間,進(jìn)而調(diào)用RtlSetAllBits函數(shù)實(shí)現(xiàn)對(duì)Fake_RtlBitMapAddr中BitMapHeader buffer的設(shè)置。通過申請(qǐng)堆的大小和UAF中堆的大小相同,那么就可能申請(qǐng)到我們的這塊內(nèi)存,從而進(jìn)行堆噴射。
如下圖所示,正好獲取到構(gòu)造好了這塊內(nèi)存中的數(shù)據(jù),最終實(shí)現(xiàn)指針的利用,從而達(dá)到提權(quán)的目的。
步驟6、向winlogon注入啟動(dòng)cmd的shellcode
視頻演示
https://www.bilibili.com/video/BV1nM4y1P7nC/
參考鏈接:
1、https://hack-big.tech/2019/01/24/uaf漏洞原理實(shí)例淺析/
2、https://www.kaspersky.com/blog/mysterysnail-cve-2021-40449/42448/
3、https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-40449
4、https://www.cve.org/CVERecord?id=CVE-2021-40449
5、https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createdca
6、https://ti.qianxin.com/blog/articles/CVE-2021-40449-vulnerability-recurrence-process/
轉(zhuǎn)載自安全客:https://www.anquanke.com/post/id/260841