分析 Pegasus 間諜程式所用的 ForcedEntry 零點選 iPhone 漏洞攻擊

Citizen Lab 發布了一項有關 iPhone 最新威脅「ForcedEntry」的報告。這個零點選 (zero-click) 的漏洞攻擊手法似乎能夠繞過 Apple 的 BlastDoor 安全機制,讓駭客直接存取裝置而不假使用者之手。

分析 Pegasus間諜程式所用的 ForcedEntry 零點選 iPhone 漏洞攻擊
分析 Pegasus間諜程式所用的 ForcedEntry 零點選 iPhone 漏洞攻擊

Citizen Lab 最近發布了一份報告,內容詳述 9 名巴林的人權分子如何遭到精密的 iPhone 漏洞攻擊。這些人權分子據稱遭到以色列 NSO Group 駭客公司的 Pegasus (飛馬) 間諜程式攻擊,經由兩種 iMessage 零點選 (zero-click) 漏洞攻擊手法駭入其 iPhone:其一是 2020 年發現的 Kismet,其二是 2021 年最新發現的  ForcedEntry。零點選攻擊手法可說是一種相當精密的威脅,因為它有別於一般惡意程式,完全不假使用者之手就能感染裝置。前述兩種手法當中,後者又特別值得關注,因為它能繞過 Apple 的 BlastDoor 安全機制,而該機制正是專為防範零點選攻擊手法而生。 

根據 Citizen Lab 的報告,Kismet 攻擊手法的流行期間是從 2020 年 7 月至 9 月,針對的是使用 iOS 13.5.1 至 13.7 的裝置,自從 Apple 在 9 月份推出 iOS 14 更新之後就已經失效。接著在 2021 年 2 月,NSO Group 開始推出能夠繞過 BlastDoor 保護的零點選漏洞攻擊手法,也就是 Citizen Lab 所稱的「ForcedEntry」。國際特赦組織 (Amnesty International) 旗下的 Amnesty Tech (集合了全球數位人權專家與資安研究人員) 也在這段期間觀察到 iMessage 零點選漏洞攻擊相關的活動,並將它命名為「Megalodon」。 

深入研究 ForcedEntry


根據 Citizen Lab 的報告,當受害者的裝置遭到 ForcedEntry 漏洞攻擊時,裝置的記錄檔會出現兩種當機情況的記錄。第一種是在呼叫 ImageIO 的功能來渲染 Adobe Photoshop PSD 資料時。 

本文分析的是第二種當機情況 (請看圖 1),這種當機情況是發生在呼叫 CoreGraphics 的函式來解碼 PDF 檔案中以 JBIG2 編碼的資料時。此處的分析完全是根據 Citizen Lab 所提供的樣本,我們尚未取得其他新樣本。 

Image from Citizen Lab shows a Symbolicated Type Two crash for ForcedEntry on an iPhone 12 Pro Max running iOS 14.6. The red highlights from Trend Micro Research.圖 1:這張 Citizen Lab 提供的圖片,顯示了 ForcedEntry 漏洞攻擊手法第二種當機情況的記錄(測試裝置:iPhone 12 Pro Max,作業系統:iOS 14.6)。紅色框線是 Trend Micro Research 所做的標記。

我們從這份當機記錄歸納出以下三項結論:第一,這個零點選攻擊是在 iMessage 處理附件檔案時發生。第二,dyld_shared_cache 的 slide 是 0,這表示所有系統模組都載入到固定的位址上。第三,當機點的位址「0x181d6e228」並非漏洞攻擊的第一地點。以下詳細說明這些結論。

CVE-2021-30860 的問題根源


此漏洞出現在核心繪圖框架「CoreGraphics.framework」的「 JBIG2Stream::readTextRegionSeg 」函式內,其當機點的位址「 0x181d6e228 」(上圖紅框 3 標示處 ) 是在「JBIG2Stream::readTextRegionSeg」函式的第 161 行:

Screenshot of the function JBIG2Stream::readTextRegionSeg showing the crash point圖 2:當機點位於 JBIG2Stream::readTextRegionSeg 函式內部。

首先,程式會根據 JBIG2SymbolDict 區段 (segment) 來算出「numSyms 」的值:

Image from Citizen Lab shows a Symbolicated Type Two crash for ForcedEntry on an iPhone 12 Pro Max running iOS 14.6. The red highlights from Trend Micro Research.

