當前位置:
首頁 > 知識 > Project Zero 對近幾年 iOS 內核漏洞利用技術的總結

Project Zero 對近幾年 iOS 內核漏洞利用技術的總結

我最近希望獲得一個在線參考,以簡要概述近年來每種公共iOS內核利用程序的利用思路。由於不存在此類文檔,因此我決定自己創建一個。

這篇文章總結了針對iOS 10到iOS 13的本地應用程序上下文中的原始iOS內核利用,重點是從漏洞初始原語到內核讀/寫的高級利用流程。在本文的結尾,我們將簡要介紹iOS內核漏洞利用緩解措施(包括硬體和軟體),以及它們如何映射到漏洞利用中使用的技術。

這篇文章沒有0 day漏洞利用,也沒有新穎的漏洞利用研究或令人興奮的惡意軟體的逆向。由於我需要這些信息,並認為其他人也可能會覺得有用,因此這篇文章可以被被用作參考。

x1術語說明

不幸的是,沒有稱為「安全研究人員的技術黑客術語」的權威詞典,這使得很難準確描述我想傳達的一些高級概念。為此,我決定將以下術語賦予本文特定的含義。如果這些定義中的任何一個與你對這些術語的理解不一致,請隨時提出改進的術語。

漏洞利用原語:在漏洞利用過程中開發的,比較通用的函數。

常見漏洞利用原語的一些示例包括:n 位元組線性堆溢出,在受控地址處的整數溢出,在何處寫入,任意存儲器讀/寫,PC控制,任意函數調用等。

特定於iOS內核利用的常見利用原語是具有對偽造的Mach埠(結構ipc_port )的發送權,該偽造的Mach埠可直接從用戶空間讀取和寫入其欄位。

漏洞利用策略:一種特定於漏洞的低級方法,用於將漏洞轉變為有用的漏洞利用原語。

例如,這是Ian Beer的iOS 11.1.2的async_wake攻擊中使用的攻擊策略:

信息泄漏用於發現任意Mach埠的地址。將分配埠頁面,並根據其地址從該頁面中選擇特定埠。所述IOSurfaceRootUserClient 漏洞被觸發以解除分配埠,產生一個接收到埠的已知地址。

最後一部分是與通用/漏洞無關的原語,我將其解釋為特定於漏洞的利用策略的終結。

通常,利用策略的目的是產生高度可靠的利用基元。

漏洞利用技術:一種可重用且合理的通用策略,用於將一個漏洞利用原語轉換為另一個(通常更有用)的漏洞利用原語。

漏洞利用技術的一個示例是面向返回的編程(ROP),它通過重用可執行代碼gadget將任意PC控制轉換為(幾乎)任意代碼執行。

針對iOS內核開發的一種利用技術是通過調用pid_for_task()使用偽造的Mach埠讀取4位元組的內核內存(將對偽造的Mach埠的發送權轉換為任意內核內存讀取原語)。

漏洞利用流:漏洞利用技術的高級方法,與漏洞無關的鏈,用於將漏洞授予的漏洞利用原語轉變為最終目標(在本文中,內核從本地應用程序上下文進行讀取/寫入)。

0x02 自iOS 10起公開的iOS內核漏洞

本節將簡要概述從針對iOS 10到iOS 13的本地上下文iOS內核漏洞利用。我將描述高級漏洞利用流程,並列出用於實現該漏洞的漏洞利用原語和技術。雖然我試圖追蹤每個原始的(即在漏洞利用代碼發布之前開發的)公共漏洞利用,它們既可以作為源代碼使用,也可以作為完整的文稿使用。

對於每種漏洞利用,我都概述了漏洞細節,漏洞利用策略(特定於該漏洞)以及隨後的漏洞利用流程(通用)。漏洞的哪些部分特定於該漏洞與哪些部分的通用程度足以被視為總體流程的一部分之間的界限是主觀的。在每種情況下,我都強調了我認為足夠通用的漏洞所授予的特殊利用原語。

mach_portal-iOS 10.1.1

由Google Project Zero(@ i41nbeer)的Ian Beer提供。

漏洞:CVE-2016-7644是XNU的set_dp_control_port()中的競爭條件,導致Mach埠被過度釋放。

利用策略:set_dp_control_port()分配了許多Mach埠,並刪除了對它們的引用,通過刪除隱藏的引用來釋放埠,從而使處理過程擁有接收權以懸掛Mach埠填充內存頁面。

後續利用流程:通過調用mach_zone_force_gc()強制進行區域垃圾回收,並使用包含指向主機埠的指針的離線(OOL)埠數組重新分配懸空埠的頁面。在一個懸掛埠之一上調用mach_port_get_context()以公開主機埠的地址。使用此值,可以猜測內核任務埠所在的頁面,每個懸掛埠的上下文值設置為包含內核任務埠的頁面上每個潛在ipc_port 的地址,並且OOL埠在用戶空間中被接收回去,以向內核任務埠提供發送許可權。

參考:mach_portal利用代碼。

iOS漏洞利用鏈1-iOS 10.1.1

由Google威脅分析小組的ClémentLecigne(@ _clem1)在野外發現。由Google Project Zero 的Ian Beer和SamuelGro?(@ 5aelo)分析。

漏洞:漏洞是IOKit函數AGXAllocationList2 :: initWithSharedResourceList()中IOAccelResource 指針的線性堆越界寫入。

利用策略:要溢出的緩衝區直接放置在recv_msg_elem 結構之前,這樣越界寫操作將使用IOAccelResource 指針覆蓋uio 指針。所述IOAccelResource 指針被釋放並用重新分配的 UIO 在開始結構OSDATA 數據緩衝器來管理IOSurface 。該UIO 被釋放,留下一個懸空OSDATA 數據經由緩衝訪問IOSurface 。

後續的利用流程:懸空的OSData 數據緩衝區通過IOSurfaceRootUserClient 實例重新分配,並且數據內容通過IOSurface 屬性讀取,以提供KASLR保護,當前任務的地址以及懸空數據緩衝區/ IOSurfaceRootUserClient 的地址。然後,釋放數據緩衝區並使用IOSurfaceRootUserClient 的patch版本進行重新分配,這樣,在修改的用戶客戶端上調用外部方法將返回從內核的__DATA 段讀取的內核任務的地址。數據緩衝區被釋放並再次重新分配,以便調用外部方法將執行OSSerializer :: serialize()gadget,導致任意讀寫後將內核任務埠的地址存儲在當前任務的特殊埠列表中。從用戶空間讀取特殊埠將向內核任務埠發送許可權。

