漏洞描述
Windows 事件跟蹤 (ETW) 機制允許記錄內核或應用程式定義的事件以進行除錯, 開發人員能夠啟動和停止事件跟蹤會話,檢測應用程式以提供跟蹤事件,并通過呼叫 ETW 用戶模式 Windows API 集來使用跟蹤事件,
最終,這些將導致對內核 (ntoskrnl.exe) 的相應系統呼叫請求以執行功能,在ETW請求更新周期性捕獲狀態中,在特定條件下,存在一個use-after-free漏洞,攻擊者可以可控地分配一個0x30位元組的緩沖區,釋放它,然后重用這個緩沖區來執行任意代碼,該漏洞于2021年8月末紕漏詳情
漏洞詳情
使用NtTraceControl() 函式發送更新定期捕獲狀態的請求,函式代碼為 0x25(EtwFunctionUpdatePeriodicCaptureState) ,則會呼叫內核態函式EtwpUpdatePeriodicCaptureState,
第一次呼叫會申請一塊TimerContextInfo內核池,
第二次呼叫該函式在在內部可以通過傳入的引數(控制GUID),導致(呼叫回呼函式)釋放到掉內核物件TimerContextInfo,
第三次呼叫該函式將再次訪問TimerContextInfo,導致UAF
該漏洞在windows 10低版本中并不存在EtwpUpdatePeriodicCaptureState,本文以windows 10 20H2 x64系統進行Exploit的開發,
ed2k://|file|cn_windows_10_business_editions_version_20h2_updated_march_2021_x64_dvd_ca61aaaa.iso|6074574848|B6741C4E4B09337471B02DC95E953992|/
為了感謝廣大讀者伙伴的支持,準備了以下福利給到大家:
[一>獲取<一]
1、200多本網路安全系列電子書(該有的都有了)
2、全套工具包(最全中文版,想用哪個用哪個)
3、100份src原始碼技術檔案(專案學習不停,實踐得真知)
4、網路安全基礎入門、Linux、web安全、攻防方面的視頻(2021最新版)
6、 網路安全學習路線(告別不入流的學習)
7、ctf奪旗賽決議(題目決議實戰操作)
[一>獲取<一]
漏洞成因
第一次呼叫NtTraceControl函式并發送EtwFunctionUpdatePeriodicCaptureState代碼,則會呼叫內核函式EtwpUpdatePeriodicCaptureState,
? 該函式內部通過傳入的LogId獲取其對應的LoggerContext,通過控制Logid和GUID,滿足EtwpCheckNotificationAccess條件,則會將LoggerContext->PeriodicCaptureStateGuids.ProviderCount置為傳入的NumOfGuids,
? 并在后續申請大小為0x30的TimerContextInfo物件,并進行初始化,設定 TimerContextInfo->WorkItem.WorkerRoutine的回呼函式為SendCaptureStateNotificationsWorker,引數為TimerContextInfo物件
? 呼叫ExSetTimer,并將LoggerContext->PeriodicCaptureStateTimerState設定為 EtwpPeriodicTimerSet(TRUE),計時器例程為TimerContextInfo

第二次呼叫時,通過控制傳入的GUID,可以讓其走Free分支,在這個分支LoggerContext->PeriodicCaptureStateGuids.ProviderCount將會被設定為0

如果在第二次呼叫之后,sendCaptureStateNotificationsWorker回呼函式被執行,那么此時因為LoggerContext->PeriodicCaptureStateGuids.ProviderCount被重置為0,該函式只是簡單的將LoggerContext->PeriodicCaptureStateTimerState = EtwpPeriodicTimerUnset(False)

并在函式末尾釋放掉TimerContextInfo物件

然而再第三次呼叫,同樣選擇走Alloc_TimerContextInfo分支,在將LoggerContext->PeriodicCaptureStateGuids.ProviderCount置為傳入的NumOfGuids后,因為之前申請的LoggerContext->PeriodicCaptureStateTimer,已經被設定了,所以不會申請新的LoggerContext,只是將LoggerContext->PeriodicCaptureStateTimerState 設定為 EtwpPeriodicTimerSet,當系統呼叫SendCaptureStateNotificationsWorker、ExAllocateTimer函式時,傳入的引數TimerContextInfo已經被釋放,導致UAF

POC開發
在呼叫NtTraceControl,FunctionCode為EtwFunctionUpdatePeriodicCaptureState,InBuffer的結構體為

EtwpCheckNotificationAccess繞過
POC開發的難點在于如何繞過EtwpCheckNotificationAccess的檢測,該函式會檢測GUID對應的SecurityDescriptor是否包含特定的權限

本次需要繞過的權限檢測為0x80(**TRACELOG_GUID_ENABLE**)

系統中的GUID,包含TRACELOG_GUID_ENABLE的有很多,但是有一點我們需要明確,我們現在的權限相對較低,不能使用組為SYSTEM、LOCAL SERVICE、Administrators等權限較高的組,可以選擇使用Everyone、Users等權限較低的用戶

