一、背景:
1月4日,國外爆出了整個一代處理器都存在的災難性漏洞:Meltdown和Spectre。
幾乎影響了全球20年內所有cpu處理器;這兩個漏洞可以使攻擊者通過利用並行運行進程的方式來破壞處理器的特權內存,通俗的來說:攻擊者能夠竊取系統中任何數據。
目前,所有安全廠商都對這兩個漏洞詳細信息以及攻擊方式進行復現和驗證,但是講解的都非常專業,難懂。所以我從網上搜尋了多個分析文章,結合個人簡單理解,提取了如下一些內容,簡單介紹下這次的漏洞:
(由於本人對硬件技術了解有限以及目前爆出來的資料不是很全面,下面分析內容僅供參考)
二、簡單易懂的描述下這一次的漏洞:
首先這次的兩個漏洞原理比較類似,通俗的比喻一下:
我想要知道我同事的昨天的行蹤,那么我就試探的對同事說:我昨天看見了你和一個女生在一起逛街,你們是不是。。。? 雖然我昨天壓根兒什么都沒看到,但是我說完,他愣了一會(愣神比較久),回了一句:我憑什么要告訴你?!雖然他沒有承認,但是顯然我已經知道了答案。
這次的漏洞也是同理,利用了CPU的兩個特殊的機制:其中Meltdown利用了CPU的亂序執行,Spectre利用了CPU的預測執行。
Spectre預測執行:在整個OS系統中,某個應用程序(惡意軟件)去詢問操作系統:“用戶剛才登錄的密碼第一個數字是1嗎?”操作系統回復:“不關你的事,你沒有權限知道。”
這個過程本身是沒有問題的,但是問題出在:操作系統雖然沒有明確的回復,但是他心里想了一遍這個答案,尤其是當對方問到一個正確的數字時,他回答的稍微猶豫了幾毫秒,這個事情被惡意軟件注意到了,就可以通過反復的提問,最后猜到了密碼是什么。
Meltdown亂序執行:假設有abc三個地址,其中a地址沒有訪問的權限,但是b和c可以訪問,此時執行下面這個條件表達式:
x= a?b:c
表面看來,由於a地址無法訪問,所以系統會直接報錯!但實際上,CPU為了加快執行速度,會采用多流水線作業方式。它會在檢查a是否可訪問的同時,預先就往下執行了。等到權限檢查結果回來,已經根據a的結果完成了b或者c的加載,只是還沒有賦給x而已。經過加載的b或者c會在緩存里。雖然報錯了,但如果再次訪問就會比較快。於是再次訪問b和c,根據返回的時間快慢,就可以猜到a的內容!
三、Meltdown(熔斷)和Spectre(幽靈)區別:
1、Meltdown依賴於Intel的CPU設計漏洞,在OOO時,忽略對memory權限的檢查。
Spectre則是更嚴重的漏洞,涉及到近20年的Intel, AMD, Qualcomm廠家和其它ARM的處理器,而且更難修復。
2、官方表述:
1.Meltdown(熔毀)
Meltdown破壞了位於用戶和操作系統之間的基本隔離,允許惡意代碼訪問主機任意內存,從而竊取其他應用程序以及操作系統內核的敏感信息。這個漏洞“熔化”了由硬件來實現的安全邊界。允許低權限用戶級別的應用程序“越界”訪問系統級的內存,從而造成數據泄露。
2.Spectre(幽靈)
Spectre則是破壞了不同應用程序之間的隔離。問題的根源在於推測執行(speculative execution),這是一種優化技術,處理器會推測在未來可能執行的指令並預執行。這種技術的目的在於提前准備好計算結果,當這些數據被需要時可立即使用,以提升系統運行效率。內在的原因是CPU的運行速度大大快於內存的讀取速度。在此過程中,英特爾等CPU沒有很好地將低權限的應用程序與訪問內核內存分開,這意味着攻擊者可以使用惡意應用程序來獲取應該被隔離的用戶級私有數據。
四、漏洞利用方式及影響:
利用方式:
1、雲端主機(包括物理機和同機其他虛擬機)的相關敏感數據;對於雲服務而言,攻擊者會通過租用雲服務、利用其自身脆弱性或安裝惡意應用程序實施攻擊,並可能獲取到可以支持雲內橫向移動的關聯數據。由於雲服務基本都是在一台服務器上運行多個虛擬機,導致越界訪問其他雲主機的證書、密碼、秘鑰等
2、竊取桌面用戶敏感信息。對於桌面用戶而言,攻擊者可從瀏覽器側當作攻擊入口。目前網上已經驗證,通過一段JS代碼可以在用戶瀏覽器中成功利用此漏洞。
3、該漏洞對於專有設備的影響,目前還在分析評估中
利用難度:
漏洞利用難度很低。相關漏洞已有成熟PoC代碼流出
利用POC驗證代碼:
https://github.com/Eugnis/spectre-attack
https://github.com/feruxmax/meltdown
https://github.com/gkaindl/meltdown-poc
https://github.com/turbo/KPTI-PoC-Collection
漏洞影響:
Windows、Linux、macOS、亞馬遜AWS、谷歌安卓均包含在內
Intel、ARM的Cortex-A架構和AMD處理器。Cortex-A目前廣泛用於手機SoC平台,包括高通、聯發科、三星等等。
漏洞危害:
相關漏洞本身只能讀取數據,不能修改數據,但由於其獲取的數據中有可能包括口令、證書和其他敏感數據,甚至能夠完整copy內存鏡像,意味着可以獲取所有打開的文件和信息,因此這個漏洞比一般性的虛擬機對雲的危害更大。這種攻擊對雲的安全監測機制幾乎不受影響,因此其對雲安全、包括私有雲,危害極大。
五、漏洞修復:
目前Intel及其他芯片廠商尚未發布修補補丁
但大多數操作系統商(微軟、CentOS)和雲技術廠商已經發布了臨時補丁,但對於系統性能會有影響,需要謹慎評估后再進行修復。
六、專業漏洞解讀:
CPU亂序執行和預測執行導致的安全問題
亂序執行(Out-of-Order Execution) [1] 和預測執行(Speculative Execution) [2] 是現代CPU為了提高性能通常采用的優化方式。亂序就是指CPU不按照程序嚴格規定的先后順序執行,預測就是CPU基於先有經驗預先執行了后續可能執行的代碼。傳統觀念認為,由於CPU在運行過程中會丟棄亂序執行和預測執行所導致的不正確的運算結果,所以亂序執行和預測執行不會對程序的正確性和安全性造成任何影響。然而,最新的發現表明攻擊者完全可以利用這兩種CPU特性進行側信道攻擊。目前已知的Meltdown攻擊和Spectre攻擊就是兩個典型的攻擊實例 [3]。
從本質上來講,這兩種攻擊都屬於基於CPU緩存(cache)的側信道攻擊的范疇。這種側信道攻擊在最近十年國外的計算機安全研究領域非常流行。它們的基本假設是攻擊者在目標主機上擁有一定的執行權限(比如操作系統的一個普通進程,雲計算中的一個虛擬主機,或者瀏覽器中的一段Java代碼),然后通過控制自己內存空間的數據(例如讀取等等)來間接的控制CPU緩存。由於CPU緩存是攻擊者和目標主機上的目標程序共享的,這種對緩存的間接控制可以被攻擊者用來推測目標程序的行為。舉個例子來說,如果攻擊者和目標程序共享物理內存(比如同一個操作系統的兩個程序往往共享同一個動態鏈接庫),攻擊者可以反復的利用CPU指令把這塊內存的某個地址清除出CPU緩存(Flush階段),然后在一定的時間間隔后讀取這個地址上的內存數據並且測量讀取的時間(Reload階段)。通過這種方式,攻擊者可以清楚的知道該地址是否被目標程序讀取過,因為一旦目標程序讀取該地址,其對應的內存會被導入CPU緩存,從而使得攻擊者自己對這個地址的訪問變快(由於從緩存讀取要遠遠快於內存)。這種攻擊方式被稱為Flush+Reload [6]攻擊。此外CPU緩存側信道還有Evict+Time [7], Prime+Probe [8] 等攻擊方式。
然而,以往的側信道攻擊針對的目標是被攻擊者內存讀取的模式,例如某條指令是否被執行或者某個數據是否被訪問,而不能直接讀取被攻擊者的內存。而Meltdown攻擊[4] 和Spectre攻擊[5] 的目標是越權的內存讀取,比如讀取(dump)整個內核的內存數據。這就使得這種側信道攻擊的后果更加嚴重。這也是為什么這個CPU漏洞會被媒體大肆渲染。下面我們就對這兩種攻擊的基本形式和本質做一下介紹。
Meltdown攻擊
Meltdown攻擊利用現代CPU中亂序執行 (out-of-order execution)的特性,徹底攻破原本由硬件保證的內存隔離,使得一個僅僅具有普通進程權限的攻擊者可以用簡單的方法來讀取內核內存。應該強調一點,Meltdown攻擊不是針對KASLR[9]的攻擊。攻擊KALSR相對要簡單很多,因為它的目標僅是獲取內核內存的虛擬地址,而Meltdown的攻擊目標是獲取內核內存的內容。
Meltdown攻擊的本質是利用CPU進行的安全檢查和亂序執行之間的race condition,給攻擊者創造一個很短的攻擊窗口。亂序執行是指當CPU中的某些指令需要等待某些資源,比如內存讀取時,CPU不會在當前指令停止,而是利用空閑的計算能力繼續執行后續的指令。這大大地增加了計算能力的利用率,從而提升了CPU性能。在支持亂序執行的CPU上,指令的執行並不是順序進行的。比如后面的指令可能在前面指令執行結束之前就開始執行。然而,為了保證程序的正確性,指令退休(retirement)必須是順序進行的,而CPU的安全檢查是在指令退休時才會進行。這樣的結果是,在CPU對某一條指令進行安全檢查之前,一部分在該指令后面的指令會由於CPU的亂序執行而被提前執行。例如,一條用戶空間的指令訪問內核內存會導致CPU拋出異常,然而該異常只有在這條指令退休的時候才會被CPU處理,而由於亂序執行而被提前執行的指令會被CPU丟棄。由於CPU保證程序的正確性,亂序執行本不會產生安全隱患。然而,由於亂序執行的指令對緩存的操作在這些指令被丟棄時不會被重置,攻擊者就可以通過緩存側信道的方式來獲取這些亂序執行的信息,從而導致了Meltdown攻擊。本質上,Spectre攻擊的原理也是一樣的。我們會在后面介紹。
以下是一個簡化的Meltdown攻擊的基本指令:
1 ; rcx = kernel address2 ; rbx = probe array3 mov al, byte [rcx]4 shl rax, 0xc5 mov rbx, qword [rbx + rax]
首先,在指令3中一個具有用戶級權限的攻擊者訪問目標內核內存地址(存儲在寄存器rcx中)。由於訪問了內核地址,這一條指令將會觸發異常,使得它和它之后的指令對寄存器的修改將被全部丟棄。但是在等待CPU完成執行該指令的同時,后兩條指令因為亂序執行實際上已經被執行過了,並且此時的計算是根據指令3所讀取到的數據所進行,並不受CPU權限限制。指令4將會把這個數據乘以4096,並在指令5中將其作為offset來對數組probe array進行訪問。由於一個內存頁的大小是4KB,不同的數據將會導致不同的內存頁被訪問並存放到CPU緩存中。此后,另一個攻擊者進程就可以通過緩存側信道攻擊,來了解哪個內存頁被訪問過了,從而推斷出被訪問的內核內存數據。
具體的緩存攻擊方式有Flush+Reload [6],Evict+Time [7],或者Prime+Probe [8]。在Meltdown這個場景中(數組probe array是在攻擊者自己的內存空間的),比較簡單而且有效的攻擊方法是Flush+Reload,前面已經描述過其基本思想。簡單的講,Flush+Reload攻擊首先把probe array的相對應的內存用clflush指令清除出CPU緩存,然后在執行了上述攻擊代碼后再逐一訪問probe array的各個內存頁並記錄訪問時間。訪問時間短說明上述代碼執行過程中CPU已經把對應的內存頁加載到緩存中了,原因是這個內存頁對應的offset正好是內核空間中rcx指向的內存內容。
總的來說,Meltdown攻擊的指令由兩部分組成:第一部分利用亂序執行來訪問受限內存,第二部分根據所讀取到的數值再編碼到內存的訪問,並通過緩存側信道提取信息。攻擊的關鍵在於,亂序執行的這兩條指令必須在讀取內核內存的指令退休之前,也就是權限審核之前,執行完畢。另外,由於訪問受限內存會導致操作系統拋出異常,攻擊者可以通過hardware transaction memory等方式抑制異常[11]或者用其他方式處理異常[4],從而反復不間斷的對受限內存進行遍歷訪問。
Spectre攻擊
Spectre攻擊利用了CPU的預測執行對系統進行攻擊。預測執行是另外一種CPU優化特性。在分支指令執行時,由於分支指令執行可能需要內存讀取(上百個CPU周期),在分支指令執行結束之前,CPU會預測哪一個分支會被運行,提取相應的指令代碼並執行,以提高CPU指令流水線的性能。CPU的預測執行是通過分支預測單元(BPU)進行的。簡單的理解,BPU儲存了某個分支指令最近執行過的分支跳轉的結果。CPU的預測執行遇到分支指令時,會根據BPU的預測結果進行跳轉。當預測執行發現預測錯誤時,預測執行的結果將會被丟棄,CPU的狀態會被重置。然而,與亂序執行類似,預測執行對CPU緩存的影響會被保留。Spectre和Meltdown攻擊在這一點上比較類似。
Spectre攻擊主要分為三個階段:
准備階段: 在這一階段,攻擊者通過一些操作來訓練CPU的BPU,以使其在運行目標代碼時會進行特定的預測執行。同時,攻擊者可以執行一些操作來提高預測執行發生的機率,比如把條件判斷所需的數據擠出緩存,這樣執行分支指令的時間會加長。另外,攻擊者也可以在這一階段做好側信道的准備工作,比如Flush+Reload攻擊中的Flush部分。
攻擊階段:攻擊者利用CPU的預測執行把目標的機密數據轉移到微架構側信道中。具體的攻擊方法我們下面詳細描述。
機密數據提取階段: 通過測量Flush+Reload或其他緩存攻擊的方法中Reload內存時間,攻擊者可以從緩存側信道中提取出目標機密數據。這一點跟Meltdown攻擊十分相似。
在攻擊階段,攻擊者利用CPU的預測執行把目標的機密數據轉移到微架構側信道中。常見的分支指令包括條件分支指令和間接分支指令。所以相對的Spectre攻擊也有兩種不同的方式。其主要的思想是,攻擊者通過控制目標程序的某個變量或者寄存器,使其讀取攻擊者指定的內存地址。這里攻擊者指定的內存地址的內容就是攻擊者試圖獲取的機密數據(比如用戶密碼)。如果目標程序中含有將這個機密數據作為內存訪問的指針或者數組offset,那么攻擊者就可以利用緩存側信道來提取被訪問的內存地址,進而提取目標機密數據。
攻擊的危害
本質上講Meltdown和Spectra都是基於側信道的攻擊,主要用於信息泄露,並不能對目標內存地址進行任意修改。Meltdown攻擊往往用於攻擊者代碼由於權限的限制而不能任意讀取其所在的內存地址空間的情況。比如在操作系統中內核內存會被映射到所有普通進程的地址空間,盡管普通進程可以通過虛擬地址訪問所有受限內存,包括內核的地址空間,直接訪問內核地址會拋出異常而終止。而Meltdown攻擊可以幫助攻擊者完成這樣的操作。在雲計算的虛擬機架構上也有類似的問題,使得虛擬機可以通過Meltdown攻擊任意讀取雲服務器宿主機(host)虛擬機管理程序(VMM)的內存地址。而Spectra攻擊則利用目標程序的特殊結構,通過系統調用或者函數調用的方式控制其中的某個變量來達到泄漏目標程序(或內核)地址空間中內存內容的目的。比如文獻[5]提出了Java代碼訪問整個瀏覽器進程內存的方法。而文獻[10]提出了利用內核即時編譯(Just-in-time compilation)的特性進行提權攻擊,正是由於即時編譯出得代碼具有Spectra攻擊所需要的特殊結構。
Meltdown攻擊所攻擊的並不是軟件漏洞,而是CPU設計本身的安全缺陷。所以Meltdown攻擊適用廣泛,后果嚴重。它已經被證明在2010年后發布的Intel桌面及服務器CPU架構上全部可行。實驗證明個人計算機和雲服務器全都會受到影響,而被成功攻破的操作系統包括Linux,MS Windows,以及包含Docker,LXC,和OpenVZ在內的container。在ARM和AMD處理器上,盡管Meltdown攻擊所依賴的硬件漏洞同樣被證實存在,目前尚無完整的攻擊。可能的原因包括指令執行過慢,CPU的流水線(Pipeline)過短等等。相比之下,Spectre攻擊需要目標程序具有特殊結構,所以受到目標軟件的限制。如果目標程序不具有該特殊結構,那么Spectre攻擊就很難進行。但是相對於Meltdown攻擊目前僅限於Intel處理器上,Spectre攻擊適用於Intel,AMD,ARM等眾多處理器上。
漏洞的防御
雖然Meltdown和Spectre是CPU漏洞,短時間內很難通過CPU升級來修補漏洞。目前對Meltdown的主要防御手段是以軟件完全隔離用戶態和內核態來實現,雖然有分析稱這樣程序的性能可能會大幅下降。而Spectra的防御就更加困難,借助編譯器做程序分析,添加順序執行指令(比如lfence,cpuid)是一種可能的方案。我們也會繼續跟蹤重要廠商對漏洞的修補,並對這些修補方式進行測試。我們實驗室也會研究和開發其他安全技術對這些攻擊進行防范。
對於一般用戶,只要不被執行惡意代碼,比如不去訪問惡意網站,就不會有不可信代碼進入內存執行,就不會被Spectra和Meltdown攻擊。所以個人用戶還是可以利用已有的防御手段(比如惡意網站攔截)對自己進行保護。同時也應該及時關注系統軟件廠商,比如操作系統廠商和瀏覽器廠商的補丁並且隨時更新。
對於在雲端,由於攻擊者可以租借虛擬環境來執行攻擊者想執行的任何代碼,所以攻擊者可以利用它們去從虛擬機用戶態讀宿主機的內核態以及虛擬態的關鍵數據,從而可以攻擊其他虛擬機。所以雲廠商有責任在第一時間對這些CPU漏洞進行軟件修補。企業用戶應該采取積極的態度配合或者推動漏洞的控制。