參考:iOS漏洞利用鏈1-AGXAllocationList2 :: initWithSharedResourceList堆溢出。

extra_recipe-iOS 10.2

伊恩·比爾(Ian Beer)。

漏洞:CVE-2017-2370是線性堆緩衝區溢出,可通過XNU的mach_voucher_extract_attr_recipe_trap()中的非特權上下文來實現,這是由於攻擊者控制的用戶空間指針用作對copyin()的調用中的長度。

利用策略:調用易受攻擊的Mach陷阱來創建kalloc 分配,並立即用受控數據溢出該kalloc 分配,從而破壞了後續ipc_kmsg 對象的ikm_size 欄位。這導致ipc_kmsg,它是Mach埠的預分配消息,認為它具有比其更大的容量,並將其與後續分配的前240個位元組重疊。通過將Mach埠註冊為用戶空間線程的異常埠,然後以受控的寄存器狀態使線程崩潰,可以重複且可靠地覆蓋後續分配的重疊部分,並且通過接收異常消息,可以讀取這些位元組。這樣就可以在損壞 ipc_kmsg 末尾提供一個受控的240位元組越界讀/寫原語。

後續漏洞利用流程:在漏洞函數之後放置另一個ipc_kmsg,並對其進行讀取,以確定分配的地址。接下來,將AGXCommandQueue 用戶客戶端重新分配到同一內存中,並讀取虛擬方法表以確定KASLR。然後,將覆蓋虛函數表,以使AGXCommandQueue 上的虛函數調用將調用OSSerializer :: serialize()gadget,從而生成2參數的任意內核函數調用原語。調用函數uuid_copy()給出任意內核讀/寫原語。

參考:iOS上的面向異常的利用,extra_recipe利用代碼。

Yalu102-iOS 10.2

由Luca Todesco(@qwertyoruiopz)和Marco Grassi(@marcograss)撰寫。

漏洞:CVE-2017-2370(與上面相同)。

利用策略:易受攻擊的Mach陷阱被調用以創建kalloc 分配,並立即用受控數據溢出它,覆蓋OOL埠數組的內容,並在用戶空間中插入指向偽造的Mach埠的指針。接收包含OOL埠的消息會產生對偽造的Mach埠的發送權,該偽造的Mach埠的內容可以直接控制。

後續利用流程:偽造的Mach埠被轉換為時鐘埠,而clock_sleep_trap()用於對內核映像指針進行暴力破解。然後將埠轉換為偽任務埠,以通過pid_for_task()讀取內存。從泄漏的內核映像指針向後掃描內核內存,直到找到內核文本庫為止,這會破壞KASLR。最後,構建一個偽內核任務埠。

注意:該漏洞利用不適用於啟用PAN的情況。

參考:Yalu102漏洞利用代碼。

ziVA-iOS 10.3.1

Zimperium的Adam Donenfeld(@doadam)。

漏洞:在多個漏洞AppleAVE2 由於外部方法分享IOSurface 與用戶空間的指針和信任IOSurface 指針從用戶空間讀取。

利用策略:創建一個IOSurface 對象,並調用AppleAVE2 外部方法以泄漏其地址。iofence 在指針IOSurface 使用泄露另一個外部方法調用,打破KASLR。所述IOSurface 對象被釋放,並與使用控制的數據重新分配IOSurface 屬性堆噴。將泄漏的指針提供給信任從用戶空間提供的IOSurface 指針的AppleAVE2 外部方法,可以劫持偽造的IOSurface 上的虛函數調用;這被視為在已知地址用受控目標對象進行的oneshot劫持虛函數調用。

後續的利用流程:被劫持的虛函數調用與OSSerializer :: serialize()gadget一起使用,以調用copyin()並覆蓋2個sysctl_oid 結構。sysctls被覆蓋,因此讀取第一個sysctl會調用copyin()來更新第二個sysctl的函數指針和參數,而讀取第二個sysctl則使用OSSerializer :: serialize()gadget來調用帶有3個參數的內核函數。這個3參數的任意內核函數調用原語用於通過調用copyin()/ copyout()來讀寫任意內存。

注意:iOS 10.3引入了task_conversion_eval()的初始形式,這是一種較弱的緩解措施,它阻止用戶空間訪問實際內核任務埠的許可權。iOS 10.3之後的任何漏洞利用都需要構建偽造的內核任務埠。

參考:Ro(o)tten apple,ziVA漏洞利用代碼。

async_wake-iOS 11.1.2

伊恩·比爾(Ian Beer)。

漏洞:CVE-2017-13861是IOSurfaceRootUserClient :: s_set_surface_notify()中的漏洞,該漏洞導致在Mach埠上刪除了額外的引用。CVE-2017-13865是XNU的proc_list_uptrs()中的一個漏洞,該漏洞通過在將內容複製到用戶空間之前無法完全初始化堆內存來泄漏內核指針。

利用策略:信息泄漏用於發現任意Mach埠的地址。將分配埠頁面,並根據其地址從該頁面中選擇特定埠,使用IOSurfaceRootUserClient 錯誤將埠釋放,從而產生對懸掛的Mach埠的已知(部分受控)地址的接收。

後續利用流程:釋放該頁面上的其他埠,並強制進行區域垃圾回收,以便使用ipc_kmsg 的內容重新分配該頁面,從而在已知地址處提供一個偽造的Mach埠,其內容受控制。重新分配將埠轉換為偽任務埠,可以使用pid_for_task()讀取任意內核內存。(使用mach_port_set_context()無需重新分配偽埠即可更新要讀取的地址。)使用內核讀取原語定位相關的內核對象,並使用偽內核任務埠再次分配偽埠。

注意:iOS 11刪除了mach_zone_force_gc()函數,該函數允許用戶空間提示內核執行區域垃圾回收,從而回收區域圖中所有可用的虛擬頁面供其他區域使用。iOS 11及更高版本的漏洞需要開發一種技術來強制區域垃圾回收。為此,至少開發了三種獨立的技術,在async_wake,v0rtex和In-the-wild iOS利用鏈3中得到了證明。

參考:async_wake漏洞利用代碼。

iOS漏洞利用鏈2-iOS 10.3.3

