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