作者:yyjb@360高級攻防實驗室
原文鏈接:http://noahblog.#/untitled-2/

背景

2021年8月份有兩個較嚴重的漏洞需要關注,其中包括NFS ONCRPC XDR Driver 遠程代碼執行漏洞CVE-2021-26432以及RDP客戶端遠程代碼執行漏洞CVE-2021-34535。

我們的目標是分析這些潛在影響可能較大的漏洞是否容易在實際的場景中被利用。這里,我們分析NFSXDR漏洞CVE-2021-26432。

NFSXDR驅動服務簡介

img

補丁分析

分析補丁我們能比較容易確定漏洞修補的位置。

img

其中一處修改的地方是在函數OncRpcMsgpDecodeRpcCallVerifier中增加對參數的判斷,

img

另一個則是在OncRpcBufMgrpAllocateDescriptorFromLLLargePoolAllocation函數中申請內存后,立即初始化該內存。

img

構造poc

直觀上來判斷,RCE的cve更可能和第一個判斷有關,這里我們通過追蹤補丁的判斷參數a1+296這個值的所有引用,最后在下面的函數中,找到了和它有關的另一個判斷位置。

img

我們這里可以猜測這是一個計算消息頭長度的函數,滿足漏洞觸發條件之一,需要這個長度固定為36。再查閱相關資料,我們能知道其余漏洞的觸發條件是如果我們選擇了RPC了驗證方式為6(RPCSEC_GSS),則RPC中Credentials中的Flavor為1即AUTH_UNIX(而補丁修補后Credentials中的Flavor只能是為6)。然后我們根據協議文檔嘗試構造數據包,通過后續的分析對比可以明確上面的固定長度對應的是GSS_Token中的數據長度。

img

構造GSS_Token中的數據長度大于其在此情況下系統默認固定長度36即可觸發漏洞路徑。

由于對GSS_Token數據長度計算方式判斷錯誤,返回的數據是可能會超過其默認申請的長度,我們可以通過靈活的構造請求包中的GSS_Token數據長度來控制這個漏洞可能會導致的效果:

如果其長度比默認的36長得不是太多(大致0x50左右),返回的數據包中會包含除GSS_Token數據之外其他的結構數據,這是一個可以導致一個信息泄露的效果:其泄露的數據具體來說包含整個對象內存的地址指針。如果我們的GSS_Token數據長度更長,則系統處理這些數據就會溢出掉后面其他所有結構數據直到其他未知內存(超出0x100基本會崩潰)。另外注意GSS_Token數據長度不是無限長度任意構造的,并且由于NFSxdr驅動中對數據接收的一些其他的限制,我們所能構造的溢出長度最長只能大概0x4000左右。

img

利用

目前,我們已經有一個比較穩定的溢出。通常漏洞利用會嘗試溢出一些特定的數據來得到一個指針執行機會。

我們考慮了以下兩種方式:

A,通過溢出控制對象大小為0x900(*XdBD,這是一種NFSXDR為內部申請小于0x800的緩沖區對象)的內部鏈表緩沖區頭,控制下一個緩沖區地址。構造寫原語,一方面這種內部緩存的對象鏈表通常不需要校驗其頭部數據,這樣溢出后會比較穩定。另一方面,通過控制這種內部鏈表結構,我們可以更加精確的控制其中的內存申請釋放時機。

img

img

但一方面,這個單鏈表的長度太短了只有4。這種0x900的對象它的生命周期是隨著RPC命令一起生成和釋放的。一旦我們嘗試風水布局,我們很難確定到這個4個對象的位置。另一方面我們不能通過前面提到的信息泄露的方式去知道這幾個對象的地址。因為目前的信息泄露觸發方式只能是在申請大緩沖區時才能滿足漏洞條件的。而這個0x900的對象屬于較小內存對象。

B,通過溢出控制OncRpcConnMgrpWskReceiveEvent中的OncRpcWiMgrpSrvWorkItemAlloc申請的內存(長度為0xa00的NLM對象),控制其對象中的引用指針。借助一個獨立的信息泄露漏洞(參考本文最后一節),在我們布局的非分頁內存中存放rop鏈來執行代碼。

NFS本身是一個無狀態的通訊協議,他使用了NLM對象來保證協議的中的資源正常訪問讀寫。這里的NLM對象,有一些特性值得我們注意。

img

當多個RPC請求短時間傳到服務端時,服務端會使用OncRpcConnMgrpWskReceiveEvent中這樣的的一個流程去處理這些請求。

img

我打印了一部分我們關注的對象的生命周期。我們的目標是溢出NLM對象頭部保存的OncRpcMsgProcessMessage函數指針。如下圖:

img

該指針會在其釋放前在NFS RPC工作線程中被調用:

img

該對象生命周期如下:

下圖中的W-pool對應NLM對象。我們的目的是在NLM釋放前調用其內部的OncRpcMsgProcessMessage指針時,覆蓋該指針。

img