由克萊門特·萊西尼(ClémentLecigne)在野外發現。由Ian Beer和SamuelGro?分析。

漏洞:CVE-2017-13861(與上面相同)。

利用策略:兩個Mach埠,埠A和埠B,作為堆噴的一部分分配。觸發該漏洞後,將丟棄對埠A的引用,並釋放了A周圍的埠,從而導致埠指針懸空。通過調用mach_zone_force_gc()強制進行區域垃圾回收,並使用包含模式的OOL埠堆噴重新分配包含埠A的頁面,該模式包含以下模式:埠A的ip_context 欄位與指向埠B的指針重疊。調用mach_port_get_context()給出埠B的地址。漏洞再次通過埠B觸發,從而導致在已知地址懸掛Mach埠的接收權。

後續的利用流程:在另一個區域垃圾回收之後,使用分段的OOL內存堆噴重新分配了懸空的埠B,以便調用mach_port_get_context()可以識別堆噴重新分配的埠B的哪個4 MB段。該段已釋放,並且埠B被重新分配了使用管道緩衝區,在已知地址提供受控的偽造Mach埠。偽埠轉換為時鐘埠,而clock_sleep_trap()用於強行使用KASLR。接下來將偽埠轉換為偽任務埠,並使用pid_for_task()建立4位元組內核讀取原語。最後,將偽埠轉換為偽內核任務埠。

參考資料:iOS漏洞利用鏈2-IOSurface。

v0rtex-iOS 10.3.3

通過Siguza(@ S1guza)。

漏洞:CVE-2017-13861(與上面相同)。

利用策略:對該埠進行了堆噴,並丟棄了一個埠上的引用。頁面上的其他埠被釋放,留下懸掛的Mach埠的接收權。

後續漏洞利用流程:使用mach_zone_force_gc()強制進行區域垃圾回收,並通過IOSurface 屬性Spray 用OSString 緩衝區重新分配包含懸空埠的頁面。所述OSString 緩衝區包含初始化埠的關鍵領域和允許的索引圖案OSString 包含埠通過調用來確定mach_port_get_context()假埠上。釋放包含偽埠的OSString 並將其重新分配為普通的Mach埠。調用mach_port_request_notification()將真實Mach埠的地址放入偽埠的ip_pdrequest中欄位,然後通過IOSurface 讀取OSString 的內容以獲取地址。再次使用mach_port_request_notification()獲取偽埠本身的地址。

釋放並重新分配字元串緩衝區,以便可以將mach_port_get_attributes()用作4位元組的任意讀取原語,並且目標地址可以通過mach_port_set_context()進行讀取更新。(這類似於pid_for_task()技術,但約束條件略有不同。)從實際Mach埠的地址開始,讀取內核內存以查找相關的內核對象。使用偽造的任務埠釋放並重新分配字元串緩衝區,足以將字元串緩衝區重新映射到進程的地址空間。通過映射更新偽埠,以使用iokit_user_client_trap()產生7參數的任意內核函數調用原語和調用內核函數生成偽造的內核任務埠。

參考:v0rtex編寫,v0rtex利用代碼。

CVE-2018-4150 bpf-filter-poc的利用-iOS 11.2.6

漏洞分析和POC,由Corellium的Chris Wade(@cmwdotme)提供,由littlelailo(@littlelailo)利用。

漏洞:CVE-2018-4150是XNU BPF子系統中的競爭條件,由於在不重新分配相應緩衝區的情況下增加了緩衝區長度,導致線性堆緩衝區溢出。

漏洞利用策略:條件競爭被觸發以錯誤地增加緩衝區的長度,而不重新分配緩衝區本身。發送數據包並將其存儲在緩衝區中,溢出到後續的OOL埠數組中,並在用戶空間中插入指向偽造的Mach埠的指針。接收包含OOL埠的消息會產生對偽造的Mach埠的發送權,該偽造的Mach埠的內容可以直接控制。

後續利用流程:偽造的Mach埠被轉換為時鐘埠,而clock_sleep_trap()用於對內核映像指針進行暴力破解。然後將埠轉換為偽任務埠,以通過pid_for_task()讀取內存。從泄漏的內核映像指針向後掃描內核內存,直到找到內核文本庫為止,這會破壞KASLR。漏洞利用的最後部分還不完整,但是在此階段使用現有代碼可以簡單,確定性地構建偽內核任務埠。

注意:該漏洞利用不適用於啟用PAN的情況。

參考文獻:CVE-2018-4150 POC,針對CVE-2018-4150-bpf-filter-poc的不完全利用漏洞利用代碼。

multi_path-iOS 11.3.1

伊恩·比爾(Ian Beer)。

漏洞:CVE-2018-4241是XNU的mptcp_usr_connectx()中的對象內線性堆緩衝區溢出,原因是邊界檢查不正確。

利用策略:整理內核堆,以將2048位元組ipc_kmsg 結構放置在與幾個多路徑TCP套接字關聯的mptses 結構(包含溢出的對象)下方的16 MB對齊地址上。該漏洞用於使用零覆蓋mptses 結構中mpte_itfinfo 指針的低3個位元組,並且套接字已關閉。這將觸發損壞指針的kfree(),從而在16 MB對齊邊界處釋放ipc_kmsg 結構。釋放的ipc_kmsg 插槽已通過堆噴的管道緩衝區重新分配。再次觸發該漏洞以覆蓋mpte_itfinfo 的低3個位元組另一個具有零的mptses 結構中的指針,並且套接字被關閉,導致另一個具有相同地址的kfree()。這將釋放剛分配到該插槽中的管道緩衝區,從而留下一個懸空的管道緩衝區。

後續利用流程:使用預先分配的ipc_kmsg 重新分配插槽。用戶空間線程崩潰,導致消息存儲在與管道緩衝區重疊的預分配ipc_kmsg 緩衝區中;讀取用戶空間中的管道會產生ipc_kmsg 結構的內容,並給出懸空管道緩衝區/ ipc_kmsg 的地址。寫入管道是為了更改ipc_kmsg 結構的內容,以便接收消息會產生對管道緩衝區內偽造的Mach埠的發送權。接收到異常消息,並使用pid_for_task()將管道重寫以將偽埠轉換為內核讀取原語。找到相關的內核對象,並將偽埠轉換為偽內核任務埠。

參考:multi_path漏洞利用代碼。

multipath_kfree-iOS 11.3.1

由John?kerblom(@jaakerblom)。