「numSyms」的資料類型是正整數 (unsigned int),而「 seg->getSize() 」函式的回傳值也是正整數。所以,由於整數會溢位,所以 numSyms  的值應該會小於一個 JBIG2Segment 的大小,舉例來說:numSyms=1=(0x80000000+0x80000001) < 0x80000000。

接著,程式會配置一塊記憶體緩衝區「syms」,其大小是 numSyms * 8 :

ForcedEntry

最後,程式在 syms 這塊緩衝區中寫入點陣圖的內容:

ForcedEntry

由於迴圈執行的次數取決於 JBIG2Segment 的大小,但因為它可能超過緩衝區 syms 的大小,所以會導致資料寫入位置超過緩衝區 syms 的範圍。

Apple 如何修正此問題?


Apple 在 iOS 14.8 當中修正了這個函式:

ForcedEntry
圖 3:修正後的 JBIG2Stream::readTextRegionSeg 函式。

我們可以看到,Apple 增加了兩項邊界檢查 (圖 3 紅框標示處) 來避免資料寫入動作超出 syms 緩衝區範圍。

Pegasus 間諜程式的漏洞攻擊手法

停用 ASLR

我們將 iOS 14.6 (18F72) 中的 dyld_shared_cache 載入 IDA Pro 來執行靜態分析,結果令人意外。我們不需重新調整區段 (segment) 的基底位址就能直接找到呼叫堆疊 (call stack) 中的位址。

若我們從圖 1 當中紅框 2 標示的位址來推算的話,dyld_shared_cache 的 slide 為  0(零)。但一般來說,在當機的情況下這些位址應該都在slide內。

假設這份當機記錄沒有被篡改過,那麼我們得到的結論令人擔心。值得注意的是,Pegasus 在漏洞攻擊之前就已經停用了位址空間配置隨機化 (Address Space Layout Randomization,簡稱 ASLR) 功能。

繞過 PAC 機制

若檢視呼叫堆疊追蹤 frame 1 的  0x181d6e20c  位址,我們可看到暫存器 X0 (JBIG2Stream::findSegment 函式回傳值) 是一個 JBIG2Segment: 的子類別 (subclass)。

ForcedEntry

其  getType()  虛擬函式可能被四個子類別強制取代 (override),但以下程式碼顯示,它們只是傳回某個列舉值 (enumerate):

ForcedEntry

例如, JBIG2SymbolDict::getType  只是傳回  jbig2SegSymbolDict=1:

ForcedEntry

因此,frame 1 應該要呼叫  seg->getType() 這個虛擬函式才對。但實際上,它卻反而呼叫當前的函式本身  (frame 0)。 

這顯示, JBIG2Segment 物件的虛擬函式表 (virtual function table) 已經被換掉,表示它繞過了指標驗證程式碼 (PAC) 安全機制。這一點之所以重要,是因為 PAC 安全機制的開發就是為了 防範零點選攻擊,而這也意味著當機點並非漏洞攻擊的第一地點。 

結論與建議


就攻擊技術來看,Pegasus 間諜程式對 iOS 使用者來說是一項相當精密的威脅。然而,這類攻擊似乎都針對極特定的目標,而非一般使用者。

有關 Pegasus 近期的攻擊資訊都是來自 Citizen Lab 和 Amnesty Tech 的鑑識分析,我們尚未在外界發現 Pegasus 的攻擊樣本。目前我們仍在積極搜尋及監控這項威脅,未來若有更新的消息,我們將持續跟大家分享。

基本上,ForcedEntry 是一個相當普通的檔案格式解析漏洞。這跟我們先前發現的 CVE-2020-9883 類似,都能做到 Pegasus 此處所做的事。然而 ForcedEntry 最值得注意的是我們至今還不曉得它是如何繞過  PAC 並關閉 ASLR。

目前,我們強烈建議您 將裝置更新到 iOS 14.8。就如前面所說,一般的 iOS 使用者並非 Pegasus間諜程式瞄準的目標。此外,使用者也可採取一些簡單的步驟來加以防範,例如,使用者可在 iMessages 中封鎖不明的寄件人。還有一種更激烈的手段就是:在裝置設定中直接停用 iMessage 功能。

原文出處:分析 Pegasus (飛馬) 間諜程式所用的 ForcedEntry 零點選 iPhone 漏洞攻擊手法 作者:Mickey Jin