NFSXRD中,每一種不同的請求類型對應不同的的RPC請求,我們通過調整RPC請求中類型的位置和順序能能夠按照我們預期的時機觸發溢出。,

img

NLM對象釋放前,我們觸發了溢出:

img

具體來說,我們申請一個0x1490的大內存對象(0x1490是我們可控制的申請讀寫數據的長度數據內存),之后使用NLM對象填充這些0x1490剩余的空洞。然后再釋放所有0x1490的內存對象,在此時重新申請0x1490的讀寫請求包,在這其中一個包結構中觸發漏洞。

以期望在所有的NLM對象釋放前,溢出某一個NLM對象中的OncRpcMsgProcessMessage指針。

img

但結果并不能如預期那樣,使漏洞剛好溢出到我們期望的目標上,即使是非常低的概率也沒有。除此之外,我們還嘗試了另一種不同的溢出思路:

第二種方法,大量發出某一種特定的PRC的指定請求(NLM請求),OncRpcConnMgrpWskReceiveEvent處理流程中會大量交替申請0xa00和0x900兩種對象,并且這兩個對象是成對出現的他們會各自占用0x1000的內存并形成一個較穩定的內存結構。當前面循環的RPC請求部分前面的相鄰0xa00,0x900對象釋放時,合并出0x2000的空閑內存。之后在還有剩余RPC請求存在的時候,構造漏洞溢出的內存長度為0x2000溢出其中的一個0xa00 NLM對象的頭部。

總結

但后續根據大量測試,我們并不能控制NLM對象能在我們漏洞觸發時剛好釋放。他有自己的時間計時器,其存在時間總也總是是低于我們的預期。并且另外一個關鍵的地方是,我們所構造的漏洞消息所申請的內存必須大于1K,太小則不能觸發漏洞流程。這時我們也不能使用0x900或者0xa00這樣本身存在的對象來占位。

我們最大的問題就是我們溢出的目標對象很難在我們控制得時機,布局成我們期望的位置(無論是0xa00 RSWI還是0x900 XdBD)。

綜上,如果僅僅限制在最新的win10以上的NFSXDR協議內部,要實現利用似乎并不容易。但考慮到目前已知的在其他協議上的一些研究結果,如果是針對一些例如server2008這樣較老系統上布置的NFSXDR服務。該漏洞是可能比較容易通過一些其他協議的內存布局方式而成功利用的。

新的漏洞

在分析漏洞的補丁差異之初,我們有留意到補丁中對申請大于0x800的小內存時,才增加了一個初始化內存的操作,但當申請較小內存的時候,并沒有對應的補丁代碼。

如下:

img

按照思維慣性,我們在后續的分析中,就會帶著這樣的一個疑問進行后續的分析——當申請較小內存時,是否也會存在同原理的錯誤?

當我們在后續嘗試exp的分析過程中發現,當我們構造數據包中GSSTOKEN數據長度如果不為4的整倍數時,返回的數據中最后幾位字節有時會出現一些不確定的數據,(如下面的示例)

這是調整申請內存構造數據包大小時候偶然發現的(申請較小內存),深入分析后,最終的結果證明了我們之前的猜測。

該協議中對于數據包對齊的邏輯中,在復制數據時,對于非4的整數長度字節數據系統會仍然會自動填補其長度為4的倍數。而其返回的數據,就會有額外的不確定內存。其長度為4-x,x為GSSTOKEN除以4的余數。

然后,這樣的一個錯誤能導致怎樣的結果呢?

為了泄漏更長的數據,我們選擇 x=1。 在下面的例子中,選擇數據長度為 0x23d=0x23c+1;

img

我們可以通過增加4 的字節(或 4 的倍數)來設置讀取請求數據的長度,以改變要泄露的其他感興趣的不同位置的數據。 如下:0x241=0x23d+4。

img

什么這里的示例使用 0x23d 的讀取長度?

這是因為當我們選擇用較小的內存讀取數據時,nfsxdr 默認申請內存的大小為 0x900。 在申請這個大小的內存時,很容易使用其他剛剛釋放的大小相同的對象的內存。 在我們調試的環境win10中,Thread內核對象的大小也恰好是接近0x900。 如果是這樣的話,這里選擇讀取 0x23d 長度的數據很可能對應到Thread 對象中存儲的函數指針地址 0xfffff806 37efe930。 最后我們可以得到0xfffff8XX 37efe9XX這樣的信息。 但是,長度為 8 字節的地址仍有 2 個字節無法確認。

通常來說,這樣的信息泄露在現代windows系統上的作用似乎仍然受到地址隨機化的限制,對于“37efe930“低位的“30”,一般來說有時我們是可能猜測的,但我們不能確認0xfffff806中的“06”。然而在一些過時的windows系統如win7,這樣的信息泄露,足夠取得一個內核指針信息。

img

所以在調用OncRpcBufMgrpAllocateDescriptorFromLLInlineBuffer時這里似乎可能仍然需要初始化其內存。

此錯誤已經在2月份修補為cve-2022-21993。

參考

https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-26432


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1897/