深入分析微軟新引入的內核虛擬地址影子(KVAS)特性
前言
目前,針對Meltdown和Spectre,各方仍然在努力修復這兩個漏洞,包括蘋果、甲骨文和微軟在內的大型廠商,已經陸續發布了補丁。英特爾發布的補丁存在一些潛在的問題,可能導致用戶主機的頻繁異常重啟,這些潛在問題從Sandy Bridge架構(2011年)開始就一直存在,直至如今的Kaby Lake(2016年,即第七代酷睿處理器)。
在之前的博客文章( https://blog.fortinet.com/2018/01/17/into-the-implementation-of-spectre )中,我們詳細介紹過Spectre漏洞的原理。此外,我們還在另一篇文章( https://blog.fortinet.com/2018/01/12/dr-strangepatch-or-how-i-learned-to-stop-worrying-about-meltdown-and-spectre-and-love-security-advisory-adv180002 )中,對微軟安全公告ADV180002所涉及的補丁進行了技術分析。該補丁主要引入的一個特性就是內核虛擬地址影子(Kernel Virtual Address Shadow,由微軟提出的一個術語,簡稱KVAS),由於該特性僅允許用戶模式代碼訪問有限的內核內存,因此能有效防範Meltdown攻擊。在本文,我們將對內核虛擬地址影子這一特性進行深入分析。關於Meltdown和Spectre漏洞,請參見: https://spectreattack.com/ 。蘋果發布的通告及補丁,請參見: https://support.apple.com/en-us/HT208394 。甲骨文發布的通告及補丁,請參見: http://www.zdnet.com/article/meltdown-spectre-oracles-critical-patch-update-offers-fixes-against-cpu-attacks/ 。
微軟發布的通告及補丁,請參見: http://www.zdnet.com/article/meltdown-spectre-oracles-critical-patch-update-offers-fixes-against-cpu-attacks/ 。微軟安全公告ADV180002,請參見: https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/ADV180002 。整體設計
在深入挖掘細節之前,我們有必要先對其有一個整體上的認識。下表由美國互聯網應急中心提供,對Spectre和Meltdown的攻擊方式進行了概括:
根據反病毒測試研究團隊對新發現的119個惡意樣本的分析,證實了Meltdown攻擊實現的難度確實較低(主要是成本非常低),因此在漏洞被爆出的兩周之內,極有可能在實際中被大量利用。所以,微軟首先專註於對Meltdown漏洞的修補,是完全合理的。
我們假定讀者已經對操作系統的概念和原理有基本的了解,包括虛擬內存、x86與x64、MSR、內核模式與用戶模式等。如果你對上述的某些概念不太了解,我們建議你首先查閱《英特爾64和IA-32架構軟體開發人員手冊》(Intel? 64 and IA-32 Architectures Software Developer』s Manuals),這是一本權威並且系統的指南,任何新手都可以從這裡起步。下圖是內核虛擬地址影子特性的總體設計思路:從概念上看,該特性分為三部分:入口、中間的任意控制流、出口。這裡的關鍵之處在於,通過巧妙的分頁結構,將內核空間與用戶空間分隔開。在用戶空間和內核空間中,只有少量的頁面會被映射。正因如此,即使攻擊者成功實現了Meltdown攻擊,也無法再進一步泄漏內核內存。入口和出口的swap地址空間會來回交換,使得只有內核代碼才有權訪問內核內存空間。這樣的設計還有一個好處,以後就可以僅對分頁結構進行操作,不必再依靠任何硬體級別上提供的額外支持(例如:微代碼更新)來實現。
如下圖所示,NtOpenProcess的代碼區域不可訪問,因為它沒有使用UserDirectoryTableBase進行映射。
詳細分析
在這裡,重點介紹我們對內核虛擬地址影子(KVAS)分析過程中的主要發現。以下是NT內核自身的關鍵細節:
Windows 7 x64系統版本號:6.1.7601.24000大小:5581544位元組Sha256:9A6C19B29EBB8D9399C771F2B570E6DCDDF75AC7F2A5F4E8013F4EC7A31F7CA8我們發現,KVAS在啟動(Boot)過程中就被初始化,會在操作系統初始化過程中被啟用。NT內核的入口點稱為KiSystemStartup,由操作系統載入器(OS Loader)調用。KiSystemStartup依次執行一些基礎的初始化步驟,其中的一個步驟就是調用KilnitializeBootStructures。KiInitializeBootStructures將會調用KiEnableKvaShadowing。KiEnableKvaShadowing的功能是負責啟用KVAS,並設置KiKvaShadow = 1。
我們還觀察到,基於進程上下文的標識符(即PCID,用於性能優化,以避免刷新整個轉換檢測緩衝區TLB,也就是俗稱的快表)中,全局標誌KiKvaShadowMode將被相應地設置為1或2。如果KiFlushPcid != 0,則該值為1;如果KiFlushPcid == 0,則該值為2。
整個過程的最關鍵環節,是建立並配置好系統調用處理器。
在此之前,首先我們迅速介紹一下用於執行系統調用的機制。當執行SYSCALL指令(例如在ntdll.dll中)時,代碼執行將會切換到內核模式常式,特殊模塊寄存器(Model Specific Register)指向該常式的地址。MSR是一個比較特殊的寄存器,必須通過rdmsr和wrmsr這兩個CPU指令來藉助索引進行訪問。例如,IA32_STAR的索引是C0000081,IA32_LSTAR的索引是C0000082等等。
IA32_STAR(0xC0000081):Ring 0和Ring 3段基址,以及SYSCALL的EIP。在較低的32位中存儲的是SYSCALL的EIP,在第32-47位存儲內核段基址,在第48-63為存儲用戶段基址。IA32_CSTAR(0xC0000083):兼容模式下,SYSCALL的內核RIP相對定址。IA32_LSTAR(0xC0000082):長模式(Long Mode,即64位)下,SYSCALL的內核RIP相對定址。基本上,全局標誌KiKvaShadow中的所有結果都會被檢查。如果對KiKvaShadow的檢查結果為TRUE,就不會使用正常的系統調用處理程序(KiSystemCall32和KiSystemCall64),而是使用影子版本。如果該處理器是AMD的,則會使用AMD專用版本。當SYSCALL指令被執行時,控制權會立即轉移到系統調用處理器,這也就意味著這些處理器也必須被映射到UserDirectoryTableBase中。同樣地,中斷服務常式(ISR)也有影子版本:
並且,這些中斷服務常式序必須要容易被讀取:
重點示例:系統調用
為了說明地址空間是如何來回交換的,我們將聚焦於一個重要的示例——系統調用。和以前一樣,我們不對其基礎原理做過多講解,如有需要,大家可以從《英特爾系統編程指南(第三卷)》(Intel』s System Programming Guide (Volume 3))中進行參考和學習。
KiSystemCall64Shadow如下:首先,SWAPGS用於將當前GS基址寄存器的值與MSR地址C0000102H(IA32_KERNEL_GS_BASE)中的值進行交換。在最初階段,映射的內核內存非常少(因此非常安全),所以就必須通過GS段來獲取所有重要的信息。從GS:6000h開始,依次包含PML4基址的物理地址(也就是x64系統中的頁目錄)。
GS段中的關鍵參數如下:位於gs:6018h的標誌將會被檢查,如果需要進行交換(Swap),則PML4基址(對應於內核地址空間)將被移動到CR3之中。移動後,便可以訪問內核棧,一切都進入了正軌。我們注意到,不一定每次都需要進行交換,因為該交換很可能已經進行過(比如,在使用系統調用過程中發生了中斷)。
需要注意的一點時,當新的PML4移動到CR3之後,地址空間會立即切換,並且緊接著的下一個指令會在新的地址空間(內核私有空間)上發生。但由於KiSystemCall64Shadow被映射到相同的虛擬地址,所以一切還都保持著正常工作。KiSystemCall64AmdShadow:從這裡可以看出,英特爾版本和AMD版本的系統調用處理器差別非常小:二者最終都調用KiSystemCall64ShadowCommon,並且依次使用KeServiceDescriptorTable(又稱系統服務描述符/調度表,簡稱為SSDT)或KeServiceDescriptorTableShadow(包含win32k.sys中的常式地址)。
系統調用返回如下:在返回到用戶模式之前,地址空間會通過sysret指令得到保護。
安全分析
我們對內核的入口和出口進行了相同的分析,這裡以中斷服務常式(ISR)為例。
中斷服務常式:
內核出口:
我們可以看到,同樣的設計也適用於ISR。這是一個非常明智的設計,我們可以推斷出其中的安全策略。由於只有入口和出口(以及少量的支持數據)被映射,所以內核能夠抵禦像Meltdown這樣的內核攻擊。
當然,世界上沒有免費的午餐。以前,應用程序對內核進行系統調用或者接收到中斷時,內核頁表總是存在,所以不需要進行TLB刷新、頁表交換等,耗費的資源也比較少。但現在,由於使用了KVAS特性,在系統調用或中斷時(例如:NVM Express SSD等繁重的輸入/輸出),性能可能會有所下降。在雲服務中,這一現象尤為明顯,例如EpicGames的例子:總結
總體來說,虛擬內核地址影子是一個非常棒的特性。該特性以一種合理的方式,對系統性能進行了權衡。
本分析報告由FortiGuard Lion團隊撰寫。登錄安全客 - 有思想的安全新媒體www.anquanke.com/,或下載安全客APP來獲取更多最新資訊吧~
推薦閱讀:
TAG:微軟Microsoft | 信息安全 | 網路安全 |