漏洞:CVE-2018-4241(與上面相同)。

開發策略:內核堆預先分配的4096位元組ipc_kmsg 結構附近的mptses 結構的幾個TCP套接字。觸發該漏洞兩次,以破壞兩個mptses 結構中mpte_itfinfo 指針的低2個位元組,從而關閉套接字會導致兩個損壞的指針的kfree()。每個指針已損壞指向0x7a0 位元組到ipc_kmsg 分配,產生4096位元組的2個消息。包含部分釋放的ipc_kmsg 結構之一(帶有ipc_kmsg的Mach埠)通過使用mach_port_peek()來檢測損壞的msgh_id 欄位,找到了完整的標頭,但釋放了郵件內容)。找到埠後,通過堆噴預分配的ipc_kmsg 結構來重新分配孔,並在每個結構中放置一條消息。填充孔與替換部分的ipc_kmsg 標頭重疊在原始ipc_kmsg 的Mach消息內容(部分釋放)上,以便在原始埠上接收消息會讀取替換ipc_kmsg 標頭的內容。標頭包含一個指向自身的指針,該指針公開了替換的地址ipc_kmsg分配。再次觸發該漏洞以釋放替換消息,從而將部分釋放的預分配ipc_kmsg保留在已知地址處。

後續攻擊流程:通過堆噴AGXCommandQueue 用戶客戶端來重新分配損壞的ipc_kmsg 中的漏洞。在用戶空間中的Mach埠上收到一條消息,該消息複製了AGXCommandQueue 對象的內容,使用該vtable可以從中確定KASLR保護。然後,通過堆噴更多預分配的ipc_kmsg 結構,並以稍微不同的內部布局釋放並重新分配已損壞的ipc_kmsg,從而對內容進行更多控制。一條消息放置在每個剛剛堆噴的ipc_kmsg 結構中,以修改重疊的AGXCommandQueue 並劫持虛擬方法調用。被劫持的虛擬方法使用OSSerializer :: serialize()gadget調用copyout(),該工具用於識別哪個堆噴的AGXCommandQueue 用戶客戶端與損壞的ipc_kmsg中的插槽重疊。依次更新每個剛剛分配的ipc_kmsg 結構的內容,以標識哪個埠與損壞的ipc_kmsg 相對應。通過發送到預分配埠的異常消息來更新AGXCommandQueue 對象的內容,將預分配埠和用戶客戶端埠一起使用以構建3參數的任意內核函數調用原語。

參考:multipath_kfree利用代碼。

empty_list-iOS 11.3.1

伊恩·比爾(Ian Beer)。

漏洞:CVE-2018-4243是由於不正確的邊界檢查而在XNU的getvolattrlist()中部分控制的8位元組堆越界寫入。

利用策略:由於重大的觸發約束,此漏洞被視為在kalloc.16 分配結束時對8個位元組的堆進行了越界寫入。內核堆被整理為kalloc.16 和ipc.ports 區域的交替塊模式,進一步的整理將逆向kalloc.16 free表。釋放各種kalloc.16 分配之後,重複觸發該漏洞,直到塊末尾的kalloc.16 分配溢出,從而破壞了後續頁面上第一個ipc_port 的前8個位元組。通過調用mach_port_set_attributes()釋放損壞的埠,留下持有接收權的程序。

後續利用流程:強制進行區域垃圾回收,並使用OOL ports數組重新分配懸空埠,該數組包含指向與ip_context 欄位重疊的另一個Mach埠的指針,以便通過調用mach_port_get_context()檢索另一個埠的地址。然後使用管道緩衝區重新分配懸空的埠,並使用pid_for_task()將其轉換為內核讀取原語。以另一個埠的地址為起點,找到相關的內核對象。最後,將偽埠轉換為偽內核任務埠。

參考:empty_list漏洞利用代碼。

iOS漏洞利用鏈3-iOS 11.4

由克萊門特·萊西尼(ClémentLecigne)在野外發現,由Ian Beer和SamuelGro?分析。

漏洞:由於未能清除釋放的指針,因此從AppleVXD393UserClient :: DestroyDecoder()可以雙重釋放。

利用策略:創建並釋放目標56位元組的分配,使懸空指針保持完整。使用IOSurface 屬性Spray 使用OSData 緩衝區重新分配插槽。再次調用易受攻擊的方法以釋放緩衝區,留下懸空的OSData 緩衝區。再次使用包含單個目標Mach埠指針的OOL埠數組重新分配該插槽,並通過IOSurface 屬性在用戶空間中讀取內容,從而生成埠的地址。再次調用易受攻擊的方法以釋放OOL埠,並使用另一個OSData 重新分配插槽包含兩個指向Mach埠的指針的緩衝區。存放OOL描述符的存放埠被破壞,丟棄了對Mach埠的兩個引用。這樣就使該過程具有在已知地址懸掛Mach埠的接收權。

後續利用流程:執行區域垃圾回收,並使用分段的OOL內存堆噴重新分配懸空的埠,以便調用mach_port_get_context()可以標識堆噴的哪一部分重新分配了埠。釋放該段,並使用管道緩衝區重新分配懸空埠,從而在已知地址處提供受控的偽造Mach埠。偽埠轉換為時鐘埠,而clock_sleep_trap()用於強行使用KASLR。接下來,將偽埠轉換為偽任務埠,並使用pid_for_task()建立內核讀取原語。最後,將偽埠轉換為偽內核任務埠。

參考:iOS漏洞利用鏈3-XPC VXD393 / D5500 IOFree。

Spice-iOS 11.4.1

Synacktiv的Luca Moro(@JohnCool__)進行漏洞分析和POC 。由Siguza,Viktor Oreshkin(@ stek29),Ben Sparkes(@iBSparkes)和littlelailo進行利用。

漏洞:「 LightSpeed」漏洞(可能是CVE-2018-4344)是XNU的lio_listio()中的一種競爭狀況,原因是狀態管理不當導致UAF。

利用策略:在一個線程的循環中調用易受攻擊的函數,以通過從kalloc.16 分配一個緩衝區並競速兩次釋放該緩衝區來反覆觸發該漏洞。另一個線程重複發送一條消息,其中包含從kalloc.16 分配的OOL埠數組,立即通過IOSurface 屬性將大量kalloc.16 分配包含指向用戶空間中偽造的Mach埠的指針,並接收OOL埠。當競爭成功時,雙釋放會導致OOL埠陣列被釋放,並且隨後的噴射可能會使用偽造的OOL埠陣列重新分配插槽。在用戶空間中接收OOL埠會給出一個獲得對偽造的Mach埠的權利,該埠的內容可以直接控制。