經過篩選,有3個GUID可以滿足要求,如下,既是Authenticated Users 低權限組,又包含TRACELOG_GUID_ENABLE的ACCESS MASK權限
14f8138e-3b61-580b-544b-2609378ae460 Allow NT AUTHORITY\Authenticated Users 001204e1 WMIGUID_QUERY, TRACELOG_CREATE_REALTIME, TRACELOG_CREATE_ONDISK, TRACELOG_GUID_ENABLE, TRACELOG_ACCESS_REALTIME
541dae91-cc3c-5807-b064-c2561c16d7e8 Allow NT AUTHORITY\Authenticated Users 001204e1 WMIGUID_QUERY, TRACELOG_CREATE_REALTIME, TRACELOG_CREATE_ONDISK, TRACELOG_GUID_ENABLE, TRACELOG_ACCESS_REALTIME
cb2ff72d-d4e4-585d-33f9-f3a395c40be7 Allow NT AUTHORITY\Authenticated Users 001204e1 WMIGUID_QUERY, TRACELOG_CREATE_REALTIME, TRACELOG_CREATE_ONDISK, TRACELOG_GUID_ENABLE, TRACELOG_ACCESS_REALTIME
EtwpCheckNotificationAccess有兩個引數
第一個引數為 上述結構體中的Guids,我們可以通過上面3個GUID中的任意一個進行繞過
第二個引數為LoggerId對應的LoggerContext結構體的InstanceGuid(可以通過對EtwpAcquireLoggerContextByLoggerId函式的逆向得到)

EtwpLoggerContext中默認的GUID
windbg里面可以直觀的看到EtwpLoggerContext里面保存的是個型別為_WMI_LOGGER_CONTEXT的陣列

該結構體_WMI_LOGGER_CONTEXT,的0x124位置保存著InstanceGuid

通過以下命令,我們可以獲取該陣列內的所有InstanceGuid
.for(r $t1=0;$t1<0x40;r $t1=$t1+1;){r $t1 ;dt nt!_GUID poi(poi(poi( nt!PspHostSiloGlobals+360h)+1c8)+($t1*8))+124h)}

這些LoggerId對應的權限雖然有包含0x80權限的,但其所處的組權限較高,因此我們通過控制LoggerId獲取系統自身的InstanceGuid進行繞過可能不太理想

向EtwpLoggerContext注冊GUID
既然EtwpLoggerContext中不存在低權限,且又包含TRACELOG_GUID_ENABLE權限的GUID,那么我們是否可以注冊一個GUID到EtwpLoggerContext中呢?
發現確實可以注冊GUID到EtwpLoggerContext中,該代碼中,我們只需要將SessionGuid和ProviderGuid改為我們自己的GUID即可

注冊GUID的部分代碼如下,其中SessionHandle即為LoggerID

通過上述描述,我們可以通過注冊一個GUID到EtwpLoggerContext陣列中,然后通過該GUID的索引,構造ETW_UPDATE_PERIODIC_CAPTURE_STATE結構體,并前后發送三次請求即可造成BSOD

Exploit開發
占位TimerContextInfo物件
在POC開發中已經得知是第二次呼叫NtTraceControl之后,TimerContextInfo物件被釋放,因此我們要在第二次呼叫之后進行占位,其大小為0x30位元組(不包含Pool Header),型別為NonPagedPoolNx,通過對TimerContextInfo的逆向,該結構體大概如下

通過逆向在IopVerifierExAllocatePoolWithQuota的呼叫中會申請型別為NonPagedPoolNx的Pool,其上層呼叫如NtSetInformationFile、NtSetEaFile等函式都可以實作控制申請pool的大小,并寫入內容,但是卻存在一個問題,就是這類poolTag為IO的池,都會在IO結束時被釋放,雖然被釋放了,但是當前內核池的內容并沒有立即被占用,內容還在,因此利用的成功率并不是百分之百,

本次占位筆者用的是NtSetEaFile函式,該函式內部檢測DEVICE_OBJECT的Flags是否包含4(DO_BUFFERED_IO),因此第一個引數的句柄我給的是PEAuth的檔案句柄,該devobj的Flags為0x44,

偽造Fake_WorkItem
NtSetEaFile函式內部,會通過其第三個引數為pbuffer(Fake_WorkItem)、其第四個函式申請指定的大小的pool,該函式將把會pbuffer的內容放到新申請的內核的地址空間,
只要占位成功,通過控制WorkItem.WorkerRoutine為我們的處理函式,WorkItem.Parameter為引數,即有可能實作對任意地址的破壞或者是讀寫,通常我們將這類處理函式稱之為Gadget,之前有用過SeSetAccessStateGenericMapping,該函式有2個引數,本次需要有一個引數的函式RtlSetAllBits,其引數為PRTL_BITMAP型別,該函式內部我們可以看到,可以通過控制BitMapHeader->SizeOfBitMap大小,實作對BitMapHeader->Buffer進行0xff的填充的大小

因此Fake_WorkItem需要滿足以下3個條件,(通過控制pbuffer即可)
? FakeContextInfo->WorkItem.List.Flink = 0(這樣當前的 WorkItem 將被驗證,并放到佇列)
? FakeContextInfo->WorkItem.WorkerRoutine = RtlSetAllBits()
?FakeContextInfo->WorkItem.Parameter = RTL_BITMAP FakeBitMapHeader

偽造Fake_RtlBitMapAddr
參考附錄4,我們可以通過TheadName,來泄露其內核地址空間,通過呼叫RtlSetAllBits函式可以實作對Fake_RtlBitMapAddr中BitMapHeader->Buffer實作0xff的設定,設定的大小為0x16個位元組,我們可以通過設定token的0x40位置的Privileges,給自身行程添加SE_DEBUG_PRIVILEGE權限,
因此構造的Fake_RtlBitMapAddr需要滿足以下兩個條件
? BitMapHeader->SizeOfBitMap==0x80(可以設定0x16個位元組的0xff)
? BitMapHeader->Buffer==token.Privileges

提權
通過Fake_WorkItem,可以成功的呼叫到RtlSetAllBits函式,又通過Fake_RtlBitMapAddr成功的將token.Privileges.Present以及Enabled都設定為了0xffffffffffffffff

因為有了SE_DEBUG_PRIVILEGE 權限,剩下就是是注入winlogo.exe行程即可,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/330109.html
標籤:其他
下一篇:上傳檔案的漏洞復現與修復
