ABSynthe : 侧信道攻击加密函数窃取密钥
0x00 前言
這篇文章是發表在NDSS2020上,有關于微架構側信道攻擊的一篇文章。一作來自于英特爾公司,先前在硬件和底層上有比較多的研究。文章標題中的幾個關鍵詞,也在文章中有一定的體現,比如自動化、黑盒,合成等,這些都與一些現有的工作有比較大的差異。
0x01?背景知識
CPU組件存在大量的側信道攻擊,但現有的每一種側信道攻擊方式,幾乎都基于白盒分析的方法。通常情況下,需要3步來完成:
·?首先需要能夠識別出這一特定的CPU組件。
·?然后需要在特定的微架構上對其做逆向分析。
·?最后通過逆向分析得到的內容,人工構造指令序列,用以側信道泄露信息。
但這些方法通常都存在一些弊端,由于現有的側信道攻擊需要人工構造指令序列,而CPU會使用微架構組件來實現其指令集,并且這些微架構組件的底層細節不可見,因此需要逆向工程進行分析。隨著CPU的更新換代,這些組件的數量,大小,復雜性都在增加,同時這些組件的屬性可以在CPU版本之間發生變化,因此會對側信道研究人員帶來新的且冗長的逆向工作。
同時,除去對于逆向工程的復雜性,當想要對目標程序進行側信道攻擊時,還需要對該軟件有比較好的了解,清楚感興趣的內容,其代碼執行路徑在何處。這一切都對攻擊者有比較高的要求。除此之外,由于這些方法基于已有信息,那么對于那些未知的共享資源或者信息,則無法進行攻擊。
在此基礎上,作者提出了黑盒分析的思路,他們將CPU組件當做黑盒,無需進行逆向分析。并且可以自動的找到目標軟件可能感興趣的內容的代碼執行路徑。文章的核心思路利用了共享資源被爭用和不被爭用時,會存在可測量的性能差異這一現象進行側信道分析。
同時本篇文章的工作可以自動的優化出在側信道獲取信息時,性能表現最好的指令序列,無需人工參與構造指令序列,并可以利用神經網絡從側信道攻擊的結果中恢復密鑰。
0x02?工具設計
作者以從受害者進程或者虛擬機中泄露諸如密鑰等敏感數據為目的,提出了這樣一種威脅模型:
·?攻擊者可以在受害者的機器上執行代碼
·?攻擊者和受害者位于同一CPU核心上執行代碼
·?所有最先進的側信道保護都已啟用
·?目標軟件存在側信道攻擊的威脅
由于作者提出的側信道攻擊的核心思路是利用共享資源在被爭用和不被爭用時,會存在可測量的性能差異。
對于2條可能存在資源爭用的指令,作者將寫指令稱為A指令,讀指令稱為B指令,通過使用A指令來嘗試引起B指令的延遲變化,用以判斷是否存在資源爭用的情況。
如下圖,在writer指令執行時和不執行時,reader指令信號會存在明顯的差異性。
這里作者嘗試找出2條存在可觀察的資源爭用信號的指令,與以往工作中人工精心挑選指令不同,這里作者通過遍歷X86_64指令集來尋找最合適用于側信道攻擊的指令。這里的指令集來自于uops.info的項目。
為了評估結果,作者建立了一個矩陣,用來反應指令B在指令A的影響下所出現的延遲相較于指令B在空指令下的延遲比例。如果延遲比大于1,那么說明指令A和B會存在資源爭用的情況。
作者對指令列表中的指令進行了一次二層嵌套for循環,用以尋找所有指令兩兩之間延遲比大于1的情況,從而找到所有存在資源競爭的指令對。
為了將結果可視化的展現,作者將指令按照其使用的執行端口進行分組。按照執行端口分組的原因有2點:
1. 執行端口本身就是一種被爭用的資源
2. 可以將相似功能的指令組合在一起
從實驗結果我們可以發現:
1. 共享執行端口的指令不一定都是高爭用,也可能是無爭用的。例如skylake中P1端口。
2. 不共享執行端口的指令一般顯示低爭用,但也有存在高爭用的,這意味著共享資源不僅只有執行端口,可能還有其他資源。例如Xeon的P1和P5,P0和P5。
通過比對在3種不同微架構上指令對在執行端口爭用上的表現,作者總結出3個結論:
1. 可能存在多個資源有爭用問題,并非只有執行端口
2. 在某個微架構上表現較好的基于資源爭用的側信道攻擊,可能在其他微架構上不一定有效
3. 性能表現最好的基于資源爭用的側信道攻擊可能需要多個指令來引起資源爭用
在可以找到引起資源爭用的指令對后,下面來介紹一下工具設計的架構。
工具可以分為2個部分,一個是分析階段,一個是攻擊階段。
在分析階段,將微架構和目標軟件作為輸入,通過Ground Truth引擎自動對其插入指令,每當其進行密鑰操作時,就會與側信道監聽程序同步,發送與密鑰相關的信號數據。
側信道攻擊的代碼Spy code最初來自于微架構的leakage map,對于leakage map每一個性能表現比較好的指令,側信道監聽程序會將它們資源爭用的度量發送給合成引擎。而合成引擎則通過評估指令產生的資源爭用信號,來生成可以觸發更高信號質量的指令序列,循環往復,直到合成引擎生成的指令序列可以以足夠高的可信度探測到密鑰信息。
在攻擊階段,利用分析階段得到的優化后的指令序列進行側信道攻擊,并將獲取的信息傳遞給密鑰恢復引擎,用以恢復目標程序密鑰。
在進行上述方法實現時,會遇到3個挑戰:
1. 在分析階段時,工具需要自動對目標軟件進行指令插入,用以和側信道攻擊代碼同步測量,收集密鑰相關的真實數據,那么如何自動化的找到密鑰相關的控制流分支是一個難點。
2. 在分析階段時,如何自動的優化側信道攻擊代碼
3. 在攻擊階段時,如何通過側信道攻擊的結果去恢復密鑰信息
那么對于第一點如何自動化插入指令的難題,作者使用了污點分析與火焰圖的技術。對于第二點如何自動化優化攻擊代碼的難題,作者采用基于高斯樸素貝葉斯分類器的差分進化遺傳算法來作為評估方法用以自動化優化指令序列。對于第三點如何恢復密鑰,作者使用了RNN分類器。具體內容我們將在下一節展開。
0x03?工具實現
前面有提到,第一個難題就是如何自動化的進行指令插入,那么指令插入肯定不能隨意亂做,我們需要找到感興趣的代碼路徑,在其前后插入相應指令。而本文的針對攻擊目標是加密函數,因此如何自動化的找到密鑰相關的代碼分支,就是一個難題。
這里作者選擇使用污點分析來找到這些指令的插入位置,而后結合火焰圖來自動的找出密鑰相關的分支。
首先簡單介紹一下火焰圖的概念:
假設我們程序中需要執行main函數,main函數自身的CPU執行時間為2秒,而main函數中又調用了foo1和foo2函數,因此我們需要去計算foo1和foo2的執行時間,才能得到main的完整執行時間。
此時我們會去看foo1和foo2函數的調用時間,首先foo1函數自身的cpu執行時間為1.5秒,但由于其調用了bar函數,我們又需要再去看bar函數,才能計算出foo1的完整cpu執行時間。
此時看到bar函數,發現bar函數不再調用其他函數,其自身的cpu執行時間為2.5秒,因此我們可以算出foo1的完整cpu執行時間為其本身的1.5和bar函數的2.5之和,就是4秒。
那么同理,我們也可以算出foo2函數的完整執行時間為3秒,因此main函數的完整執行時間為自身的執行時間,加上foo1的時間,再加上foo2的時間,即9秒。
這一函數調用過程我們將其畫成火焰圖,如下圖所示。
回到工具中,這里工具ABSynthe首先會將密鑰文件中的所有數據標注為污點,進行污點分析。然后使用perf record來獲取目標程序所有函數的火焰圖,找到其中具有顯著執行時間的函數,看其是否被我們的污點標注過,如果標注過,則在這些函數位置插入指令。
如下圖中:
其中scalar是被標注成污點的密鑰變量,第4行為密鑰相關分支。第2和5行為我們嵌入的指令。
每當該分支被執行時,CRYPTLOOP_VALUE會發出信號,往共享內存中寫入一個值,然后側信道程序除了搜集側信號信號以外,還會讀取該值,用于后續的訓練。
在搜集信息時,同樣會存在難點,由于同步傳輸數據,本身就會產生噪音,影響側信道的測量。
這里為了避免這一問題,作者使用了軟同步策略,利用一個內存共享頁來實現共享內存通道。同時讓spy code持續監視目標共享內存位置,并將每個延遲測量值標記為樣本值。
那么對于第2個難題,如果想造成一次效果較好的側信道攻擊,那么執行的指令序列的構造非常重要,之前的工作這一構造通常由人工完成。而在本篇文章里,作者使用差分進化算法來自動化的優化構造指令序列,該算法的輸入為可以在微架構組件上產生資源爭用的指令,這里作者選擇了性能表現最好的指令作為種子。
同時作者希望算法可以自由的選擇最終的指令序列,但又希望其生成的指令序列是有效的,因此作者提前設計了一種配方,讓算法在尋找性能最好的指令序列時,對這些配方進行mutate。
首先我們來看一下配方的構成,第一個參數是Repeat number,這一參數用來定義指令序列需要執行的次數,范圍為1~20次。指令序列的執行時間可以作為探測目標程序密鑰操作的一種信號,執行時間需要在可觀測和高分辨率中做一個衡量,因此指令序列執行次數非常重要。
第2、3參數代表是否在執行指令序列前或執行指令序列后存在內存屏障。如果存在內存屏障,可以保證內存通信時,不會因為亂序執行而使測量時間的指令出現噪音。但相應的,也可能會降低指令序列執行時間的分辨率。因此需要將這一參數保留,讓算法來選擇是否要其存在。
第4、5、6、7參數是用于來創建資源爭用的。每個參數定義了特定信道所需的指令數量。
最后位置的參數用來規定使用哪種方式將指令塊合并到一起。這里作者提出了3種合并方式:
1. 串聯,即將簡單的將配方中的指令塊連接在一起。
2. 交錯,即將來自不同塊的指令交錯連接在一起。
3. 串聯后的隨機洗牌,即將配方中的指令塊簡單連接在一起后,再進行隨機洗牌
同時差分進化遺傳算法需要一個適應度函數來進行評估當前指令序列的質量,看該指令序列是否能夠產生可區分目標程序執行到不同代碼路徑的度量信號。
這里作者使用了高斯樸素貝葉斯分類器來進行評估。原因是該分類器在不需要調參的情況下表現良好,同時其在training和evaluation時具有線性的時間復雜度,可以保證差分進化遺傳算法能夠快速進行。
然后作者使用信號值來訓練該分類器,這些信號值來自于目標程序執行到某個代碼路徑時,我們的指令序列產生的信號,我們根據我們之前對目標程序插入的指令,來標記其對應是否執行的該代碼路徑,例如0和1。
同時作者為了證明優化指令序列的重要性,在目標程序Broadwell-NIST-P256上進行了對比實驗。
優化前:
優化后:
我們可以看到,在僅使用性能最好的單一指令時,PCA圖分界不夠明顯,特征不夠明顯。而在使用算法優化后的指令序列時,PCA圖分界比較明顯,因此說明這樣的指令序列獲取的信號度量更加具有特征性。
第3個難題是在之前的訓練中,由于數據的搜集一直是保持同步的,因此我們可以容易知道程序開始的起點位置和長度,因此分類器可以簡單的得到相關的密鑰值。但是在真實世界的攻擊中,我們獲取的信號很可能是多個從未知位置開始的連續信號,這就比較困難。同時在長時間捕獲信號的過程中,很容易失去同步。因此之前標記對應代碼執行路徑和延遲時間的方式在這里不可行。
為了解決這一問題,作者使用時間序列為向量,選擇了一種專門針對時間序列數據的LSTM RNN算法,該算法在不完全同步的情況下具有魯棒性,在信號發生微小時間偏移時,允許非同步的恢復密鑰。
作者同時提到,可以有方法驗證恢復密鑰的正確性,例如目標程序在簽名操作時,會使用密鑰。那么作者也將恢復的密鑰用于一次簽名操作,如果簽名相同,則說明密鑰正確,否則則說明密鑰錯誤。然后作者發現,恢復的密鑰往往都是不正確的。可能是密鑰某bit位丟失,或者是恢復錯誤。
但是每次密鑰恢復錯誤時,可能都需要對上百個bit位進行爆破,以找到正確的密鑰,但這樣的操作顯然不可取,例如一個384bit的密鑰,如果有n個bit猜測錯誤或者丟失,那么需要進行384^n次爆破,這顯然不可行。
但這里作者提到,由于考慮了時間序列問題,現在的算法的返回值是(time, secret),因此可以容易知道哪一位可能存在丟失或錯誤。因為丟失的時候,2個bit位之間會形成較大的時間間隙,而錯誤的時候,2個bit位之間會出現很窄的時間間隙。對于每一個可能出問題的bit位,一共只有3種情況,第一種是該位正常,忽略,第二種是該位丟失或錯誤應該改為0,第3種是該位丟失或錯誤,應該改為1。因此在密鑰恢復錯誤的情況下,如果有n個位置錯誤,那么只需要進行3^n次爆破來恢復密鑰。
考慮到上述原因,作者為了解決這一問題,使用了2個LSTM模型,在恢復密鑰時,如果2個模型預測值相同,那么才會接受。
這兩個模型,第一個是三層LSTM嵌套的模型,第二個模型是LSTM接一個激活函數RELU的全連接層*3的模型。這兩個模型都用0.2的 dropout 來緩解過擬合問題 并且由于是個多分類任務,輸出都用的softmax layer。然后它使用集成學習(Ensemble)的方式把兩個模型組合在一起,以獲得更好的效果。
這里的訓練數據特征是延遲值,訓練集的樣本分為兩類,奇熱一類是從程序已知的開始位置開始,另一類是從程序未知的開始位置開始。
0x04?實驗評估
作者使用了libgcrypt 1.6.3和libgcrypt 1.8.5中的加密函數EdDSA 25519、EdDSA 25519-hardened、EdDSA 25519-secure (1.8.5 only)、RSA、ECDSA P-256作為攻擊目標進行實現評估。值得注意的是,EdDSA 25519-hardened中已經對側信道攻擊有了基本的防御機制,而EdDSA 25519-secure對于側信道的防御機制被認為是最先進的。
作者在4個不同的微架構上進行了測試,使用F1分數來評估工具的性能。
這里值得注意的是,在ARM上,作者是人工編寫的指令序列。這里原因是,對于ARM沒有完整的leakage map,無法遍歷測試。而另外3個x86微架構,作者測試了所有可能的指令,并使用了4條最好的指令序列。這也體現出,作者的工具要比人工編寫指令序列性能高的多。
同時注意到紅框部分,由于這一條表現的性能非常好,作者選用其進行測試,看其在信息不同步的情況下,對密鑰的恢復能力如何。
作者對這些目標在信息不同步的情況下,進行了7次測試。可以發現不基于GPG加密軟件的情況下,正確恢復密鑰的準確率在100%,而在GPG加密軟件下有一定錯誤。原因是在無外部提示或者分析人員設置的情況下,密鑰相關分支完全由工具自動的進行識別。
同時作者將自己工具優化生成的指令序列與其他工作人工構造的指令序列進行了性能比對。
可以發現工具自動優化得到的指令序列,性能高于其他人工構造的指令序列。
同時從兩個維度來驗證工具的魯棒性。首先是能否自動的找到我們感興趣的分支,即密鑰相關的內容。
這里作者選擇在完全無側信道防御的EdDSA 25519算法上進行了7次測試,可以發現在密鑰相關程序開始時和其他時候有顯著的差異。說明工具在我們感興趣的區域預測密度顯著較高,證明了工具的可靠性。
第二個維度,作者從被干擾的情況下,測試工具的魯棒性。這里作者使用usleep函數,來干擾cpu的執行時間,干擾量為0.1%~30.6%。
這里我們可以發現2個點,第一點是即使目標程序存在噪音,密鑰恢復的準確度都不會有太多變化,這是因為我們前面介紹過,密鑰的恢復算法具有魯棒性,可以抵御干擾。第二點是,我們的側信道程序上如果出現噪音,則會受到影響,因為這涉及到了信號采集問題,如果信號不能準確采集,那么則無法進行密鑰的恢復。
當然工具也有一些局限性。
首先工具要求目標軟件會在加密運行時花費較長時間。同時密鑰需要從文件系統中進行加載,否則無法進行自動污點分析。
第二點是工具需要目標微架構的指令集定義格式易于創建leakage map,才能使用工具的方法自動生成并優化指令序列。這一點在x86上比較容易獲得,但是對于ARM還不行。
第三點是工具在后續的處理階段,可以有更為自動化的方式,通過暴力破解啟發式的方法來應用于各種程序。
0x05?后記
本篇文章第一個創建了在x86微架構上完整的leakage maps,并實現了一個全自動的側信道攻擊,其可以利用資源競爭的方式,對各種平臺,各種環境上的加密程序來進行側信道攻擊。對于前人工作具有比較高的創新性,同時為后續側信道攻擊測試提供了便捷性。
總結
以上是生活随笔為你收集整理的ABSynthe : 侧信道攻击加密函数窃取密钥的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python win32com 字体选择
- 下一篇: 功率放大器ADS仿真实例