【導讀】 iPhone曝出「史上最複雜」硬體等級漏洞!駭客只需一條iMessage即可拿到所有敏感數據,而使用者不會有任何察覺。整個漏洞涉及的鏈條極為複雜,讓Karpathy都驚呼:不是普通人能幹出來的事。
最近,卡巴斯基的研究人員發現,有駭客在四年多的時間裡給數千部iPhone留下了一個非常隱密的後門。
透過這個硬體等級的後門,能直接取得iPhone最高等級的Root權限。而要成功利用這個後門,就必須對蘋果產品最底層的機制有非常全面且細緻的了解。
以至於發現這個漏洞的卡巴斯基研究人員稱「無法想像這個漏洞是如何被意外發現的。」在他看來,除了蘋果和ARM之外,幾乎不可能有人能獲知這個漏洞。
而間諜軟體可以透過這個複雜的漏洞,將麥克風錄音、照片、地理位置和其他敏感資料傳輸到攻擊者控制的伺服器。
儘管重新啟動就能關閉這個漏洞,但攻擊者只需在設備重新啟動後向設備發送新的惡意iMessage文本,就能重新開啟這個漏洞。
期間完全不需要使用者進行操作,也不會留下任何蛛絲馬跡,非常隱密。
對此,OpenAI科學家Andrej Karpathy表示:這無疑是我們迄今所見過的攻擊鏈中最複雜的一個。
對此,Karpathy認為,這已經不是個人行為能夠觸及的範疇了,應該是國家層級的行為了。
而一位聲稱自己還用Palm手機的網友回覆道:「我堅持用Palm手機的意義就在這裡。」
甚至還有網友感嘆:「如果你成功地惹惱了具備這種技術能力和資源的人,可能你最不需要擔心的就是自己手機裡的數據了。」
目前,蘋果已於2023年10月25日修復了這項核心安全漏洞。
「三角行動」攻擊鏈
這個漏洞被發現的研究人員稱為「三角行動」(Operation Triangulation)。
- 攻擊者透過iMessage發送一個惡意附件,應用程式會在使用者毫無察覺的情況下開啟這個漏洞。
- 該附件利用了一個遠端程式碼執行的漏洞(CVE-2023-41990),該漏洞存在於一個只有蘋果知道的、未公開的ADJUST TrueType字體指令中。這個指令自九十年代初就存在,直到最近一個更新才被移除。
- 在攻擊過程中,它採用了一種稱為「返回/跳躍導向程式設計」的高級程式設計技巧,並且使用了多個階段的程式碼,這些程式碼是用NSExpression/NSPredicate查詢語言編寫的,它們修改JavaScriptCore庫的環境,以執行一個用JavaScript編寫的權限提升的漏洞攻擊程式。
- 這個JavaScript漏洞攻擊程式經過特殊處理,使其變得幾乎無法讀懂,同時也盡可能地縮小了它的體積。然而,它仍然包含大約11000行程式碼。這些程式碼主要用於分析和操縱JavaScriptCore和核心記憶體。
- 它也利用了JavaScriptCore的一個調試功能DollarVM ($vm),透過這個功能,攻擊者可以在腳本中操縱JavaScriptCore的內存,並呼叫系統原生的API函數。
- 這個攻擊工具被設計成相容於新舊型號的iPhone,並且對於新型號的設備,它包含了一個用於繞過指針認證碼(PAC)的技術,這使得攻擊能夠針對最新設備生效。
- 它透過利用XNU記憶體映射系統呼叫(mach_make_memory_entry和vm_map)中的一個整數溢位漏洞(CVE-2023-32434),實現了以使用者層級對裝置所有實體記憶體的讀寫控制。
- 該工具還運用了硬體記憶體映射I/O(MMIO)暫存器來規避頁面保護層(PPL),這一問題在CVE-2023-38606中已經被緩解。
- 利用了所有漏洞之後,JavaScript漏洞便能隨意操控設備,包括部署間諜軟體。不過,攻擊者選擇了:(a)啟動IMAgent進程,注入程式碼以清除利用痕跡;(b)無痕模式下執行Safari進程,並引導至含有下一階段內容的網頁。
- 該網頁內嵌了一個腳本,能夠確認受害者身份,一旦驗證通過,便會載入下一階段的攻擊代碼:Safari漏洞。
- Safari漏洞透過CVE-2023-32435來執行shellcode。
- 這個shellcode進一步執行另一個核心級漏洞,同樣利用CVE-2023-32434和CVE-2023-38606。它在規模和功能上都非常龐大,但與JavaScript編寫的核心漏洞截然不同。它們共享的只是與上述漏洞利用相關的部分程式碼。然而,其大部分程式碼也專注於解析和操控核心記憶體。
- 這個漏洞最終獲得了root權限,並繼續執行其他階段的操作,這樣就可以載入間諜軟體。
謎一樣的漏洞
討論的焦點是一個已經修復的安全漏洞,編號為CVE-2023-38606。
新一代iPhone在硬體層面增加了額外的安全防護措施,專門用來保護核心記憶體中的敏感區域。
即使攻擊者能夠讀寫內核內存,例如利用CVE-2023-32434漏洞實施的這次攻擊,這種防護也能阻止他們完全控制設備。
研究人員發現,攻擊者為了規避這種硬體防護,竟然利用了蘋果自家設計的SoC中的另一個硬體功能。
簡單來說,攻擊者的手法是這樣的:他們在繞過硬體防護的同時,將資料、目標位址和資料的雜湊值一併寫入到晶片中未被韌體使用的某些未知硬體暫存器,以此來對特定的實體位址進行資料寫入。
研究人員推測,這個不為人知的硬體功能很可能是為了蘋果工程師或工廠的調試或測試而設計的,或者是意外包含在內的。由於韌體並未使用此功能,研究人員對於攻擊者是如何知曉並利用這項功能的方式一無所知。
技術細節
在系統級晶片(System on a Chip, SoC)中,各種週邊設備可能會提供特殊的硬體寄存器,以供中央處理器(CPU)使用,從而控制這些外設。
為了實現這一點,這些硬體暫存器被映射到CPU可以存取的記憶體中,這種方式被稱為「記憶體映射輸入/輸出(Memory-Mapped I/O, MMIO)」。
蘋果的產品,如iPhone、Mac以及其他裝置中,週邊裝置的MMIO位址範圍被儲存在一個特殊的檔案格式中,名稱為「裝置樹(DeviceTree)」。
這些設備樹檔案可以從韌體中提取,並且可以使用dt(DeviceTree)工具來查看它們的內容。
設備樹中MMIO的儲存範例
例如,在這張截圖裡,可以看到cpu0的acc-impl MMIO範圍的起始位址(0x210f00000)和大小(0x50000)。
在深入研究「三角行動」(Operation Triangulation)攻擊中使用的漏洞時,研究人員意外發現,攻擊者為了繞過硬體層級的核心記憶體保護所使用的大部分MMIO位址,並沒有在裝置樹中定義。
這個漏洞專門針對蘋果從A12到A16的SoC,攻擊的是位於0x206040000,0x206140000和0x206150000的神秘MMIO暫存器區塊。
這激發了研究人員的好奇心,也進行了一系列的嘗試。翻遍了各種設備的設備樹文件和韌體文件,但都沒找到任何線索。
這讓研究人員困惑不已,這些被攻擊者利用的MMIO位址,為什麼不在韌體中使用呢?攻擊者是怎麼發現這些位址的?這些MMIO地址到底屬於哪些週邊設備?
之後研究人員決定去查看這些未知MMIO區塊附近是否有其他已知的MMIO位址。這次,他終於找到了一些有價值的資訊。
在gfx-asc的設備樹條目的資訊中,這是GPU的協處理器。
設備樹中gfx-asc條目的資料轉儲
它包含兩個MMIO(Memory-Mapped I/O)記憶體映射範圍:0x206400000–0x20646C000和0x206050000–0x206050008。
gfx-asc MMIO範圍與漏洞所用位址的相關性
要更準確地描述,這個漏洞使用了以下一些未知的位址:0x206040000、0x206140008、0x206140108、0x206150020、0x206150040和0x206150048。
研究人員發現,這些位址大部分位於兩個gfx-asc記憶體區域的中間,而剩餘的一個位址則靠近第一個gfx-asc區域的起始位置。
這暗示了所有這些記憶體映射輸入輸出(MMIO)暫存器很有可能是屬於圖形處理單元(GPU)的協處理器!
隨後,研究人員對這個漏洞進行了更深入的分析,並且發現了一個進一步的證據。
在初始化過程中,漏洞首先會寫入一些位於每個SoC特定位址的記憶體映射輸入輸出(MMIO)暫存器。
if (cpuid == 0x8765EDEA): # CPUFAMILY_ARM_EVEREST_SAWTOOTH (A16) base = 0x23B700408 command = 0x1F0023FF
elif (cpuid == 0xDA33D83D): # CPUFAMILY_ARM_AVALANCHE_BLIZZARD (A15) base = 0x23B7003C8 command = 0x1F0023FF
elif (cpuid == 0x1B588BB3): # CPUFAMILY_ARM_FIRESTORM_ICESTORM (A14) base = 0x23B7003D0 command = 0x1F0023FF
elif (cpuid == 0x462504D2): # CPUFAMILY_ARM_LIGHTNING_THUNDER (A13) base = 0x23B080390 command = 0x1F0003FF
elif (cpuid == 0x07D34B9F): # CPUFAMILY_ARM_VORTEX_TEMPEST (A12) base = 0x23B080388 command = 0x1F0003FF
if ((~read_dword(base) & 0xF) != 0): write_dword(base, command) while(True): if ((~read_dword(base) & 0xF) == 0): break漏洞中GFX電源管理器控製程式碼的偽代碼
在裝置樹和Siguza開發的工具pmgr的輔助下,研究人員發現所有這些位址都對應於電源管理器中的GFX暫存器所在的MMIO(Memory-Mapped Input/Output)範圍。
最後,當研究人員嘗試去存取這些未知區域的暫存器時,得到了第三個證實。
GPU的協處理器幾乎立刻報錯,顯示資訊:「GFX SERROR Exception class=0x2f (SError interrupt), IL=1, iss=0 – power(1)」。
這樣,研究人員就確認了所有這些未知的MMIO暫存器,它們是用來進行漏洞利用的,確實屬於GPU的協處理器。
這促使研究人員更深入地研究這個固件,這些固件也是用ARM架構編寫且未加密的,但是他在韌體中並沒有找到任何與這些寄存器相關的資訊。
他決定更仔細地研究這個漏洞是如何操縱這些未知的MMIO寄存器的。在所有暫存器中,0x206040000特別引人注目,因為它位於與其他所有暫存器都不同的獨立MMIO區塊中。
它僅在漏洞的初始化和結束階段被操作:在初始化過程中是第一個被設定的寄存器,在結束階段是最後一個。
根據研究人員的經驗,很明顯這個暫存器不是用來啟用/停用漏洞所利用的硬體功能,就是用來中斷控制。
研究人員開始追蹤中斷的線索,不久之後,他不僅辨識出了這個未知的暫存器0x206040000,還發現了位址範圍0x206000000–0x206050000究竟映射了什麼。以下展示的是研究人員能夠辨識出的漏洞程式碼的逆向工程結果。
def ml_dbgwrap_halt_cpu():
value = read_qword(0x206040000)
if ((value & 0x90000000) != 0): return
write_qword(0x206040000, value | 0x80000000)
while (True): if ((read_qword(0x206040000) & 0x10000000) != 0): break
def ml_dbgwrap_unhalt_cpu():
value = read_qword(0x206040000)
value = (value & 0xFFFFFFFF2FFFFFFF) | 0x40000000 write_qword(0x206040000, value)
while (True): if ((read_qword(0x206040000) & 0x10000000) == 0): break利用程式使用0x206040000暫存器的偽代碼
成功將先前偽代碼中的ml_dbgwrap_halt_cpu函數與XNU原始碼的dbgwrap.c檔案中同名函數配對。此檔案包含了用於操控主CPU的ARM CoreSight MMIO調試暫存器(ARM CoreSight MMIO debug registers)的程式碼。
原始碼顯示,存在四個與CoreSight相關的MMIO區域,它們分別是ED、CTI、PMU和UTT。每個區域佔據0x10000字節,彼此緊鄰。
ml_dbgwrap_halt_cpu函數利用了UTT區域。與其他三個區域不同,UTT並非來自ARM,而是蘋果專門為了便利性添加的專有特性。
研究人員確認了位址範圍0x206000000到0x206050000確實是GPU協處理器的CoreSight MMIO調試寄存器區塊,這是透過向對應位址寫入ARM_DBG_LOCK_ACCESS_KEY實現的。
主CPU的每個核心都有自己的CoreSight MMIO調試寄存器區塊,但不同於GPU協處理器,它們的位址可以在設備樹中找到。
另一個有趣的發現是,漏洞的作者(們)知道如何利用蘋果專有的UTT區域來重新啟動CPU,而這部分程式碼並不包含在XNU原始碼中。可以合理推測,這一操作很可能是透過實驗得出的。
然而,透過實驗是無法發現攻擊者在第二個未知區域內對暫存器的操作的。研究人員不確定那裡有哪些MMIO調試寄存器區塊,如果這些寄存器並未被韌體所用,攻擊者是如何發現其用途的也是個謎。
現在,再來關注其他漏洞利用的未知暫存器。
暫存器位址0x206140008和0x206140108負責控制啟用/停用以及執行漏洞所依賴的硬體功能。
def dma_ctrl_1():
ctrl = 0x206140108
value = read_qword(ctrl) write_qword(ctrl, value | 0x8000000000000001) sleep(1)
while ((~read_qword(ctrl) & 0x8000000000000001) != 0): sleep(1)
def dma_ctrl_2(flag):
ctrl = 0x206140008
value = read_qword(ctrl)
if (flag): if ((value & 0x1000000000000000) == 0): value = value | 0x1000000000000000 write_qword(ctrl, value) else: if ((value & 0x1000000000000000) != 0): value = value & ~0x1000000000000000 write_qword(ctrl, value)
def dma_ctrl_3(value):
ctrl = 0x206140108
value = value | 0x8000000000000000
write_qword(ctrl, read_qword(ctrl) & value)
while ((read_qword(ctrl) & 0x8000000000000001) != 0): sleep(1)
def dma_init(original_value_0x206140108):
dma_ctrl_1() dma_ctrl_2(False) dma_ctrl_3(original_value_0x206140108)
def dma_done(original_value_0x206140108):
dma_ctrl_1() dma_ctrl_2(True) dma_ctrl_3(original_value_0x206140108)
利用程式使用0x206140008 和0x206140108 暫存器的偽代碼
暫存器0x206150020專門用於蘋果的A15/A16 Bionic SoC。在漏洞利用的啟動階段,此暫存器會被設定為1;而在漏洞利用完成後,會恢復為初始的數值。
暫存器0x206150040被用來保存一些狀態標識和目標物理位址的低位元部分。
最後的暫存器,0x206150048,則負責儲存待寫入的資料以及目標實體位址的高位部分。這些資料會與資料的校驗雜湊值以及另外的數值(可能是指令)一起打包。此硬體功能會將資料分塊,每塊大小為64(0x40)位元組進行對齊寫入,並且需要連續九次寫入操作將全部資料寫入至0x206150048暫存器。
if (cpuid == 0x8765EDEA): # CPUFAMILY_ARM_EVEREST_SAWTOOTH (A16) i = 8 mask = 0x7FFFFFF
elif (cpuid == 0xDA33D83D): # CPUFAMILY_ARM_AVALANCHE_BLIZZARD (A15) i = 8 mask = 0x3FFFFF
elif (cpuid == 0x1B588BB3): # CPUFAMILY_ARM_FIRESTORM_ICESTORM (A14) i = 0x28 mask = 0x3FFFFF
elif (cpuid == 0x462504D2): # CPUFAMILY_ARM_LIGHTNING_THUNDER (A13) i = 0x28 mask = 0x3FFFFF
elif (cpuid == 0x07D34B9F): # CPUFAMILY_ARM_VORTEX_TEMPEST (A12) i = 0x28 mask = 0x3FFFFF
dma_init(original_value_0x206140108)
hash1 = calculate_hash(data)hash2 = calculate_hash(data+0x20)
write_qword(0x206150040, 0x2000000 | (phys_addr & 0x3FC0))
pos = 0while (pos < 0x40): write_qword(0x206150048, read_qword(data + pos)) pos += 8
phys_addr_upper = ((((phys_addr >> 14) & mask) << 18) & 0x3FFFFFFFFFFFF)value = phys_addr_upper | (hash1 << i) | (hash2 << 50) | 0x1Fwrite_qword(0x206150048, value)
dma_done(original_value_0x206140108)利用漏洞使用0x206150040和0x206150048暫存器的偽代碼
只要操作無誤,硬體就會執行直接記憶體存取(DMA)操作,把資料寫入指定的記憶體位址。
利用這項硬體特性,攻擊者可以繞過頁面保護層(Page Protection Layer, PPL),主要用途是修改頁表條目。此外,它還能修改受保護的__PPLDATA段內的資料。儘管這個漏洞並未用於修改內核程式碼,但在研究人員進行的一次測試中,曾經成功修改了內核的__TEXT_EXEC段內的一條指令,並引發了一個顯示預期位址和值的「未定義內核指令”錯誤。
這種情況只出現過一次,其他嘗試都導致了AMCC錯誤的發生。關於那次成功的嘗試,研究人員有一些思路,未來研究人員計劃深入研究,因為他認為,將一個本用於攻擊的漏洞轉化為正面用途,比如在新款iPhone上啟用內核調試功能,將會非常有意義。
在討論了所有與MMIO(Memory-Mapped I/O)暫存器相關的工作之後,現在來關注最後一個主題:哈希值的計算方法。具體的演算法如下所示。
sbox = [ 0x007, 0x00B, 0x00D, 0x013, 0x00E, 0x015, 0x01F, 0x016, 0x019, 0x023, 0x02F, 0x037, 0x04F, 0x01A, 0x025, 0x043, 0x03B, 0x057, 0x08F, 0x01C, 0x026, 0x029, 0x03D, 0x045, 0x05B, 0x083, 0x097, 0x03E, 0x05D, 0x09B, 0x067, 0x117, 0x02A, 0x031, 0x046, 0x049, 0x085, 0x103, 0x05E, 0x09D, 0x06B, 0x0A7, 0x11B, 0x217, 0x09E, 0x06D, 0x0AB, 0x0C7, 0x127, 0x02C, 0x032, 0x04A, 0x051, 0x086, 0x089, 0x105, 0x203, 0x06E, 0x0AD, 0x12B, 0x147, 0x227, 0x034, 0x04C, 0x052, 0x076, 0x08A, 0x091, 0x0AE, 0x106, 0x109, 0x0D3, 0x12D, 0x205, 0x22B, 0x247, 0x07A, 0x0D5, 0x153, 0x22D, 0x038, 0x054, 0x08C, 0x092, 0x061, 0x10A, 0x111, 0x206, 0x209, 0x07C, 0x0BA, 0x0D6, 0x155, 0x193, 0x253, 0x28B, 0x307, 0x0BC, 0x0DA, 0x156, 0x255, 0x293, 0x30B, 0x058, 0x094, 0x062, 0x10C, 0x112, 0x0A1, 0x20A, 0x211, 0x0DC, 0x196, 0x199, 0x256, 0x165, 0x259, 0x263, 0x30D, 0x313, 0x098, 0x064, 0x114, 0x0A2, 0x15C, 0x0EA, 0x20C, 0x0C1, 0x121, 0x212, 0x166, 0x19A, 0x299, 0x265, 0x2A3, 0x315, 0x0EC, 0x1A6, 0x29A, 0x266, 0x1A9, 0x269, 0x319, 0x2C3, 0x323, 0x068, 0x0A4, 0x118, 0x0C2, 0x122, 0x214, 0x141, 0x221, 0x0F4, 0x16C, 0x1AA, 0x2A9, 0x325, 0x343, 0x0F8, 0x174, 0x1AC, 0x2AA, 0x326, 0x329, 0x345, 0x383, 0x070, 0x0A8, 0x0C4, 0x124, 0x218, 0x142, 0x222, 0x181, 0x241, 0x178, 0x2AC, 0x32A, 0x2D1, 0x0B0, 0x0C8, 0x128, 0x144, 0x1B8, 0x224, 0x1D4, 0x182, 0x242, 0x2D2, 0x32C, 0x281, 0x351, 0x389, 0x1D8, 0x2D4, 0x352, 0x38A, 0x391, 0x0D0, 0x130, 0x148, 0x228, 0x184, 0x244, 0x282, 0x301, 0x1E4, 0x2D8, 0x354, 0x38C, 0x392, 0x1E8, 0x2E4, 0x358, 0x394, 0x362, 0x3A1, 0x150, 0x230, 0x188, 0x248, 0x284, 0x302, 0x1F0, 0x2E8, 0x364, 0x398, 0x3A2, 0x0E0, 0x190, 0x250, 0x2F0, 0x288, 0x368, 0x304, 0x3A4, 0x370, 0x3A8, 0x3C4, 0x160, 0x290, 0x308, 0x3B0, 0x3C8, 0x3D0, 0x1A0, 0x260, 0x310, 0x1C0, 0x2A0, 0x3E0, 0x2C0, 0x320, 0x340, 0x380]
def calculate_hash(buffer):
acc = 0 for i in range(8): pos = i * 4 value = read_dword(buffer + pos) for j in range(32): if (((value >> j) & 1) != 0): acc ^= sbox[32 * i + j]
return acc此未知硬體功能使用的雜湊函數偽代碼
如你所見,這是一個客製化的演算法,其雜湊值的計算依賴於一個預先定義好的sbox表(sbox table)。他嘗試在龐大的二進位檔案庫中搜尋它,但一無所獲。
你可能已經注意到,這個哈希並不特別安全,因為它只有20位(兩次各計算10位),但只要沒人知道如何計算和應用它,它就足夠用了。這種做法最恰當的描述就是「隱晦式安全性(security by obscurity)」。
如果攻擊者沒有使用這個硬體特性,而且韌體中沒有任何關於如何使用它的指引,他們如何可能發現並利用它?
研究人員又做了一個測試。他發現Mac內建的M1晶片也具備這未知的硬體特性。接著,他利用了功能強大的m1n1工具進行了實驗。
該工具具備一個trace_range功能,可以追蹤對指定MMIO暫存器範圍的所有訪問,用它來監測0x206110000到0x206400000記憶體範圍的活動,但結果顯示macOS並未使用這些暫存器。
這次涉及的GPU協處理器是最近才在蘋果的SoC中首次出現的。研究人員懷疑這個硬體功能在之前的零售韌體中有過任何用途。
儘管如此,也不能排除它可能曾在某個特定韌體更新或XNU原始碼的發布中不小心洩露過,之後又被刪除的可能性。
研究人員原本希望透過iOS 16.6中對這個漏洞的修復,來探究第二個未知區域裡隱藏了什麼。最後確實找到了蘋果是如何解決這個問題的,但他們故意將修復措施弄得難以理解。
蘋果透過在設備樹的pmap-io-ranges中加入了MMIO範圍0x206000000–0x206050000和0x206110000–0x206400000來防止這個漏洞被利用。
XNU根據這裡的資訊來判斷是否允許某些物理位址的對應。所有記錄在案的條目都貼上了一個標籤名,這些標籤清楚地說明了這些記憶體範圍的用途。
儲存在pmap-io-ranges中的條目範例
在這裡,PCIe指的是「高速週邊設備互連(Peripheral Component Interconnect Express)」,DART是「裝置位址解析表(Device Address Resolution Table)」,DAPF代表「裝置位址過濾器(Device Address Filter)」,諸如此類。
下面列出的是被漏洞利用的記憶體區域的標籤名稱。這些標籤在清單中顯得格外醒目。
利用漏洞的區域條目
「隱晦式安全」並不安全
可以看到,這個漏洞非比尋常,我們既不清楚攻擊者如何學會利用這個未知的硬體特性,也不知道它最初是用來做什麼的。
甚至不確定它是由蘋果開發出來的,還是類似ARM CoreSight這樣的第三方元件造成的。
但漏洞說明了一個事實:只要存在能夠繞過安全防護的硬體特徵,那麼無論多麼先進的硬體安全措施,在精明的攻擊者面前都會變得毫無用處。
硬體安全常依賴「隱晦式安全性」(security through obscurity),相較於軟體來說,硬體更難逆向工程分析。
但這種方法本身是有缺陷的,因為所有的秘密終將有被揭露的一天。那些依賴「隱晦式安全」來維護的系統,永遠無法做到真正的安全。(新智元)
參考資料:
https://arstechnica.com/security/2023/12/exploit-used-in-mass-iphone-infection-campaign-targeted-secret-hardware-feature/
https://securelist.com/operation-triangulation-the-last-hardware-mystery/111669/