後續漏洞利用流程:第二個Mach埠在偽埠上註冊為通知埠,在偽埠的ip_pdrequest 欄位中公開了第二個埠的地址。使用mach_port_get_attributes()修改了偽埠,以構造內核讀取原語。從公開的埠指針開始,讀取內核存儲器以找到相關的內核對象。使用iokit_user_client_trap()將偽埠轉換為偽用戶客戶端埠,從而提供7參數的任意內核函數調用原語。最後,構建一個偽內核任務埠。

注意:該漏洞利用不適用於啟用PAN的情況。

分析是對文件pwn.m中的實現進行的,因為這似乎可以與該列表中的其他漏洞利用實現進行最直接的比較。

參考資料:LightSpeed,iOS / macOS沙箱逃逸,Spice利用代碼。

footm1ll-iOS 11.4.1

Luca Moro的漏洞分析和POC。由Tihmstar(@tihmstar)利用。

漏洞:「 LightSpeed」漏洞(與上面相同)。

利用策略:在一個線程的循環中調用易受攻擊的函數,以通過從kalloc.16 分配一個緩衝區並競速兩次釋放該緩衝區來反覆觸發該漏洞。另一個線程發送固定數量的消息,其中包含從kalloc.16 分配的OOL埠數組。當競爭成功時,兩次釋放會導致OOL埠數組釋放,從而在某些消息中留下懸空的OOL埠數組指針。第一個線程停止觸發漏洞,並創建了大量IOSurface 對象。依次接收每個消息,並使用IOSurface 噴射大量kalloc.16 分配,其中包含指向用戶空間中偽造的Mach埠的指針屬性。每次堆噴都可以使用虛假的OOL埠陣列從懸空的OOL埠陣列重新分配插槽。成功接收用戶空間中的OOL埠將為偽造的Mach埠提供接收權,該偽造的Mach埠可以直接控制其內容。

後續漏洞利用流程:第二個Mach埠在偽埠上註冊為通知埠,在偽埠的ip_pdrequest 欄位中公開了第二個埠的地址。使用pid_for_task()修改了假埠,以構造內核讀取原語。從公開的埠指針開始,讀取內核存儲器以找到相關的內核對象。使用iokit_user_client_trap()將偽埠轉換為偽用戶客戶端埠,從而提供7參數的任意內核函數調用原語。最後,構建一個偽內核任務埠。

注意:該漏洞利用不適用於啟用PAN的情況。

參考資料:LightSpeed,一個iOS / macOS沙箱逃逸,漏洞利用代碼。

Chaos - iOS 12.1.2

奇虎360 Vulcan Team的Zhao Qixun Zhao(@ S0rryMybad)。

由於XNU的task_swap_mach_voucher()無法遵守MIG生存期語義,導致在ipc_voucher 對象上添加或刪除了額外的引用,因此漏洞CVE-2019-6225可以UAF。

利用策略:噴射了大量ipc_voucher 對象,並且觸發了兩次漏洞,以減少憑證上的引用計數並將其釋放。頁面上的其餘內存將被釋放,並強制進行區域垃圾回收,將懸空的ipc_voucher 指針留在線程的**ith_voucher** 欄位中。

後續利用流程:懸掛的憑證由OSString 緩衝區使用IOSurface 屬性Spray 重新分配。調用thread_get_mach_voucher()以獲得到該憑證的新分配的憑證埠的發送權,這導致指向該憑證埠的指針存儲在與OSString 緩衝區重疊的偽憑證中;讀取OSString 屬性將顯示憑證埠的地址。所述OSString 重疊假憑證被釋放並具有大堆噴,這兩個在硬編碼的地址包含一個假的Mach埠控制的數據的分配,並更新假的重新分配iv_port指向偽造的埠的指針。再次調用thread_get_mach_voucher()以獲得對假埠的發送權,並標識哪個OSString 緩衝區包含假Mach埠。這樣,該進程就可以向**IOSurface** 屬性緩衝區中**的偽造的Mach埠發送許可權,該埠位於已知地址(大致等效於懸掛的Mach埠)。通過重新分配OSString 緩衝區以將偽埠轉換為偽任務埠並調用pid_for_task()來構建內核讀取原語。讀取任意內存。找到相關的內核對象,並將偽埠轉換為偽映射埠,以將偽埠重新映射到用戶空間,從而無需重新分配它。最後,偽埠被轉換為偽內核任務埠。

注意:A12引入了PAC,它限制了使用某些涉及代碼指針的利用技術的能力(例如,vtable劫持)。此外,iOS 12在ipc_port_finalize()中引入了緩解措施,以防止在埠處於活動狀態時釋放埠(即,埠未被破壞,例如,因為進程仍擁有該埠的權利)。這改變了過去漏洞利用的通用結構,即在某個進程仍保留其使用權的同時,該埠將被釋放。結果,在iOS 12 漏洞利用中獲得假埠的權利似乎比早期漏洞利用的發生晚。

參考:IPC憑證UaF遠程越獄階段2(EN)。

voucher_swap-iOS 12.1.2

由Google Project Zero的Brandon Azad(@_bazad)提供。

漏洞:CVE-2019-6225(與上面相同)。

利用策略:對內核堆進行修飾,以將ipc_port 分配塊直接放在管道緩衝區塊之前。噴射了大量ipc_voucher 對象,並觸發該漏洞以減少憑證上的引用計數並釋放它。頁面上的其餘憑單將被釋放,並強制進行區域垃圾回收,將懸空ipc_voucher 指針留在線程的ith_voucher欄位中。

後續利用流程:懸空的憑證通過OOL ports數組進行重新分配,該數組包含指向先前分配的ipc_port 的指針,該指針與憑證的iv_refs 欄位重疊。通過調用thread_get_mach_voucher()來檢索憑證埠的發送權,並通過重複調用易受攻擊的函數來更新憑證的引用計數,從而更新重疊的ipc_port 指針以指向管道緩衝區。接收OOL埠會產生對偽造的Mach埠的發送權,該埠的內容可以直接控制。調用mach_port_request_notification()以插入指向包含偽造埠中另一個Mach埠的指針的數組的指針ip_requests 欄位。使用pid_for_task()構建內核讀取原語,並讀取另一個Mach埠的地址以計算假埠的地址。找到相關的內核對象,並構建偽造的內核任務埠。

