以索尼PSV為例,說說如何從F00D中提取金鑰?
前言
如果大家不懂F00D是什麼,我可以做個簡單介紹,一句話,F00D是一個處理器專門處理和儲存金鑰。如果你感興趣,想要詳細瞭解 35C3大會 的一篇訪談文章。讀完這篇文章,你將學會一個技能,即如何利用F00D加密處理器中所出現的漏洞。在我們深入研究之前,我將解釋F00D的一些基本工作原理。
模擬金鑰派生
PlayStation®VITA是索尼的一代掌機,簡稱PSV,今天我們就以它為例進行說明。在PSV上,加密處理的裝置有兩個,並且,這兩個裝置所執行的功能基本上是相同的。 “DMAC5”就是其中一種裝置,它可以對ARM核心執行各種加密操作,例如:
1.對儲存卡進行加密或解密;
2.對連續記憶體分配器(CMA)PC備份進行加密或解密;
3.對PFS(完全前向保密)進行加密或解密,PFS(perfect forward secrecy),中文可叫做完全前向保密。要求一個金鑰只能訪問由它所保護的資料;用來產生金鑰的元素一次一換,不能再產生其他的金鑰;一個金鑰被破解,並不影響其他金鑰的安全性。
4.對核心核心轉儲(coredump)進行加密;
……
DMAC5裝置由兩大部分組成:加密裝置本身和與之相關的金鑰環。金鑰環包含0x20個大小為0x20位元組的插槽。預設情況下,F00D都會自帶金鑰環,其中有幾個插槽是直接連著ARM的。然後,DMAC5可以通過在執行加密操作時指定一個金鑰槽來使用此金鑰環。
PSV上除了DMAC5之外,還有另一個功能相同的加密裝置,我們稱之為“Bigmac”,因為它只能由“F00D”處理器訪問。 雖然Bigmac和DMAC5的介面幾乎相同,但Bigmac只能通過F00D訪問。
就像DMAC5一樣,Bigmac也有一個相關的金鑰環,功能和DMAC5大致相同,不過Bigmac的金鑰環有0x800個0x20位元組的插槽,並且你可以為每個插槽設定特定功能。這些功能通常包括:
1.指定用哪種演算法(AES,HMAC,CMAC等)訪問它;
2.指定用哪種演算法模式(加密,解密或兩者兼有);
3.是將輸出結果寫入記憶體還是僅寫入特定的插槽;
4.是否可以寫入;
不過大多數插槽沒有許可權,無法使用。另外,對於存放主金鑰的金鑰槽來說,是不允許進行覆蓋的;而對於其他槽來說,經過一定的配置,則可用於加密。
Bigmac的關鍵用途之一就是“派生”金鑰,也就是說,Bigmac會將一個加密的金鑰“解密”到一個金鑰槽中。利用這個原理,索尼既可以更新各種重要的金鑰,同時,也不用擔心將其暴露在明文中了。這意味著,獲得這些派生金鑰的唯一方法就是破壞用於解密這些金鑰的主金鑰,或以某種方式讀出金鑰槽。
在此,讓我們先了解一下使用Bigmac進行解密的傳統做法。其中,關鍵的是以下4個方面:
1.找到我們要解密的資料來源;
2.確定資料所在的目標地址,如RAM地址或金鑰槽編號;
3. AES金鑰存放在哪個金鑰槽裡;
4.搞清要解密的資料大小;
按著以上的提示,如果要在正常情況下解密金鑰,我們首先需要一個經過加密的金鑰,然後將目標地址指向一個金鑰槽,並將其大小設定為0x10位元組。所以要提取金鑰,我們的第一選擇就是修改目標地址,將其儲存在記憶體地址中。但這一做法顯然無法實現,因為用於派生金鑰的所有金鑰槽,都被明令禁止在目標地址未指向金鑰槽的情況下進行使用。
所以我的另一個思路就是嘗試改變要解密的資料大小。有趣的是,使用不是分組密碼倍數的大小似乎有效。在標準AES中,你需要提供的資料的大小必須是密碼塊大小的倍數,本文用的是0x10。因此,通常可以假設它們會使用填充模式來處理不可分割的塊大小,同時,Bigmac的輸出結果與輸入的大小是一致的。
經過一番測試,我發現Bigmac可以接受的資料塊大小是4個位元組的倍數。當執行4位元組資料塊的解密時,我注意到每次呼叫引擎時返回的明文都不同。當解密的大小大於0x10位元組時,卻沒有觀察到此種現象,這意味著我們輸入的部分位元組與前面計算的結果混合在了一起。
然後我們可以嘗試根據此屬性,進行提取金鑰的測試。讓我們假設Bigmac正在對一些殘留資料進行簡單的複製。當我們提供4個位元組的資料00 00 00 00時,解密過程如下圖所示。
Bigmac緩衝區中的殘留資料來自之前返回的結果
這樣,我們就知道00 00 00 00是用前一個操作中的殘留資料來進行加密的。接下來的問題就是,弄清楚殘留的資料是什麼?為此我們需要使Bigmac內部緩衝區進入已知狀態,我們可以使用由0組成的金鑰來解密一個完全由0組成的資料塊,這樣我們就能同時知曉明文、密文和金鑰了。
解密00,用已知的明文和密文填充Bigmac緩衝區
為了確定Bigmac沒有清除它的內部緩衝區,我們現在可以通過使用0金鑰塊解密4位元組的00 00 00 00來確認這一點。
Bigmac緩衝區包含上次操作的殘留資料
正如以上我所設想的那樣,當傳入的資料小於加密塊時,Bigmac只是一味地往裡複製資料,而不會清除其內部緩衝區。而往裡複製的資料大小,則完全取決於我們輸入的大小。
提取過程
在搞清楚了金鑰儲存原理後,就是利用其中的漏洞來進行攻擊了。不過先別急,在進行正式攻擊之前,讓我們來模擬一次金鑰派生過程。假設有一個金鑰:00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D0E 0F,它是以某種加密形式進行儲存的,並且加密金鑰是未知的。假設我們需要將這個加密金鑰解密到某個金鑰槽中。這樣的話,Bigmac的內部緩衝區中就會包含相應的解密的金鑰。如果我們要求Bigmac使用全部是0的金鑰塊來解密長4位元組的資料00 00 00 00,則會發生如下過程。
部分覆蓋可以降低暴力破解金鑰資料的難度
大家可以看到,當前內部緩衝區中,解密後的資料為00 00 00 00 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F,由4位元組的全部是0的資料塊和後面的金鑰資料組成。要注意的是,即使原始金鑰派生必須將結果儲存到金鑰槽中,我們也不會受到部分解密的限制。這使我們能夠控制金鑰、觀察密文和部分控制明文。
由於此資料的4個位元組為零,我們可以使用2 ^ 96次而不是2^128次,就能暴力破譯就能破解剩餘的資料。雖然這是一個巨大的進步,但還是不夠理想。
為了解決這個問題,我們需要繼續重複上面的過程。不過,這次不是寫入4位元組的全0值,而是寫入12位元組的全0值。這樣,我們就可以使用2 ^ 32次就能暴力破譯就能破解剩餘的資料,以現在的PC計算能力,這個工作量,可以在幾分鐘內輕鬆完成。
部分寫入會導致4位元組的金鑰資料保留在Bigmac緩衝區中
接著,我們可以使用8位元組的全0值來重複上面的過程,不過現在,我們可以藉助於從12位元組的全0值這一步所獲得的已知值來確定金鑰的另外4個位元組。
現在,我們可以重新使用之前的使用4位元組的全0值所獲得的值,並使用暴力破解出來的值來確定另外4個位元組。
部分覆蓋允許我們獲得另外32位的金鑰資料塊
現在在經過3 * 2 ^32次嘗試後,終於可以暴力破解出了我們所模擬派生的96位金鑰。不過要獲得金鑰的最後32位,最簡單的方法就是使用完整金鑰來解密或加密某些選定的明文。然後,通過嘗試解密或加密明文來暴力破解最後32位,直到獲得預期的密文。
至此,128為模擬的派生金鑰全部被解密。
總結
在進行暴力破解時,可能會出現碰撞現象,不過這屬於正常現象。
不過,本文所描述的這種金鑰提取方法無法用於提取“主金鑰”。因為,主金鑰位於一個金鑰槽中,並且該金鑰槽已經被鎖定,所以無法進行覆蓋。所以,該方法僅適用於在Bigmac裝置中進行加密或解密資料。
此類派生的示例是F00D載入器的AA金鑰,這個金鑰是通過使用主金鑰(插槽0x208)將標頭的一部分解密到另一個槽(例如0xA)而得到的。這意味著如果索尼更改了AA金鑰,我們可以通過設定故障來執行bootrom程式碼並執行此攻擊來獲得新金鑰。而此方法只在bootrom中有效,因為索尼在引導之後禁用0x208主金鑰。
應該說這是一個有趣的漏洞,不過可以通過禁止向加密裝置輸入非對齊資料來進行提前預防。另一個簡單的解決方案就是在加密操作結束時清除內部緩衝區。由於此漏洞存在於在硬體中,攻擊者總能夠利用它來獲取派生金鑰。這樣的話,系統中唯一可用於加密或解密的安全部分就只剩主金鑰了。