性能VS安全?CPU晶元漏洞攻擊實戰 - 破解macOS KASLR篇

作者:蒸米,白小龍 @ 阿里移動安全

0x00 影響

早上突然就被Meltdown和Spectre這兩個晶元漏洞刷屏了,但基本上都是一些新聞報道,對漏洞的分析和利用的信息基本為0。作為安全研究者,不能只浮在表面,還是要深入了解一下漏洞才行,於是開始研究這方面的資料。結果發現其實這個硬體漏洞的影響非常廣,不光是Intel, ARM和AMD也受影響,只是AMD的影響比較小罷了。因此基本上所有的操作系統(Windows,macOS,Linux,Android等)都有被攻擊的風險。漏洞有兩種攻擊模式:一種被稱為Meltdown,是在用戶態攻擊內核態,造成內核信息泄露。另一種被稱為Spectre,一個應用可以突破自己的沙盒限制,獲取其他應用的信息。另外,因為是硬體漏洞,這個攻擊對雲的影響非常大,利用這個漏洞,一個guest可以獲取host或同一台伺服器上其他guest的信息,可以說是一個非常嚴重的漏洞,因此亞馬遜和google都在緊急加班修復漏洞。比如google就公布了漏洞修復的進度在:support.google.com/faqs。雖然是硬體漏洞,但是在系統或軟體層面上通過犧牲性能的方法還是可以進行修補的。

0x01 原因

那麼我們現在知道漏洞很嚴重了,那麼漏洞形成的原因是什麼呢?關鍵點在於Speculative execution(推測執行)。推測性執行是一種優化技術,CPU會執行一些可能在將來會執行任務。當分支指令發出之後,傳統處理器在未收到正確的反饋信息之前,是不會做任何工作的,而具有預測執行能力的新型處理器,可以估計即將執行的指令,採用預先計算的方法來加快整個處理過程。如果任務最終沒有被執行,CPU還可以回滾到之前的狀態,就當做什麼都沒發生過一樣。但是這樣真的安全嗎?答案是,並不安全。攻擊者通過尋找或構建一些指令就可以在CPU回滾的時間窗口裡進行一系列的攻擊。比如Google Blog中提到的邊界檢查繞過(CVE-2017-5753),分支目標註入(CVE-2017-5715), 惡意數據緩存載入(CVE-2017-5754)。

舉個例子,如果CPU執行下面這段代碼:

arr1->length沒有被緩存的時候, CPU會從arr1->data[untrusted_offset_from_caller]處讀取數據,如果untrusted_offset_from_caller的值超過arr1->length,就會造成越界讀。當然,正常情況下這並不會出現什麼問題,因為在執行到判斷語句那一行的時候,CPU發現不對,後面的語句不應該被執行,於是會將狀態回滾到越界讀之前。

但是接下來,問題就出現了。假設arr1->length,arr2->data[0x200]和arr2->data[0x300]都沒有被緩存,CPU會繼續推測執行下面的代碼,在這裡index2會根據value&1產生兩個不同的值0x200,0x300,而Value就是越界讀到的值。接下來,代碼會根據Value的值去讀取arr2->data[0x200]或arr2->data[0x300]的值並且這個值會被加入到緩存里。接下來,我們可以再次嘗試去讀取arr2->data[0x200]和arr2->data[0x300],讀取時間短的那個值說明被緩存過了,因此就可以判斷出value&1的值為0還是1,從而做到內核信息泄露。

其實,在google的blog發布之前,就已經存在類似的攻擊了,只是危害沒有這麼大而已,今天我們就直接實戰一個利用Intel CPU晶元漏洞來破解macOS KASLR的攻擊。

0x02 晶元漏洞實戰之破解KASLR

這種攻擊比較簡單,但是是後面高級攻擊的基礎,因此我們先從這個攻擊講起。之前我們講到,為了讓CPU效率更高,它們依靠推測性執行在任務到來之前就提前執行任務。同樣,數據預取就利用這個思想推測性地先將數據載入到緩存中。Intel的CPU有五個軟體預取指令:prefetcht0,prefetcht1,prefetcht2,prefetchnta和prefetchw。這些指令作用是提示CPU,告訴他一個特定的內存位置可能很快被訪問。然而,Intel的手冊中卻提到,預取「未映射到物理頁面的地址」會導致不確定的性能損失。因此,我們可以通過CPU預讀指令執行的時間長短來判斷這個地址有沒有被映射到物理頁面上。

我們知道KASLR的原理是在內核的基址上增加一個slide,讓攻擊者無法猜測內核在內存中的位置。但是內核肯定是被映射到物理頁面上的,因此我們可以使用預取指令去遍歷內核可能的起始地址,如果執行預取指令的時間突然變短,就說明我們猜中了內核的起始地址。我們在網上成功找到了破解macOS 10.13 KASLR的POC,並做了一點簡單的修改:pastebin.com/GSfJY72J

其中關鍵代碼如下:

這是一段彙編,參數會傳入想要預取的地址,然後利用rdtscp和rdtscp來統計指令執行的時間,並返回。於是我們從內核可能的起始地址開始,不斷地執行這段彙編代碼,直到我們找到內核的起始地址為止。

可以看到在0x15c00000這一行,指令執行的時間明顯縮短了。因此,我們可以猜出Kernel Slide為0x15c00000。

0x03 修復

根據某內部漏洞修復人員在twitter上的回復,蘋果已經在macOS 10.13.2上對此類晶元漏洞進行了修復,採用了犧牲性能的針對用戶態使用兩次映射的方式來解決該問題。並且據說10.13.3上有更好的解決方案。另外iOS的A*系列晶元暫時還不受這類漏洞的影響。

0x04 總結

本篇文章只是給晶元的一系列漏洞開了個頭,我們隨後還會有更多關於晶元漏洞的分析和利用實戰,歡迎繼續關注本系列的文章,謝謝。

參考文獻:

1.

googleprojectzero.blogspot.hk

2. siguza.github.io/IOHIDe

3. Prefetch Side-Channel Attacks: Bypassing

SMAP and Kernel ASLR, CCS 2016.


推薦閱讀:

為什麼我國的計算機科技領域發展了十幾年水平依舊落後國外這麼多?
如果CPU的cache(緩存)容量上GB或更高,會有哪些不同?
計算機為什麼要設置線性地址,從邏輯地址到線性地址再到物理地址?
C++的std::atomic與體系結構中多核內存模型/緩存一致性協議(監聽 目錄協議)有什麼關係?
長期在64位CPU上運行32位程序是否會導致未用到的高位損毀?

TAG:安全 | 中央处理器CPU | 漏洞 | 中央处理器CPU计算机体系架构 |