參考文獻:voucher_swap:在iOS的12 MIG環境與開發引用計數,voucher_swap攻擊代碼。

MachSwap-iOS 12.1.2

本·斯帕克斯(Ben Sparkes)。

漏洞:CVE-2019-6225(與上面相同)。

利用策略:噴射了大量ipc_voucher 對象,並且觸發了兩次漏洞,以減少憑證上的引用計數並將其釋放。頁面上的其餘憑單將被釋放,並強制進行區域垃圾回收,將懸空的ipc_voucher 指針留在線程的ith_voucher 欄位中。

後續利用流程:懸空憑證由OSString 緩衝區重新分配,該緩衝區包含使用IOSurface 屬性Spray 指向用戶空間中虛假埠的虛假憑證。調用thread_get_mach_voucher()以獲得對偽造憑證埠的發送權,從而產生對偽造Mach埠的發送權,該偽造Mach埠的內容可以直接控制。一條消息被發送到假埠,以泄露ipc_kmsg 對象的地址。使用pid_for_task()構建內核讀取原語,並且從公開的指針開始定位相關的內核對象。最終,構建了偽造的內核任務埠。

注意:該漏洞利用不適用於啟用PAN的情況。

參考文獻:MachSwap:在iOS 12內核漏洞,machswap攻擊代碼。

iOS漏洞利用鏈5-iOS 12.1.2

由克萊門特·萊西尼(ClémentLecigne)在野外發現。由Ian Beer和SamuelGro?分析。

漏洞:CVE-2019-6225(與上面相同)。

利用策略:噴射了大量ipc_voucher 對象,並觸發該漏洞以減少憑證上的引用計數並釋放它。頁面上的其餘憑單將被釋放,並強制進行區域垃圾回收,將懸空的ipc_voucher指針留在線程的ith_voucher 欄位中。

後續利用流程:懸空的憑證由OOL內存堆噴重新分配。分配了大量的Mach埠,然後調用thread_get_mach_voucher()以獲得針對該憑證的新分配的憑證埠的發送權,這導致指向該憑證埠的指針存儲在與OOL埠數組重疊的偽憑證中。分配了更多的埠,然後接收OOL內存噴射,公開了偽造憑證的憑證埠地址。懸掛的憑證再次與另一個OOL內存噴射重新分配,該更新更新了憑證的iv_port指向下一頁的指針。Mach埠被破壞,區域垃圾被強行回收,偽造的憑證只剩下一個指向懸掛埠的指針。懸掛的埠通過管道緩衝區重新分配。最後,調用thread_get_mach_voucher(),以將偽造的Mach埠發送到已知地址的發送權,該地址的內容可以直接控制。偽埠轉換為偽任務埠,並使用pid_for_task()建立內核讀取原語。找到相關的內核對象,並將偽埠轉換為偽內核任務埠。

參考:iOS漏洞利用鏈5-task_swap_mach_voucher。

iOS漏洞利用鏈4-iOS 12.1.3

由克萊門特·萊西尼(ClémentLecigne)在野外發現。由Ian Beer和SamuelGro?分析,還由一位匿名研究人員分析。

漏洞CVE-2019-7287是由於未選中memcpy()導致IOKit函數ProvInfoIOKitUserClient :: ucEncryptSUInfo()中的線性堆緩衝區溢出。

利用策略:整理內核堆,以在OOL埠數組之前的kalloc.4096 中放置,在通過IOSurface 屬性訪問的OSData 緩衝區之前的kalloc.6144中放置。該漏洞被觸發與從分配源kalloc.4096 並從所分配的目的地kalloc.6144 ,使目標Mach埠的地址被複制到OSDATA 緩衝器。然後OSDATA的緩衝器被讀出,公開的目標埠的地址。再次整理堆以在OOL內存緩衝區之前的kalloc.4096 和kalloc.6144中放置在OOL埠數組之前。再次觸發該漏洞,將指向目標埠的指針插入OOL埠數組。釋放目標埠,並強制進行區域垃圾回收,在OOL ports數組中留下一個懸空的埠指針。懸空的埠通過管道緩衝區重新分配,並且OOL埠被接收,從而為已知地址的偽Mach埠提供了接收權,該偽造的Mach埠的內容可以直接控制。

後續利用流程:虛假埠被轉換為虛假時鐘埠,而clock_sleep_trap()用於強行使用KASLR。偽埠轉換為偽任務埠,並使用pid_for_task()建立內核讀取原語。找到相關的內核對象,並將偽埠轉換為偽內核任務埠。

參考:iOS漏洞利用鏈4-cfprefsd ProvInfoIOKit,關於iOS 12.1.4的安全性內容。

攻擊iPhone XS Max-iOS 12.1.4

王鐵磊(@wangtielei)和徐昊(@windknown)。

漏洞:該漏洞是XNU UNIX域套接字綁定實現中的競爭條件,這是由於臨時解鎖反模式導致了「UaF」。

利用策略:噴射套接字,並觸發漏洞,以使指針指向vnode 結構中懸空的套接字指針。關閉套接字,強制進行區域垃圾回收,並通過OSData 堆噴(可能是IOSurface 屬性堆噴)用受控數據重新分配套接字。偽套接字被構造為具有0的引用計數。觸發使用後釋放來調用偽套接字上的socket_unlock(),這將導致偽套接字/ OSData 緩衝區使用kfree()釋放。這樣就留下了懸掛的OSData緩衝區,可以使用未指定的方式進行訪問。

後續利用流程:懸空的OSData 緩衝區通過OOL ports數組進行重新分配,並且OSData 緩衝區被釋放,剩下懸空的OOL ports數組。噴射內核內存以將偽造的Mach埠放置在硬編碼地址上(或使用了信息泄漏),並且OOL埠陣列與另一個OSData 緩衝區重新分配,將指向偽造的Mach埠的指針插入到OOL埠陣列中。接收OOL埠,從而在已知地址向偽Mach埠發送或接收許可權,偽埠通過未指定的方式轉換為偽內核任務埠。

注意:此漏洞的唯一參考是BlackHat演示,因此上面解釋存在不確定性。

