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