作者:蒸米
0x00 序
Ian Beer@google 發布了 CVE-2017-7047 Triple_Fetch 的 exp 和 writeup,chenliang@keenlab 也發表了一篇關于 Triple_Fetch 的分析,由于這個漏洞和 exp 有非常多的亮點,所以還剩很多可以深入挖掘的細節。因此,我們簡單分析一下漏洞形成的原因,并具體介紹一下漏洞利用的細節,以及如何利用這個漏洞做到 iOS 10.3.2 上的沙盒逃逸。
0x01 CVE-2017-7047 Triple_Fetch 漏洞形成的原因

因為 chenliang 對漏洞成因的分析非常詳細,這里我就簡單描述一下,因為使用 XPC 服務傳輸大塊內存的話很影響效率,蘋果為了減少傳輸時間,對大于 0x4000 的 OS_xpc_data 數據會通過 mach_vm_map 的方式映射這塊內存,然后將這塊數據的 send right 以 port 的方式發送到另一方。但這段內存的共享是基于共享物理頁的方式,也就是說發送方和接收方會共享同一塊內存,因此我們將數據發送以后再在發送端對數據進行修改,接收方的數據也會發生變化。
因此通過 race condition,可以讓接收端得到不同的數據(接收端認為是相同的數據),如果接收端沒有考慮到這一點的話就可能會出現漏洞。比如我們剛開始讓接收端獲取的字符串是 @”ABCD”(包括@和”),那么接收端會為這個字符串分配7個字節的空間。隨后在進行字符串拷貝的時候,我們將字符串變為@"ABCDOVERFLOW_OVERFLOW_OVERFLOW",接收端會一直拷貝到遇到”符號為止,這樣就造成了溢出。
Triple_Fetch 攻擊所選擇的函數是 CoreFoundation 里的 ___NSMS1() 函數,這個函數會對我們構造的惡意字符串進行多次讀取操作,如果在讀取的間隙快速對字符串進行三次修改,就會讓函數讀取到不同的字符串,讓函數產生判斷失誤,從而造成溢出并讓我們控制 pc,這也是為什么把這個漏洞稱為 Triple_Fetch 的原因。下圖就是攻擊所使用的三組不同的字符串:

攻擊所選擇的 NSXPC 服務是 “com.apple.CoreAuthentication.daemon”。對應的二進制文件是 /System/Library/Frameworks/LocalAuthentication.framework/Support/coreauthd。原因是這個進程是 root 權限并且可以調用 processor_set_tasks() API 從而獲取系統其他進程的 send right。下圖是控制了pc后的crash report:

0x02 Triple_FetchJOP &ROP&任意代碼執行
利用漏洞 Triple_Fetch 雖然可以控制 pc,但是還不能控制棧,所以需要先做 stack_pivot,好消息是 x0 寄存器指向的 xpc_uuid 對象是我們可以控制的:

因此我們可以利用 JOP 跳轉到 _longjmp 函數作為來進行stack pivot,從而控制stack:

最終發送的用來做 JOP 的格式偽造的 xpc_uuid 對象如下:

控制了 stack 就可以很容易的寫 rop 了。但是 beer 目標不僅僅是執行rop,它還希望獲取目標進程的 task port 并且執行任意二進制文件,因此除了 exp,攻擊端還用 machmsg 發送了 0x1000 個帶有 send right 的 port 到目標進程中:

這些 port 的 machmsg 在內存中的位置和內容如下(msgh_id 都為 0x12344321):

隨后,exp 采用 rop 的方法對這些 port 進行遍歷并且發送回發送端:

隨后,攻擊端會接收 machmsg,如果獲取到的 msgh_id 為 0x12344321 的消息,說明我們成果得到了目標進程的 task port:

得到了 task_port 后,sploit() 函數就結束了,開始進入 do_post_exploit()。do_post_exploit() 也做了非常多的事情,首先是利用 coreauthd 的 task port 以及 processor_set_tasks() 獲取所有進程的 task port。這是怎么做到的呢?
利用 coreauthd 的 task port 我們可以利用 mach_vm_* API 任意的修改 coreauthd 的內存以及寄存器,所以我們需要先開辟一段內存作為 stack,然后將 sp 指向這段內存,再將 pc 指向我們想要執行的函數地址就可以讓目標進程執行任意的函數了,具體實現在 call_remote() 中:

隨后我們控制 coreauthd 依次執行 task_get_special_port(), processor_set_default(), host_processor_set_priv(),processor_set_tasks() 等函數,來獲得所有進程的 task port 并返回給攻擊端(具體實現在 get_task_ports())中。接著,攻擊端會遍歷這個列表并篩選出 amfid,launchd,installd,springboard 這四個進程的 task port。然后利用之前 patchamfid 的技巧,對
amfid 打補丁。最后再啟動 debugserver。
其實這個 exp 不但可以執行 debugserver,還可以用來在沙盒外執行任意的二進制文件。只要把 pocs 文件夾下的 hello_world 二進制文件替換成你自己的想要執行的二進制文件,編譯安裝后,點擊 ui 中的 exec bundle binary 即可:

具體怎么做到的呢?秘密在 spawn_bundle_binary() 函數中,先在目標進程中調用 chmod 將 bin 改為
0777,然后通過一系列的 posix_spawn API(類似fork())在目標進程中執行該 bin 文件。
沙盒外的代碼執行提供了更多可以攻擊內核的接口。并且可以讀取甚至修改其他應用或者系統上的文件。比如,漏洞可以讀取一些個人隱私數據(比如,短信,聊天記錄和照片等)并發送到黑客的服務器上:

所以建議大家早日更新iOS系統到最新版本。
0x03 總結
本文介紹了 beer 發現的通用 NSXPC 漏洞。另外,還分析了 iOS 用戶態上,用 JOP 做 stack pivot 以及利用 ROP 做到任意代碼執行的攻擊技術。當然,這些漏洞只是做到了沙盒外的代碼執行,想要控制內核還需要一個或兩個XNU或者 IOKit 的漏洞才行,并且蘋果已經修復了 yalu102 越獄用的 kpp 繞過方法,因此,即使有了Triple_Fetch 漏洞,離完成全部越獄還有很大一段距離。
0x04 參考文獻:
- https://bugs.chromium.org/p/project-zero/issues/detail?id=1247
- http://keenlab.tencent.com/zh/2017/08/02/CVE-2017-7047-Triple-Fetch-bug-and-vulnerability-analysis/
- http://newosxbook.com/articles/PST2.html
- https://www.blackhat.com/docs/us-17/wednesday/us-17-Feng-Many-Birds-One-Stone-Exploiting-A-Single-SQLite-Vulnerability-Across-Multiple-Software.pdf
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/375/
暫無評論