作者開發了此漏洞利用的兩個版本:一個用於非PAC設備,一個用於支持PAC的設備。此處介紹的漏洞利用是針對啟用PAC的設備的。non-PAC漏洞利用實際上更簡單(劫持socket_lock()使用的函數指針)。

參考:攻擊iPhone XS Max。

SockPuppet-iOS 12.2和iOS 12.4

由Ned Williamson(@nedwilliamson)與Google Project Zero合作。

該漏洞:CVE-2019-8605是一個由於XNU的in6_pcbdetach()未能清除釋放指針的UaF漏洞。

利用策略:在漏洞之上構造了任意讀取,任意的kfree()和任意的Mach埠地址公開原語。

任意讀取原語:多次觸發該漏洞以創建許多與套接字關聯的ip6_pktopts 懸空結構。懸空的ip6_pktopts 通過IOSurface 屬性通過OSData 緩衝區spray 重新分配,使得ip6po_minmtu 設置為已知值,而ip6po_pktinfo 設置為要讀取的地址。所述ip6po_minmtu 欄位經由檢查的getsockopt() ,以及如果正確的話,的getsockopt(IPV6_PKTINFO)被調用來讀取20個位元組的數據的地址所指向的ip6po_pktinfo 。

任意kfree()原語:漏洞被多次觸發以創建許多與套接字關聯的ip6_pktopts 懸空結構。懸空的ip6_pktopts 通過IOSurface 屬性使用OSData 緩衝區Spray 重新分配,使得ip6po_minmtu 設置為已知值,而ip6po_pktinfo 設置為可用地址。所述ip6po_minmtu 欄位經由檢查的getsockopt() ,以及如果正確的話,setsockopt的(IPV6_PKTINFO)被調用來調用kfree_addr()在ip6po_pktinfo 指針。

任意Mach埠地址公開原語:漏洞被多次觸發以創建許多與套接字關聯的ip6_pktopts 懸空結構。懸空的ip6_pktopts 使用包含指向目標埠的指針的OOL埠數組spray重新分配。的ip6po_minmtu 和ip6po_prefer_tempaddr 欄位經由讀取的getsockopt(),公開目標埠指針的值。使用任意讀取原語檢查埠是否為預期類型。

後續利用流程:Mach埠地址公開原語用於公開當前任務的地址。創建了兩個管道,並使用內核讀取原語找到了內核中管道緩衝區的地址。找到了相關的內核對象,並在管道緩衝區之一中構造了偽內核任務埠。任意kfree()原語用於釋放另一個管道的管道緩衝區,並且通過堆噴OOL埠數組來重新分配管道緩衝區。然後寫入管道,以將指向偽內核任務埠的指針插入OOL埠數組,然後接收OOL埠,從而生成偽內核任務埠。

注意:與該列表中的大多數其他利用線性結構的漏洞利用不同,SockPuppet是按層次結構進行構建的,並始終基於相同的原語。這種獨特的結構可能是由於潛在漏洞的強大函數和穩定性所致:該錯誤直接提供了任意讀取和任意免費的原語,並且在實踐中,這兩個原語都是100%安全可靠的,因為可以檢查重新分配是成功的。但是,這種結構意味著在特定於漏洞的利用與通用利用之間的高級利用流程中沒有明確的時間邊界。相反,該邊界出現在漏洞利用代碼中的概念層之間。

SockPuppet錯誤已在iOS 12.3中修復,但在iOS 12.4中已重新引入。

參考:SockPuppet:適用於iOS 12.4的內核漏洞利用,SockPuppet利用代碼。

oob_timestamp-iOS 13.3

布蘭登·阿扎德(Brandon Azad)。

漏洞:CVE-2020-3837是由於不正確的邊界檢查而導致在IOKit的IOAccelCommandQueue2 :: processSegmentKernelCommand()中對多達8個位元組的時間戳數據進行線性堆越界寫入。

利用策略:整理內核映射以布置兩個96 MB的共享內存區域,一個8頁的ipc_kmsg ,一個8頁的OOL埠陣列和80 MB的OSData 緩衝區(通過IOSurface 屬性堆噴)。根據當前時間計算要溢出的位元組數,並觸發溢出以破壞ipc_kmsg 的ikm_size 欄位,這樣ipc_kmsg 的大小現在在16頁至80 MB之間。包含ipc_kmsg 的埠被銷毀,釋放了損壞的ipc_kmsg ,OOL埠數組以及一些後續的OSData 緩衝區。更多OSData通過IOSurface 噴射緩衝區,以重新分配OOL埠陣列,該陣列包含一個指向偽埠的指針,該指針位於可能與96 MB共享內存區域之一重疊的硬編碼地址上。接收OOL埠,從而對已知地址的偽Mach埠產生接收權,該地址的內容可以直接控制。

後續利用流程:使用pid_for_task()構造內核內存讀取原語,找到相關的內核對象,並構建偽造的內核任務埠。

注意:iOS 13引入了zone_require,這是一個緩解措施,可在使用某些對象之前檢查是否從預期的zalloc 區域中分配了某些對象。當對象在zalloc_map 之外分配時,實現中的疏忽導致了繞過。

參考:oob_timestamp利用代碼。

0x03 iOS內核利用緩解措施

接下來,我們將介紹一些當前的iOS內核利用緩解措施。此列表並不詳盡,但簡要總結了利用開發人員可能會在iOS 13上遇到的一些緩解措施。

Kernel Stack Canaries - iOS 6

iOS 6引入了內核堆棧Canaries(或堆棧Cookie),以防止內核中的堆棧緩衝區溢出。列表中的漏洞均不受堆棧金絲雀的影響,因為它們不針對堆棧緩衝區溢出漏洞。

Kernel ASLR-iOS 6

內核地址空間布局隨機化(內核ASLR或KASLR)是一種緩解措施,可在內核地址空間中將內核緩存映像的基地址隨機化。在實施內核ASLR之前,內核緩存映像中的內核函數和對象的地址始終位於固定地址。

繞過KASLR是所有現代iOS內核利用的標準步驟。

Kernel Heap ASLR-iOS 6

從iOS 6開始,各種內核堆區域的基址已被隨機化,這旨在減輕利用硬編碼地址確定對象分配位置的漏洞。

解決內核堆隨機化問題是現代iOS內核利用的標準步驟。通常,這涉及堆堆噴,即使沒有確切的地址,也要誘導內核分配大量數據以影響堆的形狀。同樣,可以利用許多漏洞來產生信息泄漏,從而泄露堆上相關內核對象的地址。

