【CSDN 編者按】一行看似普通的系統通知代碼,居然能讓一部 iPhone 反復重啟、卡死在恢復界面、徹底“變磚”?在本篇文章中,作者展示了一個幾乎無需交互的 iOS 漏洞利用方法——攻擊者只需誘導用戶安裝一個惡意小組件,手機就可能陷入無限恢復重啟的死循環,哪怕重啟也無濟于事。
原文鏈接:https://rambo.codes/posts/2025-04-24-how-a-single-line-of-code-could-brick-your-iphone
作者 | rambo.codes 翻譯 | 鄭麗媛
出品 | CSDN(ID:CSDNnews)
今天要講的,是我在 iOS 系統上發現的一個非常喜歡的漏洞。我之所以喜歡這個漏洞,一方面是因為利用它非常簡單,幾乎一行代碼就能觸發;另一方面,它用到的是一個蘋果操作系統中歷史悠久但仍然存在的功能,這個功能是公開的,很多蘋果的系統組件還依賴它,不過不少開發者甚至從來沒聽說過它。
這個功能就叫做——Darwin 通知機制。
首先,“Darwin 通知”是什么?
你可能聽說過 iPhone 上的 App 都是“沙盒運行”的——意思是每個 App 都被限制在自己的一塊區域里,不能隨便訪問別的 App 數據,也不能亂動系統的核心部分。這是蘋果為了安全設計的一種機制。
但有時候,一個 App 還是需要和別的 App 或系統進行簡單的消息交換,這時候就需要一種“進程之間打招呼”的方法。蘋果系統中,有幾種方式可以實現這個目的,比如:
NSNotificationCenter:只能在同一個進程內部使用,可傳遞對象或字符串。
NSDistributedNotificationCenter:可支持不同進程之間的簡單通信,并允許附帶字符串形式的數據,但使用起來有一些限制。
Darwin 通知:這是蘋果系統最底層的通知機制,屬于操作系統的核心部分(叫做 CoreOS),能讓不同進程不管是不是在沙盒內,都能互相發送簡單的通知消息。
簡單來說,Darwin 通知最大的特點就是:簡單、快速,而且不需要任何額外權限。你只需要知道通知的名字,就可以接收或者發送它。那么 Darwin 通知機制具體要怎么用呢?下面簡單舉個例子。
假設有一個系統功能,比如“鎖屏”操作,它在內部可能監聽了一個叫做 com.apple.springboard.toggleLockScreen 的通知(這名字只是一個示例)。
如果某個進程想通知系統“請鎖屏”,它就可以調用 notify_post("com.apple.springboard.toggleLockScreen") 這個函數。
如果系統正在監聽這個通知,那它就會響應,并執行鎖屏操作。
而如果有其他進程想監聽這個通知,也可以通過一個叫 notify_register_dispatch 的函數注冊監聽,當通知被發出時就會收到消息。
更進一步,Darwin 通知還可以附帶一個狀態值,比如“1”表示開啟,“0”表示關閉。某個進程發送這類通知時需要先申請一個句柄(可以理解為“發言資格”),然后就能使用 notify_set_state() 來設置這個狀態。同樣地,其他進程可以通過 notify_get_state() 來讀取這個狀態。這就讓 Darwin 通知不僅能“廣播事件”,還可以存儲一些系統級的“全局狀態信息”,供系統中任何進程實時讀取。
問題來了:這個機制太開放,反而成了漏洞
關鍵點在于:這個 Darwin 通知機制雖然非常方便,但它的權限檢查幾乎為零。
任何程序,哪怕是受限的沙盒 App(就是你手機上安裝的普通 App),都可以使用它:不需要系統權限,不需要蘋果簽名,也不需要 Entitlement(蘋果用來標記系統權限的認證機制)。當然,這在設計上并不算問題,畢竟蘋果的很多系統框架(包括第三方 App 可用的)確實依賴 Darwin 通知來完成某些功能。
雖然 Darwin 通知的數據傳輸能力有限,不太可能被用來竊取敏感數據,但別忘了:發送通知同樣不需要權限。總結一下 Darwin 通知的特點:
接收通知不需要特殊權限;
發送通知不需要特殊權限;
API 是公開的;
沒有任何發送方校驗機制。
正因為如此,我開始思考一個問題:是否存在某些系統組件會監聽特定的 Darwin 通知,并在接收到通知時執行高權限操作?如果有,那么是否可能在沙盒應用中通過偽造通知,實現類似拒絕服務(DoS)的攻擊?
你現在正在讀這篇文章,說明我已經劇透了:確實存在這樣的漏洞。
漏洞利用演示:EvilNotify
在我意識到 Darwin 通知機制可能存在嚴重漏洞之后,我決定進行深入測試。我下載了一份最新的 iOS 系統鏡像(當時是 iOS 18 的早期測試版),開始查找系統中有哪些進程使用了 notify_register_dispatch 或 notify_check 這兩個函數——只要某個進程用到了這兩個函數,那它就可能“對某些通知做出反應”,從而成為攻擊目標。
很快,我找到了不少目標進程,于是做了一個小測試應用,取名叫 “EvilNotify”,專門用來驗證我的想法。
可惜,我現在手頭連一臺容易被攻擊的舊 iOS 設備都沒有,因此無法錄制運行效果的真實視頻。不過,上面這個 iOS 模擬器的演示視頻,基本展示了大部分概念驗證(Proof of Concept, PoC)能實現的效果。雖然有些功能在模擬器上無法運行,但核心部分的演示還是保留了下來。
在視頻的最后,你應該能看到一點提示,說明了最終“拒絕服務(DoS)攻擊”手段是怎樣的。但在那之前,讓我先列一下 EvilNotify 利用漏洞可以實現的所有破壞性操作。要注意:這些操作都是系統級的,所以哪怕用戶強行退出了 App,也無濟于事。
EvilNotify 能通過 Darwin 通知機制,觸發以下一系列系統行為:
讓狀態欄顯示出“液體檢測”警告圖標(通常只有檢測到 Lightning 接口有液體時才出現);
觸發靈動島(Dynamic Island)顯示“外接顯示器已連接”的狀態提示;
禁用全系統的滑動手勢,比如下拉控制中心、通知中心,甚至無法喚出鎖屏界面,整部手機基本“半癱瘓”;
強制系統忽略 Wi-Fi,只使用蜂窩移動網絡直接鎖定屏幕;
強制鎖屏;
彈出“數據傳輸中”的界面,用戶必須手動取消,否則設備無法正常使用
模擬設備進入和退出“查找我的 iPhone”(Find My)中的“丟失模式”,并強制觸發 Apple ID 密碼驗證,要求重新啟用 Apple Pay;
讓設備進入一個“正在恢復中”狀態(Restore in Progress)。
“正在恢復中”
因為我當時想找一個最有效的拒絕服務(DoS)方式,最后一種觸發“正在恢復中”的模式看起來最有潛力——設備一旦進入“正在恢復中”狀態,唯一的辦法是點擊“重新啟動”按鈕,從而強制重啟設備。
更妙的是,觸發這個模式的代碼,只需要一行:
notify_post("com.apple.MobileSync.BackupAgent.RestoreStarted");
就是這一行!只要執行了它,設備就會立刻進入“正在恢復中”模式。由于設備實際上并沒有真正進行數據恢復操作,所以過一段時間這個狀態就會超時失敗,但在此期間,用戶除了點擊“重新啟動”按鈕之外別無選擇,而點擊這個按鈕就會導致設備重啟。
我進一步分析二進制文件發現,正是系統的主界面管理器 SpringBoard 在監聽這條通知,用來觸發相應的 UI 界面——正常情況下,這條通知只在通過電腦恢復本地備份時發送。但正如之前所說,由于 Darwin 通知沒有權限限制,任何 App 都可以偽造這條通知,輕松騙過系統進入恢復模式。
拒絕服務攻擊演示:VeryEvilNotify,用一個小組件讓 iPhone 無限重啟
在我找到了這樣一個可能導致拒絕服務(DoS)的 Darwin 通知機制后,我接下來的目標,就是設法讓它在設備重啟后仍能反復觸發。
一開始這聽起來相當棘手。畢竟在 iOS 系統中,應用在后臺運行的機會非常有限,許多有副作用的 API 在應用不處于前臺時是無法正常工作的。不過我發現 notify_post 在應用處于后臺時仍然有效,因此這個問題被排除了。
至于怎樣在設備重啟后,反復發送通知,我最初也不太確定。不過我猜測,利用應用擴展(App Extension)應該是最有可能成功的方式。
一些類型的第三方應用擴展,可以在設備“第一次解鎖之前”就運行。因此,我決定嘗試一種我非常熟悉的擴展類型 —— Widget Extension(小組件擴展),并基于此創建了一個新的應用,命名為 “VeryEvilNotify(非常邪惡的通知)”。
在 iOS 系統中,小組件擴展會被周期性喚醒,用于生成快照(snapshot)和時間線(timeline),這些內容將被系統緩存,并展示在鎖屏界面、主屏幕、通知中心和控制中心等位置。由于小組件的使用范圍廣泛,當系統檢測到用戶安裝并首次打開了一個包含小組件的 App 時,會非常積極地嘗試加載該小組件擴展,從而為用戶提供選擇并添加組件到界面的機會。
本質上,小組件擴展就是一個可以運行代碼的進程,因此我將那行關鍵代碼添加到了擴展的入口邏輯中。為了最大程度地提升小組件被系統喚醒執行的可能性,我還配置了所有可能的小組件類型。不過這也存在一個問題:小組件擴展生成的內容(占位符、快照、時間線)會被系統緩存以節省資源。即使擴展請求了更高的更新頻率,系統也會強制實施“時間預算”策略,對頻繁更新的請求進行節流控制。
為了繞過這一限制,我決定讓擴展在執行完那行關鍵代碼后故意崩潰。具體做法是:在小組件擴展的所有時間線提供點中調用 Swift 的 fatalError() 函數,強制使擴展崩潰——為什么?因為當系統發現一個小組件崩潰、沒有生成任何內容后,它會認為“小組件初始化失敗”,下次系統啟動后會再次嘗試喚醒它來修復問題。
因此在擴展的入口點中,我將 notify_post 的調用置于最前,確保每次擴展被喚醒時,都會執行漏洞觸發代碼:
import WidgetKit
import SwiftUI
import notify
struct VeryEvilWidgetBundle: WidgetBundle {
var body: some Widget {
VeryEvilWidget
()
if #available
(
iOS
18, *
)
{
VeryEvilWidgetControl
()
}
}
}
/// Override extension entry point to ensure the exploit code is always run whenever
/// our extension gets woken up by the system.
@main
struct VeryEvilWidgetEntryPoint {
static func main
()
{
notify_post
(
"com.apple.MobileSync.BackupAgent.RestoreStarted"
)
VeryEvilWidgetBundle.main
()
}
}
有了這個小組件擴展之后,只要我在測試設備上安裝并啟動 VeryEvilNotify 應用,設備就會立即彈出“正在恢復中”的界面,然后因超時失敗,要求用戶“重新啟動”系統。而設備重啟后,只要 SpringBoard 初始化完成,系統就會再次喚醒這個小組件,從而無限循環地觸發崩潰與恢復。
最終結果就是:設備進入軟磚狀態(soft-brick)。唯一的恢復方式是徹底抹除所有數據,重新刷機,并從備份恢復系統——而更糟糕的是,如果這個 App 被包含進了用戶的備份文件中,那么當用戶恢復備份后,該漏洞可能再次被觸發……
我猜 iOS 系統確實有考慮“擴展崩潰后不該無限重試”,也設置了某種節流機制。但可能是由于這個擴展觸發的時間點太巧了——擴展崩潰的時機與“正在恢復中”狀態開始并失敗的時間點重疊,剛好打破了系統的保護機制,導致系統無法正常處理崩潰恢復。
在實現了這個驗證概念(PoC)后,我將這個漏洞如實上報給了蘋果的安全團隊。
時間線
以下是關于此次漏洞報告的簡要時間線。期間還有來自蘋果安全報告系統的自動消息更新,但為了簡潔,我在本文沒有一一列出。
2024 年 6 月 26 日:向蘋果提交了初步報告
2024 年 9 月 27 日:收到蘋果通知,稱緩解措施正在進行中
2025 年 1 月 28 日:問題被標記為已解決,同時確認符合漏洞賞金條件
2025 年 3 月 11 日:漏洞分配了編號 CVE-2025-24091,并在 iOS/iPadOS 18.3 中修復
漏洞賞金金額:17500 美元(約合人民幣 12.7 萬元)
雖然 CVE 已經分配,蘋果也提供了預定發布公告和致謝的鏈接,但截至本文發布時,公告尚未正式上線,不過應該很快就會發布。為了保險起見,我下面提前附上了公告內容:
可以注意到,公告中提到“敏感通知現在需要受限權限”,這也暗示了蘋果采取的修復措施。關于具體細節,可以繼續閱讀下面的介紹。
蘋果修復漏洞的方式
如蘋果在公告中所說,現在要發送敏感的 Darwin 通知,發送進程必須具備受限權限(restricted entitlements)。這并不是一個統一的權限可以通發所有敏感通知,而是采用了前綴式的權限控制,格式為:com.apple.private.darwin-notification.restrict-post. 。
通過簡單分析反匯編代碼可以推測:決定一個通知是否被“受限”的依據,是通知名稱是否帶有 .com.apple.private.restrict-post. 這個前綴。
舉個例子,以前發送的是:com.apple.MobileBackup.BackupAgent.RestoreStarted,現在變成了:com.apple.private.restrict-post.MobileBackup.BackupAgent.RestoreStarted。在這樣的設計下,系統組件 notifyd 會在允許發送該通知前,先校驗發送進程是否具備相應的權限。
同時,監聽這些通知的系統組件(例如恢復界面)也會使用這個新的“加前綴”的通知名。這樣一來,只有被授權的系統程序能互相通信,普通 App 就完全被擋在外面了。
我沒有專門去逐個比對舊版 iOS,查找引入這個機制的確切版本。不過,借助 ipsw-diffs 工具可以看到,這項權限機制最早出現在 iOS 18.2 beta 2(版本號 22C5125e)中。其中,最早采用這一新機制的系統組件是:backupd、BackupAgent2 和 UserEventAgent。
這些組件最先獲得了發送“敏感通知”的授權,從而封堵了我在 PoC(概念驗證)中展示的最嚴重的利用手段。在隨后的各個 iOS 18 測試版及正式版中,越來越多的系統進程也逐步采用了這種受限通知機制。最終在 iOS 18.3 中,所有我在 PoC 測試中展示的問題均被徹底修復。
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.