在 Hyper-V 的虛擬網(wǎng)絡(luò)交換機驅(qū)動程序 ( vmswitch.sys ) 中發(fā)現(xiàn)了一個嚴重漏洞。
該漏洞是使用我們命名為hAFL1的Fuzzer發(fā)現(xiàn)的,我們將其開源出來了(https://github.com/SB-GC-Labs/hAFL1) 。
hAFL1 是 kAFL 的修改版本,可以對 Hyper-V 半虛擬化設(shè)備進行模糊測試,并增加了結(jié)構(gòu)感知、詳細的崩潰監(jiān)控和覆蓋率指導(dǎo)。
Hyper-V 是Azure (微軟的公有云)的底層虛擬化技術(shù)。
該漏洞允許遠程代碼執(zhí)行(RCE) 和拒絕服務(wù)(DoS)。利用它,攻擊者可以使用 Azure 虛擬機控制整個公有云平臺,并在 Hyper-V 主機上運行任意代碼。
該漏洞首次出現(xiàn)在2019 年 8 月的vmswitch版本中,該漏洞可能已經(jīng)存在一年多。
2021 年 5 月,微軟為漏洞CVE-2021-28476分配了9.9 的 CVSS 評分,并為其發(fā)布了補丁。
0x02 vmswitch.sys
為什么目標是 Hyper-V?越來越多的公司正在將其工作負載的主要部分遷移到公有云,例如 AWS、GCP 和 Azure。公有云為用戶提供了靈活性,讓他們無需管理自己的裸機服務(wù)器。然而,這些云本質(zhì)上基于共享基礎(chǔ)架構(gòu)——共享存儲、網(wǎng)絡(luò)和 CPU 能力。這意味著管理程序中的任何漏洞都會產(chǎn)生更廣泛的影響;它不僅會影響一臺虛擬機,而且可能會影響其中的許多虛擬機。
Hyper-V 是 Azure 的底層虛擬化技術(shù),我們決定以它的虛擬交換機 ( vmswitch.sys ) 為目標,因為它是云功能的核心關(guān)鍵組件。
為什么選擇模糊測試?在開發(fā)模糊測試工具和靜態(tài)分析 Hyper-V 的網(wǎng)絡(luò)驅(qū)動程序vmswitch.sys 之間,我們選擇了第一個。原因很簡單——代碼規(guī)模。手動審計挖掘漏洞很枯燥乏味,我們希望一個好的 fuzzer 能夠找到不止一個Crashs。
在 Hyper-V 術(shù)語中,主機操作系統(tǒng)在Root Partition 中運行,客戶操作系統(tǒng)在Child Partition 中運行。為了向子分區(qū)提供與硬件設(shè)備的接口,Hyper-V 廣泛使用了半虛擬化設(shè)備。通過半虛擬化,VM 和主機都使用修改后的硬件接口,從而帶來更好的性能。一種這樣半虛擬化設(shè)備是網(wǎng)絡(luò)交換機,這是我們的研究目標。
Hyper-V 中的每個半虛擬化設(shè)備都包含兩個組件:
1、在子分區(qū)中運行的虛擬化服務(wù)使用者 ( VSC )。netvsc.sys是網(wǎng)絡(luò) VSC。
2、在根分區(qū)中運行的虛擬化設(shè)備提供程序 ( VSP )。vmswitch.sys是網(wǎng)絡(luò) VSP。
這兩個組件通過 VMBus(一種基于超級調(diào)用的分區(qū)內(nèi)通信協(xié)議)相互通信。VMBus 使用兩個環(huán)形緩沖區(qū)——一個發(fā)送緩沖區(qū)和一個接收緩沖區(qū)來在客戶和主機之間傳輸數(shù)據(jù)。
Hyper-V 中的半虛擬化網(wǎng)絡(luò)由 netvsc(使用者)和 vmswitch(提供者)組成。
Fuzzing 是一種自動化軟件測試技術(shù),涉及提供無效或隨機數(shù)據(jù)作為計算機程序的輸入。fuzzer 生成輸入,將它們發(fā)送到其目標并監(jiān)控目標上的崩潰或意外行為。模糊測試的核心組件是harness,它負責(zé)將輸入直接發(fā)送到目標。harness與目標緊耦合;它必須通過目標通常使用的通信通道發(fā)送輸入。為了使模糊測試過程高效,現(xiàn)代Fuzzer實現(xiàn)了幾個附加功能。第一個是覆蓋指導(dǎo)——能夠準確跟蹤執(zhí)行了哪些代碼流并相應(yīng)地改變新輸入,目的是增加目標程序中訪問的代碼量。另一個重要功能是崩潰監(jiān)控——獲取有關(guān)模糊測試過程中發(fā)生的任何崩潰的詳細信息的能力。此類信息可以是堆棧跟蹤或觸發(fā)崩潰的代碼行。最后是結(jié)構(gòu)意識; fuzzer 生成符合特定結(jié)構(gòu)(例如網(wǎng)絡(luò)協(xié)議、文件格式等)的輸入,而不是發(fā)送完全任意的輸入。這增加了通過基本驗證在早期階段處理輸入而不是丟棄輸入的機會。我們使用 fuzzing infrastructure 來指代包含上述組件以執(zhí)行模糊測試過程的任何軟件項目。
0x03 harness
我們的目標是擁有一個能夠向vmswitch發(fā)送輸入的模糊測試基礎(chǔ)框架。此外,希望我們的 fuzzer 是可以實現(xiàn)覆蓋引導(dǎo),并提供詳細的崩潰報告,準確指出發(fā)生崩潰的原因。最后,結(jié)構(gòu)意識對我們來說也很重要,以vmswitch接受的格式發(fā)送輸入,而不是使用任意輸入浪費時間和資源。
開發(fā)Fuzzer的第一階段是設(shè)計harness。我們從MSRC 博客文章中汲取靈感,該文章詳細介紹了 VPCI(Hyper-V 的半虛擬化 PCI 總線)的模糊測試。由于這個目標與我們的相似,我們開始使用相同的步驟。
https://msrc-blog.microsoft.com/2019/01/28/fuzzing-para-virtualized-devices-in-hyper-v/
Microsoft 帖子中提出的想法很簡單——找到 VSC 使用的 VMBus 通道,并使用此通道使用已知的、記錄在案的 API 將數(shù)據(jù)發(fā)送到 VSP 。我們的目標是將這些步驟應(yīng)用于我們的目標:查找netvsc使用的VMBus通道,并使用此通道使用VmbPacketAllocate和VmbPacketSend將數(shù)據(jù)發(fā)送到vmswitch。
1.查找 VMBus 通道
netvsc是在 Hyper-V 子分區(qū)的客戶操作系統(tǒng)中運行的NDIS驅(qū)動程序,并公開虛擬化網(wǎng)絡(luò)適配器。作為虛擬適配器初始化過程的一部分,netvsc分配了一個名為MiniportAdapterContext 的結(jié)構(gòu)(這是作為函數(shù)NvscMicroportInit 的一部分發(fā)生的)。MiniportAdapterContext 的偏移量 0x18是我們的 VMBus Channel指針。
作為 netvsc 中初始化過程的一部分,VMBus Channel指針被寫入 MiniportAdapterContext 結(jié)構(gòu)。
有了這些新知識,我們編寫了一個在子分區(qū)上運行的專用驅(qū)動程序 ( harness.sys )。它遍歷所有 NDIS 微型端口適配器,找到我們想要模糊測試的適配器(通過對其名稱進行字符串匹配)并從適配器上下文結(jié)構(gòu)中獲取 VMBus Channel指針。有了netvsc使用的 VMBus 通道,驅(qū)動程序就會允許我們向vmswitch發(fā)送數(shù)據(jù)。
通過ndis.sys驅(qū)動尋找VMBus通道的過程
2.vmswitch
Hyper-V 中的每個 VSP 都必須實現(xiàn)和注冊數(shù)據(jù)包處理回調(diào)EvtVmbChannelProcessPacket。每當新數(shù)據(jù)包到達 VSP 時,都會調(diào)用此函數(shù)。在vmswitch 中,這個回調(diào)函數(shù)是VmsVmNicPvtKmclProcessPacket 。
vmswitch需要NVSP類型的數(shù)據(jù)包,這是一種用于通過 Hyper-V 的 VMBus 傳輸?shù)臄?shù)據(jù)包的專有格式。有許多 NVSP 數(shù)據(jù)包類型;有些負責(zé)設(shè)置VMBus 的發(fā)送和接收緩沖區(qū),有些負責(zé)執(zhí)行VSP 和VSC 之間的握手(例如交換NDIS 和NVSP 版本),有些用于在客戶和主機之間發(fā)送RNDIS 消息。
RNDIS通過抽象控制和數(shù)據(jù)通道定義了主機和遠程 NDIS 設(shè)備之間的消息協(xié)議。在 Hyper-V 設(shè)置中,“host”是客戶 VM,“RNDIS 設(shè)備”是vmswitch或外部網(wǎng)絡(luò)適配器,“抽象通信通道”是 VMBus。
我們決定將我們的模糊測試工作集中在處理 RNDIS 消息的代碼流上,原因有兩個:
1、有很多代碼處理 RNDIS 消息。
2、在vmswitch中發(fā)現(xiàn)的相當多的漏洞都在 RNDIS 數(shù)據(jù)包處理中。
處理 RNDIS 消息的函數(shù)是VmsVmNicPvtVersion1HandleRndisSendMessage ,它直接會從VmsVmNicPvtKmclProcessPacket 調(diào)用。
要使用 RNDIS 消息Fuzzing vmswitch,我們必須調(diào)用這些函數(shù)并將 RNDIS 消息傳遞給它。
3.發(fā)送 RNDIS 消息
void VmsVmNicPvtKmclProcessPacket
( VMBCHANNEL Channel,
VMBPACKETCOMPLETION Packet,
PVOID Buffer,
UINT32 BufferLength,
UINT32 Flags
)
{...}
VmsVmNicPvtKmclProcessPacket接受五個參數(shù):VMBus Channel 指針、數(shù)據(jù)包對象、緩沖區(qū)及其長度以及flags。buffer 參數(shù)用于將數(shù)據(jù)包元數(shù)據(jù)發(fā)送到vmswitch。它由4個字段組成:
1、msg_type – NVSP 消息類型
2、channel_type – 0 表示數(shù)據(jù),1 表示控制
3、send_buf_p_index – 寫入數(shù)據(jù)的發(fā)送緩沖區(qū)部分的索引?;叵胍幌拢琕MBus 通過兩個環(huán)形緩沖區(qū)傳輸數(shù)據(jù);此字段指定數(shù)據(jù)的確切位置
4、send_buf_p_size – 發(fā)送緩沖區(qū)中數(shù)據(jù)的大小
數(shù)據(jù)包處理回調(diào)的 Buffer 參數(shù)中的不同字段
起初,必須通過 VMBus 向緩沖區(qū)發(fā)送數(shù)據(jù)。但是經(jīng)過一段時間的研究,我們找到了另一種發(fā)送 RNDIS 消息的方法,不涉及 VMBus 向緩沖區(qū)發(fā)送數(shù)據(jù)??梢苑峙鋬?nèi)存,將數(shù)據(jù)復(fù)制到其中,然后創(chuàng)建指向已分配緩沖區(qū)的內(nèi)存描述符列表(或MDL)。發(fā)現(xiàn)這種方式對我們來說更方便,因為它使我們無需將 RNDIS 消息復(fù)制到發(fā)送緩沖區(qū)。
要使用 MDL 發(fā)送 RNDIS 消息,上面的緩沖區(qū)指定以下值:
●msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT
●channel_type= 1
●send_buf_p_index = -1(表示使用MDL)
●send_buf_p_size = 0(使用 MDL 時忽略此參數(shù))
MDL 本身附加到數(shù)據(jù)包對象。
此時,不僅能夠向vmswitch發(fā)送任意輸入,而且確切地知道要發(fā)送哪些數(shù)據(jù)包以及如何發(fā)送它們,以便執(zhí)行 RNDIS 代碼流。有了這一功能,我們的harness可以觸發(fā)vmswitch的n day漏洞 :CVE-2019-0717。
0x04 Harness 與 Fuzzer 連接
該過程的下一步是將我們的工具集成到一個模糊測框架中,不需要完全自己實現(xiàn)——編寫超級調(diào)用、設(shè)計突變引擎、解碼覆蓋跟蹤等。有幾個選項可用,但我們選擇了kAFL 似乎最適合我們的需求——Fuzzing內(nèi)核模式驅(qū)動程序。
我們的Fuzzer有三個級別的虛擬化(用“LN”表示級別 N)。L0 – 裸機服務(wù)器 – 將在 Linux 的內(nèi)置管理程序 KVM 上運行 kAFL。然后將創(chuàng)建我們的 Hyper-V 主機 (L1)——一個運行 Windows 10 且啟用了 Hyper-V 的虛擬機。在我們的 Hyper-V 主機之上,將運行兩臺機器 (L2):root分區(qū),vmswitch將在其中執(zhí)行,以及一個子分區(qū),我們將從中運行我們的harness和Fuzzing vmswitch。
hAFL1 設(shè)置 -:vmswitch 在root分區(qū)(L2)內(nèi)運行,harness在子分區(qū)(L2)內(nèi)運行。
問題是kAFL 不支持嵌套虛擬化,而我們的設(shè)置是基于嵌套虛擬化的——我們在 KVM 之上的 Hyper-V 主機之上有一個客戶操作系統(tǒng)。通過這樣的設(shè)置,kAFL 無法直接與在 L2 中運行的組件進行通信。更準確地說,這意味著vmswitch缺乏覆蓋信息,并且無法將fuzz有效載荷(輸入)從 kAFL 發(fā)送到我們的harness。
因此,為了適應(yīng) kAFL,我們必須重新設(shè)置。如果我們不能從 L2 fuzz,那我們就試試能不能從 L1 fuzz 。實際上,這意味著必須找到一種方法來從 L1 內(nèi)而不是從root分區(qū)內(nèi)運行vmswitch。然后,我們只需從與vmswitch相同的虛擬化級別運行我們的工具。
幸運的是,我們找到了一個巧妙的解決方法。事實證明,當啟用 Hyper-V 功能并禁用 Intel VTx 時,Windows 以回退模式啟動,其中 Hyper-V 無法運行,但vmswitch仍會加載到內(nèi)核內(nèi)存中!但是,不存在root和子分區(qū),因為 Hyper-V 不運行,所以我們只剩下 L1。這正是我們想要的,現(xiàn)在可以在單個Windows VM 上運行工具并調(diào)用我們的目標函數(shù)VmsVmNicPvtVersion1HandleRndisSendMessage 。
遇到的下一個問題是缺少 VMBus 通道。完全運行時,vmswitch使用 VMBus 通道與其使用者(netvsc實例)進行通信。但是由于 Hyper-V 處于非活動狀態(tài),并且沒有正在運行的 VM,因此vmswitch沒有這樣的 VMBus 通道可供使用。我們需要找到一種方法來為vmswitch提供一個 VMBus 通道,或者讓它自己初始化一個。
經(jīng)過一段時間的逆向,我們在vmswitch 中發(fā)現(xiàn)了一個名為VmsVmNicMorph的特殊函數(shù),它完全可以做到這一點——它為vmswitch初始化一個新的 VMBus 通道。然而,簡單地調(diào)用這個函數(shù)會導(dǎo)致藍屏,因為它試圖調(diào)用與 VMBus 相關(guān)的函數(shù),而 VMBus 并沒有運行。我們決定patch所有 VMBus 邏輯。因為 VMBus 是一個獨立的通信層,不會干擾正在發(fā)送的數(shù)據(jù)。你可以把它想象成 OSI 網(wǎng)絡(luò)層模型:VMBus 是傳輸層,獨立于vmswitch,應(yīng)用層。也就是說,我們可以放棄執(zhí)行 VMBus 邏輯,而仍然為vmswitch接收適當?shù)?VMBus 通道對象使用。
還有一個問題需要解決。一個名為PatchGuard的 Windows 功能阻止了對簽名內(nèi)核模式代碼的更改。所以如果我們想修改vmswitch 中的指令,必須禁用 PatchGuard。為此,我們使用了一個名為EfiGuard的開源工具,它為我們提供了相關(guān)功能:它禁用了內(nèi)核補丁保護和驅(qū)動程序強制簽名,允許我們在機器上運行我們未簽名的harness驅(qū)動程序。
https://github.com/Mattiwatti/EfiGuard
我們在構(gòu)建 hAFL1 過程中的問題和解決方案
當前的設(shè)置與我們最初設(shè)想的完全不同。vmswitch直接在 Windows 10 主機上運行(而不是在root分區(qū)內(nèi)),我們的harness驅(qū)動程序 ( harness.sys ) 運行在同一級別而不是在子分區(qū)內(nèi)。用戶模式harness進程通過超級調(diào)用從 kAFL 接收fuzz有效載荷,并使用 IOCTL 將它們傳遞給我們的harness驅(qū)動程序。回顧一下——Hyper-V 無法使用,因為 VT-x 被禁用了。但是我們的fuzzer運行了,將模糊測試輸入發(fā)送到vmswitch并獲取覆蓋信息以推動fuzzing過程向前發(fā)展。
hAFL1 設(shè)置 :vmswitch 在 L1 內(nèi)運行,我們的harness也在L1中運行。
0x05 Fuzzing改進
下面是我們對Fuzzer框架中加入的更多邏輯和功能。
1.覆蓋引導(dǎo)
kAFL 利用Intel-PT在整個模糊測試迭代中跟蹤指令指針的值,并改變輸入以增加它命中的基本塊的數(shù)量。為了僅從某個進程的上下文harness)中跟蹤執(zhí)行,kAFL 使用CR3 過濾,只有當 CR3 寄存器值與 CR3 過濾器值匹配時,它才會記錄執(zhí)行跟蹤。
https://software.intel.com/content/www/us/en/develop/blogs/processor-tracing.htmlhttps://software.intel.com/content/www/us/en/develop/documentation/debug-extensions-windbg-pt-user-guide/top/commands/commands-for-configuration/ip-filter-configuration.html
但是訪問基本塊的數(shù)量太少,即使是單個數(shù)據(jù)包也應(yīng)該通過比Fuzzer UI 顯示的更多的基本塊進行傳播。
分析發(fā)現(xiàn),vmswitch以異步、多線程的方式處理數(shù)據(jù)包。數(shù)據(jù)包首先經(jīng)過短暫的同步處理,然后作為工作項推送到隊列中,等待由專用系統(tǒng)工作線程處理。顯然,該線程與我們的harness具有不同的 CR3 值。這就是為什么 fuzzer 在它源自工作線程時根本不跟蹤執(zhí)行。為了克服這個問題,我們禁用了 CR3 過濾。這不會污染跟蹤結(jié)果,因為只有我們在vmswitch 中觸發(fā)了代碼。
https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/system-worker-threads
最后,為了監(jiān)控vmswitch的覆蓋率,我們編寫了一個 Python腳本將 Intel-PT 數(shù)據(jù)從 kAFL 格式轉(zhuǎn)換為 IDA 的Lighthouse插件格式。
https://github.com/SB-GC-Labs/hAFL1/blob/main/tools/convert_kAFL_coverage_to_lighthouse.pyhttps://github.com/gaasedelen/lighthouse
vmswitch 覆蓋率使用 IDA 的 Lighthouse 插件實現(xiàn)可視化
2.Crashs監(jiān)控
為了能夠有效地監(jiān)控分析崩潰,F(xiàn)uzzer有必要生成詳細的崩潰報告。但是,kAFL 沒有提供很多 Windows 目標中的崩潰信息。例如,它不會輸出觸發(fā)崩潰的目標代碼中的堆棧跟蹤或確切偏移量,我們需要自己實現(xiàn)這個邏輯。
我們使用了 Xen 代碼庫的一部分來獲取堆棧跟蹤和模塊信息。然后,編寫了兩個 KVM 超級調(diào)用,將這些信息從 L1 發(fā)送回 kAFL。最后,我們實現(xiàn)并注冊了一個特殊的 BugCheck 回調(diào)來調(diào)用這些 KVM 超級調(diào)用。
有了這些條件,我們能夠獲得有關(guān)vmswitch 中發(fā)生的每次崩潰的詳細信息——一個完整的堆棧跟蹤,包含函數(shù)名稱和偏移量,如下截圖所示。
來自 hAFL1 的詳細崩潰報告,顯示了堆棧跟蹤、函數(shù)名稱和其中的偏移量。
3.結(jié)構(gòu)意識
為了更快地進行模糊測試,我們希望Fuzzer生成與目標期望的格式相匹配的輸入。在我們的例子中,這些輸入是 RNDIS 消息。
我們使用協(xié)議緩沖區(qū)定義了 RNDIS 消息,并使用libprotobuf-mutator 對它們進行了變異。為了將我們自定義的、基于協(xié)議緩沖區(qū)的變異策略集成到 kAFL 中,必須創(chuàng)建一個新狀態(tài)并將其添加到 kAFL 的狀態(tài)機中,這是一個管道。任何fuzz有效載荷都通過此管道由 kAFL 的內(nèi)置變異器進行變異。
https://developers.google.com/protocol-buffershttps://github.com/google/libprotobuf-mutatorhttps://github.com/SB-GC-Labs/hAFL1/blob/main/README.md
0x06 漏洞挖掘
在 hAFL1 運行兩個小時后,發(fā)現(xiàn)了一個關(guān)鍵的 CVSS 9.9 的 RCE 漏洞。
hAFL1 圖形用戶界面,接口與 kAFL 相同,但可以通過添加新的基于協(xié)議緩沖區(qū)的變異策略進行擴展。
https://github.com/SB-GC-Labs/hAFL1
該漏洞存在于vmswitch.sys ——Hyper-V 的網(wǎng)絡(luò)交換機驅(qū)動程序中。它是通過從訪客虛擬機向 Hyper-V 主機發(fā)送特制數(shù)據(jù)包來觸發(fā)的,可被利用以實現(xiàn) DoS 和 RCE。
該漏洞首次出現(xiàn)在 2019 年 8 月的版本中,表明該漏洞已在生產(chǎn)環(huán)境中存在了一年半以上。它影響了 Windows 7、8.1 和 10 以及 Windows Server 2008、2012、2016 和 2019。
Hyper-V 是 Azure 的管理程序;因此,Hyper-V 中的漏洞會導(dǎo)致 Azure 中的漏洞,并可能影響公有云的整個區(qū)域。從 Azure VM 觸發(fā)拒絕服務(wù)將使 Azure 基礎(chǔ)架構(gòu)的主要部分崩潰,并關(guān)閉共享同一主機的所有虛擬機。
通過更復(fù)雜的利用鏈,該漏洞可以授予攻擊者遠程代碼執(zhí)行能力,通過控制主機和在其上運行的所有虛擬機,攻擊者可以訪問存儲在這些機器上的個人信息,運行惡意軟件等。
0x07 背景知識
1.vmswitch
在 Hyper-V 術(shù)語中,主機操作系統(tǒng)在“root分區(qū)”中運行,而客戶操作系統(tǒng)在“子分區(qū)”中運行。為了向子分區(qū)提供與硬件設(shè)備的接口,Hyper-V 廣泛使用了半虛擬化設(shè)備。通過半虛擬化,VM 知道它是虛擬的;VM 和主機都使用修改后的硬件接口,從而帶來更好的性能。一種這樣的半虛擬化設(shè)備是網(wǎng)絡(luò)交換機,這是我們的研究目標。
每個半虛擬化設(shè)備由兩個組件組成:
1、在子分區(qū)中運行的虛擬化服務(wù)使用者 (VSC)。netvsc.sys是網(wǎng)絡(luò) VSC。
2、在根分區(qū)中運行的虛擬化設(shè)備提供程序 (VSP)。vmswitch.sys是網(wǎng)絡(luò) VSP。
這兩個組件通過 VMBus(一種基于超級調(diào)用的分區(qū)內(nèi)通信協(xié)議)相互通信。
VSC 和 VSP 分別運行在根分區(qū)(Hyper-V 主機)和客戶分區(qū)(客戶 VM)上。
2.通訊協(xié)議
netvsc(網(wǎng)絡(luò)使用者)使用NVSP類型的數(shù)據(jù)包通過 VMBus與vmswitch(提供者)通信。這些數(shù)據(jù)包有多種用途:初始化和建立兩個組件之間的 VMBus 通道、配置各種通信參數(shù)以及將數(shù)據(jù)發(fā)送到 Hyper-V 主機或其他 VM。NVSP 包括許多不同的數(shù)據(jù)包類型;其中之一是用于發(fā)送 RNDIS 數(shù)據(jù)包的NVSP_MSG1_TYPE_SEND_RNDIS_PKT 。
3.RNDIS 和 OID
RNDIS通過抽象控制和數(shù)據(jù)通道定義了主機和遠程 NDIS 設(shè)備之間的消息協(xié)議。在 Hyper-V 設(shè)置中,“主機”是客戶 VM,“遠程 NDIS 設(shè)備”是 vmswitch 或外部網(wǎng)絡(luò)適配器,“抽象通信通道”是 VMBus。
RNDIS 也有各種消息類型——init、set、query、reset、halt等。當 VM 希望設(shè)置或查詢其網(wǎng)絡(luò)適配器的某些參數(shù)時,它會向vmswitch發(fā)送OID 請求——帶有相關(guān)對象的消息標識符(OID) 及其參數(shù)。此類 OID 的兩個示例是用于設(shè)置適配器 MAC 地址的OID_GEN_MAC_ADDRESS和用于設(shè)置適配器當前多播地址列表的OID_802_3_MULTICAST_LIST 。
RNDIS 設(shè)置消息結(jié)構(gòu),來自 RNDIS 規(guī)范。OID 是數(shù)據(jù)包的必填字段之一。
4.虛擬交換擴展
vmswitch,Hyper-V 的虛擬交換機,也被稱為“Hyper-V 可擴展交換機”。它的擴展是 NDIS 過濾器驅(qū)動程序或 Windows 過濾平臺 (WFP) 驅(qū)動程序,它們在交換機內(nèi)部運行,可以捕獲、過濾或轉(zhuǎn)發(fā)處理的數(shù)據(jù)包。Hyper-V 可擴展交換機具有 OID 請求的控制路徑,如下圖所示:
Hyper-V 可擴展交換機擴展作為交換機控制路徑的一部分
0x08 漏洞分析
1.臭名昭著的 OID
一些 OID 請求發(fā)往外部網(wǎng)絡(luò)適配器,或連接到vmswitch 的其他網(wǎng)絡(luò)適配器。此類 OID 請求包括例如硬件卸載、互聯(lián)網(wǎng)協(xié)議安全 (IPsec) 和單root I/O 虛擬化 (SR-IOV) 請求。
當這些請求到達vmswitch接口時,它們被封裝并使用OID_SWITCH_NIC_REQUEST類型的特殊 OID 沿可擴展交換機控制路徑向下轉(zhuǎn)發(fā)。新的 OID 請求形成為NDIS_SWITCH_NIC_OID_REQUEST結(jié)構(gòu),其成員OidRequest指向原始 OID 請求。生成的消息通過vmswitch控制路徑,直到到達其目標驅(qū)動程序。流程如下圖所示。
Hyper-V 可擴展交換機控制路徑中的 OID 請求封裝。
Microsoft 記錄的 NDIS_SWITCH_NIC_OID_REQUEST 結(jié)構(gòu)
2.漏洞代碼
在處理 OID 請求時,vmswitch 會跟蹤其內(nèi)容以進行日志記錄和調(diào)試;這也適用于OID_SWITCH_NIC_REQUEST 。但是,由于其封裝結(jié)構(gòu),vmswitch需要對此請求進行特殊處理,并取消引用 OidRequest以跟蹤內(nèi)部請求。該缺陷是,vmswitch從未驗證的值OidRequest,并因此取消引用無效指針。
以下步驟導(dǎo)致 vmswitch 中的漏洞函數(shù):
1、消息首先由 RndisDevHostControlMessageWorkerRoutine 處理——一個通用的 RNDIS 消息處理函數(shù)。
2、vmswitch識別設(shè)置請求并將消息傳遞給更具體的處理程序 - RndisDevHostHandleSetMessage。
3、稍后,消息被傳遞到 VmsIfrInfoParamsNdisOidRequestBuffer。該函數(shù)負責(zé)使用IFR (跟蹤記錄器)跟蹤消息參數(shù),這是一種 Windows 跟蹤功能,可以實時記錄二進制消息。
4、最后,數(shù)據(jù)包到達 VmsIfrInfoParams_OID_SWITCH_NIC_REQUEST,它專門跟蹤 OID_SWITCH_NIC_REQUEST 類型的請求及其各自的結(jié)構(gòu) NDIS_SWITCH_NIC_OID_REQUEST。
導(dǎo)致bug的函數(shù)調(diào)用鏈,處理特定 OID 的 RNDIS 請求消息的跟蹤。
3.實現(xiàn)利用
netvsc,網(wǎng)絡(luò)虛擬服務(wù)消費者 (vsc) 。不發(fā)送帶有OID_SWITCH_NIC_REQUEST 的OID 請求。盡管如此,設(shè)計缺陷會導(dǎo)致vmswitch接受并處理此類請求,即使它來自客戶 VM。這允許我們通過直接從客戶 VM發(fā)送帶有OID_SWITCH_NIC_REQUEST 的 RNDIS設(shè)置消息來觸發(fā)跟蹤機制中的任意指針取消引用漏洞。
這種漏洞可以作為兩種利用場景的基礎(chǔ)。如果OidRequest成員包含無效指針,Hyper-V 主機將直接崩潰。另一種選擇是使主機的內(nèi)核從內(nèi)存映射設(shè)備寄存器中讀取,進一步實現(xiàn)代碼執(zhí)行。Hyper-V 主機上的 RCE 將使攻擊者能夠隨心所欲讀取敏感信息、以高權(quán)限運行惡意負載等。
0x09 研究總結(jié)
該漏洞是由于虛擬機管理程序任意指針取消引用與設(shè)計缺陷造成的,該缺陷允許客戶和主機之間的通信通道過于寬松。
CVE-2021-28476 等漏洞證明了共享資源模型(例如公有云)帶來的風(fēng)險。事實上,在共享基礎(chǔ)設(shè)施的情況下,即使是簡單的錯誤也可能導(dǎo)致毀滅性的結(jié)果,如拒絕服務(wù)和遠程代碼執(zhí)行。
軟件中的漏洞是不可避免的,這句話也適用于公有云基礎(chǔ)設(shè)施。這加強了混合云戰(zhàn)略的重要性,該戰(zhàn)略不會將所有雞蛋放在一個籃子里或一個區(qū)域中的所有實例上。這種方法將有助于迅速從 DoS 攻擊中恢復(fù),適當?shù)姆侄螌⒎乐乖谀承C器被攻破后集群被控制。
參考及來源:https://www.guardicore.com/labs/hafl1-our-journey-of-fuzzing-hyper-v-and-discovering-a-critical-0-day/及https://www.guardicore.com/labs/critical-vulnerability-in-hyper-v-allowed-attackers-to-exploit-azure