W ^ X / DEP-iOS 6

iOS 6還通過確保將內核頁面映射為可寫或可執行文件,而不是兩者(通常稱為「寫或執行」或「 W ^ X」)來引入大量內核地址空間。這意味著頁表不再將內核代碼頁映射為可寫,並且內核堆和堆棧也不再映射為可執行文件。(確保非代碼數據未映射為可執行文件通常被稱為數據執行保護或DEP。)

現代的公共iOS漏洞利用程序並沒有嘗試繞過W ^ X(例如,通過修改頁表和注入shellcode);相反,通過修改內核數據結構並執行代碼重用攻擊來實現利用。這主要是由於存在一種稱為KTRR的更強大的,硬體強制的W ^ X緩解。

PXN-iOS 7

蘋果的A7處理器是iPhone中的第一個64位ARMv8-A處理器。以前,iOS 6將內核和用戶地址空間分開,因此在正常的內核執行期間無法訪問用戶代碼和數據頁。隨著轉向64位,地址空間不再分開。因此,在頁表項中設置了「從不執行特權(PXN)」位,以確保內核無法執行駐留在用戶空間頁中的shellcode。

與W ^ X相似,由於對KTRR的更強保護,PXN作為防止跳轉到用戶空間shellcode的保護。

PAN-iOS 10

永不特權訪問(PAN)是一項ARMv8.1-A安全函數,可防止內核訪問用戶空間也可以訪問的虛擬地址。這用於防止內核取消攻擊者提供的指向用戶空間中數據結構的指針。它類似於某些Intel處理器上的Supervisor模式訪問阻止(SMAP)函數。

儘管以前沒有繞過 PAN ,但現代的公共iOS內核漏洞通常會通過將數據噴入內核然後學習數據地址來解決PAN問題。儘管最可靠的技術涉及公開插入內核的數據的地址,但是存在一些通常可以解決PAN的技術,例如堆噴足夠的數據以壓倒內核映射的隨機性,並強制將固定的硬編碼地址分配給受控數據。還存在其他用於在用戶空間和內核之間建立共享內存映射的原語,這些原語也可用於解決PAN。

KTRR-iOS 10

KTRR(可能是內核文本只讀區域,是Kernel Integrity Protection的一部分)是在Apple A10處理器(ARMv8.1-A)上引入的自定義硬體安全緩解措施。它是WMU保護的一種強大形式,由MMU和內存控制器在連續的單個內存範圍內實施,覆蓋內核高速緩存映像的只讀部分以及一些敏感數據結構(如頂級頁表和信任高速緩存) 。蘋果公司也將其稱為內核完整性保護(KIP)v1。

儘管之前兩次公開繞過KTRR ,但現代的公共iOS內核漏洞通常通過不操縱受KTRR保護的內存來繞過KTRR。

APRR-iOS 11

APRR(可能代表訪問保護重新路由或訪問許可權限制寄存器)是Apple A11和更高版本的CPU上的自定義硬體函數,可通過特殊寄存器間接訪問虛擬內存訪問許可權(通常在頁面的頁面表條目中指定),從而允許訪問可以按原子和按核心更改大頁面組的許可權。它通過將通常直接指定訪問許可權的PTE中的位轉換為包含真實訪問許可權的特殊寄存器的索引來工作。更改寄存器值會在具有相同訪問許可權索引的所有頁面上交換保護。APRR有點類似於較新的Intel處理器上可用的「內存保護密鑰」函數。

APRR本身不提供任何安全邊界,但是可以在一個地址空間內分割特權級別,PPL大量使用它在iOS內核中創建安全邊界。

PPL-iOS 12

PPL(頁面保護層)是基於APRR並依賴於KTRR的軟體層,旨在在內核讀/寫/執行與直接頁表訪問之間建立安全邊界。PPL的主要目標是防止攻擊者修改已進行代碼簽名的頁面(例如,使用內核讀/寫來覆蓋進程的可執行代碼)。這必然意味著PPL還必須保持對頁表的完全控制,並防止攻擊者映射敏感的物理地址,包括頁表,頁表元數據和IOMMU寄存器。

截至2020年5月,尚未公開繞過PPL。也就是說,到目前為止,現代iOS內核漏洞並未受到PPL的影響。

PAC-iOS 12

指針驗證碼(PAC)是一種ARMv8.3-A安全函數,它通過將指針值的加密簽名存儲在指針的高位來減輕指針篡改。Apple隨A12一起推出了PAC,並顯著增強了實現(與ARM標準相比),以抵禦使用內核讀/寫的攻擊者,儘管在大多數情況下它在函數上無法區分。蘋果的內核使用PAC來實現控制流完整性(CFI),從而在內核讀/寫和內核代碼執行之間設置了安全邊界。

儘管眾多公共旁路了iOS內核的基礎PAC-CFI的,PAC內核仍然是一種有效的緩解漏洞:它已嚴重製約了許多開發中的漏洞和緩解了利用技術。例如,過去的攻擊利用內核執行原語來構建內核讀/寫原語(例如,參見ziVA)。如果不先繞過PAC,就無法再在A12上使用。此外,IOKit中PAC保護的指針的廣泛使用使將許多錯誤轉化為有用的原語變得非常困難。考慮到IOKit中嚴重的安全問題的悠久歷史,這是一個巨大的勝利。

zone_require-iOS 13

zone_require是iOS 13中引入的一種軟體緩解措施,可在使用前添加檢查,以確保從預期的zalloc 區域分配了某些指針。iOS內核緩存中最常見的zone_require檢查是Mach埠。例如,每次ipc_port 鎖定時,都會調用zone_require()函數以檢查包含Mach埠的分配是否駐留在ipc.ports 區域中(例如,不包含通過kalloc()分配的OSData 緩衝區)。

由於偽造的埠是現代技術的組成部分,因此zone_require對其具有重大影響。像CVE-2017-13861(async_wake)漏洞上參考ipc_port 不再提供創建一個假的埠的直接路徑。雖然zone_require已被公開繞過,但該技術依然有效。

https://bugs.chromium.org/p/project-zero/issues/detail?id=1986#c5

參考及來源:https://googleprojectzero.blogspot.com/2020/06/a-survey-of-recent-ios-kernel-exploits.html?m=1

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

19個0 day漏洞影響數十億IoT設備
谷歌移除上百個Chrome擴展,曾進行大規模監控活動