macOS 終於開始解決 XPC 的一個大坑

2021-12-24 非嘗鹹魚販

今年的 WWDC 剛過去,蘋果生態當中的幾大作業系統都宣布了全新的測試版本。比如 macOS 升級到了 12.0,命名為 Monterey。

有眼尖的網友在新版文檔當中看到了這個新加入的 API:

int xpc_connection_set_peer_code_signing_requirement(    xpc_connection_t connection, const char *requirement);

這個 API 屬於 XPC 框架。

XPC

XPC 是 macOS 和 iOS 當中一種基於 Mach 消息的跨進程通信機制,其 API 可以很輕鬆地將計算任務拆分到多個進程中完成。特別是系統會在消息發送的時候自動啟動對應的 service,開發者只需關心 connection 的生命周期,而不是具體的進程。

進程隔離可以提升應用的安全性和穩定性。例如在處理格式解析的時候,損壞或者惡意構造的文件可能造成進程崩潰。有了 XPC,開發者可以將這類容易出問題的運算任務放進獨立進程中實現,並使用嚴格的沙箱配置。

一方面 XPC 進程錯誤不會讓主程序崩潰,另一方面沙箱也會限制漏洞的利用。例如 Safari 瀏覽器和 WKWebView 就利用了這種機制,採用獨立進程渲染 Web 內容。

XPC 的目的是簡化多進程權限隔離。XPC 服務不一定會採用更嚴格的沙箱,反之,還有一種特權 XPC 服務的應用。

在 macOS 系統中想要臨時以管理員權限執行操作,系統會要求輸入密碼或者使用 TouchID 驗證身份。實際上後臺程序臨時的權限提升需求很常見,如果每一次都要求認證,會對用戶體驗造成一定程度的損害。

macOS 將 AuthorizationExecuteWithPrivileges 函數標記為過時,並推薦使用 SMJobBless 替代。但這兩個函數的行為並不等價,甚至可以說是大相逕庭。AuthorizationExecuteWithPrivileges 類似 sudo,可以創建更高權限的子進程;SMJobBless 則會向系統中安裝一個 PrivilegedHelper 並註冊為 Mach Service。

這樣一來不是直接 sudo 執行命令,而是僅在第一次安裝時需要驗證管理員身份,之後後臺的 XPC Helper 以 root 權限運行,界面等較低權限的程序通過 XPC 暴露的接口遠程調用 XPC Helper 裡的代碼。

這個機制對第三方開發者開放,而另一方面 mac 系統本身有很多內置的 XPC 服務。

這樣便產生了跨安全邊界的通信,需要考慮惡意輸入的問題。做安全設計需要具備一個思維就是,不要輕易信任數據輸入。

我們來看一些風險案例。

Rootpipe

在 2014 年,研究人員向(當時還被叫做)OS X 系統報告了一個安全問題,並命名為 Rootpipe。問題組件出在 writeconfig 的 XPC 服務中。這個服務提供了一個可以寫入任意內容到任意路徑,同時設置文件屬性的遠程接口。

這個接口沒有做任何校驗,任何第三方應用程式都可以調用。寫入文件屬性的參數可以設置 suid 位,因此直接創建一個具有 suid 權限的可執行文件,其再調用 setuid 即可提升到 root。

校驗 peer

macOS 針對此類問題採用的策略是限制可訪問 XPC 服務的 peer 的代碼籤名,首先要求對方數字籤名來自 Apple,有時候還會要求具有特定的 entitlement。

XPC 主要有兩種風格的 API,一種是面向過程的 C API,在此之上又封裝了支持複雜 Objective-C 對象序列化的 NSXPC 系列 API。

面向過程的 API 使用 xpc_connection_set_event_handler 設置一個 block(Objective-C 的匿名函數)來處理 connection 的各種事件。當 xpc_get_type(event) 返回 XPC_TYPE_CONNECTION 時,意味著連接剛剛建立。服務可以通過驗證 peer 的有效性來決定是 xpc_connection_resume 繼續通信,還是忽略連接。

如果是基於 NSXPC,遠程調用被封裝到 NSXPCListener 類中。校驗 peer 的時機在 delegate 類的 listener:shouldAcceptNewConnection: 方法。假如校驗合法,則繼續連接並返回 YES。

- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)connection {    connection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(HelperToolProtocol)];    connection.exportedObject = [[HelperTool alloc] init];    [connection resume];    return YES;}

mac 的文檔在這裡留了一個大坑,就是沒有說明到底應該怎麼校驗傳入連接的合法性。

在 SMJobBless 的官方實例 EvenBetterAuthorizationSample 裡寫了一句非常誤導人的描述。代碼在程序的 Info.plist 裡設置了一個 SMAuthorizedClients 鍵值標記允許的代碼籤名要求(Code Signing Requirement)

https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/RequirementLang/RequirementLang.html

Code Signing Requirement 是一個領域特定語言(DSL),用來描述代碼籤名所需要滿足的條件。示例如下:

anchor apple and info [CFBundleShortVersionString] < "17.4"

這個示例讓開發者認為只要簡單在 Info.plist 裡設置好這個值即可。然而事實上這是需要開發者編寫代碼去實現如下流程:

也就是說僅僅設置 Infp.plist 是沒有任何效果的。

另一個更大的坑來自如何正確地獲取 peer 連接的 SecCodeRef。

SecCodeCopySelf 指向進程自身,沒有檢查的意義。

而 SecStaticCodeCreateWithPath 校驗的是文件,存在可運行時替換的問題。由於 mac 系統不像 Windows 那樣鎖定運行中的可執行文件,完全可以先執行惡意程序 A,然後將自身路徑替換成可信的程序 B 而不影響運行。這樣嘗試檢查合法性會誤認為有效。這個函數僅在運行程序之間有意義。

SecCodeCopyGuestWithAttributes 支持傳入一個 CFDictionaryRef,鍵名包括:

https://developer.apple.com/documentation/security/code_signing_services/guest_attribute_dictionary_keys?language=objc

一個示例如下:

SecCodeRef code = NULL;NSDictionary *attributes = @{    kSecGuestAttributePid: @connection.processIdentifier};
SecCodeCopyGuestWithAttributes(0, attributes, kSecCSDefaultFlags, &code);


這裡採用了對方進程的 pid 作為參數,看上去沒有什麼問題,甚至 mac 自己的服務也這麼寫。

CVE-2019-8565

進程 pid 實際上在 XPC 驗證 peer 的場景中不能信任。筆者在 macOS High Mojave 上找到的漏洞證明,即使是 Apple 自己也被這個 API 坑了。

漏洞在 macOS 10.14.4 被修復。漏洞根源在於 com.apple.appleseed.fbahelperd 這個 XPC 服務。在處理傳入連接的時候,進程直接使用 pid 作為參數校驗。

實際上在 Unix 系統中 pid 的個數是有上限的,但進程的創建和終止讓達到這個上限並非難事。因此作業系統有 pid 復用的機制,在不同時刻,同一個 pid 可能對應了不同的進程。

除了將用過的 pid 回收,還有一個技巧可以主動替換 pid 對應的進程,就是 exec 函數。一般使用 exec 執行程序之前都會 fork,但假如故意忽略掉 fork,就會出現 pid 保持原樣,進程卻被整個替換成全新的命令的情況。使用 posix_spawn 函數的 POSIX_SPAWN_SETEXEC 標誌位也可以實現同樣效果。

XPC 在處理來自不同進程的請求時復用了同一個消息隊列,這就給條件競爭攻擊留下了空間。

攻擊程序創建十個左右完全一致的子進程,同時向 XPC 服務發起請求。使用非阻塞函數發送消息之後,迅速調用 exec / posix_spawn 將自身進程替換成籤名合法的系統自帶程序:

#define COUNT 10int pids[COUNT];for (int i = 0; i < COUNT; i++) {    int pid = fork();    if (pid == 0) {        xpc_connection_t connection = xpc_connection_create_mach_service("Helper", NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);        xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {});        xpc_connection_resume(connection);        xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);        xpc_connection_send_message(connection, message);        char* target_binary = "/path/to/valid signed binary";        char* target_argv[] = {target_binary, NULL};        exec_blocking(target_binary, target_argv, environ);    } else {        pids[i] = pid;    }}sleep(1);for (int i = 0; i < COUNT; i++) {    pids[i] && kill(pids[i], 9);}

這樣一來,總有一些請求正好繞過代碼籤名檢查,得以訪問受限制的 XPC 服務接口。在結合 fbehelper 服務本身的路徑穿越等缺陷,可以在毫秒級別獲得 root 權限。

auditToken

既然 pid 不可靠,在需要安全檢查的場景又該如何處理?

在 XNU 裡有一個 audit_token_t 結構,除了 pid 之外還保存了其他欄位,特別是 p_idversion,用來保證相同的 audit_token_t 只能表示同一個進程:

audit_token.val[0] = my_cred->cr_audit.as_aia_p->ai_auid;audit_token.val[1] = my_pcred->cr_uid;audit_token.val[2] = my_pcred->cr_gid;audit_token.val[3] = my_pcred->cr_ruid;audit_token.val[4] = my_pcred->cr_rgid;audit_token.val[5] = p->p_pid;audit_token.val[6] = my_cred->cr_audit.as_aia_p->ai_asid;audit_token.val[7] = p->p_idversion;

校驗代碼籤名的時候用 audit_token_t 比 pid 更為安全(雖然 Project Zero 後來在這裡又找了一個漏洞),但是蘋果看上去不想讓第三方開發者用這個結構。以下兩個函數分別可以在面向過程和 NSXPC 的接口中獲取 audit token,但它們既沒有文檔也沒有在頭文件中提供:


macOS 自帶的服務大量使用這兩個接口做安全檢查,但它們卻不向第三方軟體提供。這就導致第三方應用不停地出現類似的安全問題:

Google Chrome CVE-2020-6574
Security: Keystone for macOS should use auditToken to validate incoming XPC messages
https://bugs.chromium.org/p/chromium/issues/detail?id=1102196

KeyBase(KB004)
還被 35c3 做成了真實 CTF 題

Office Mac 版(CVE-2018-8412)

VMware Fusion (CVE-2018-6962)

Adobe CreativeCloud (CVE-2018-4991)

解決方案

回到一開始我們關注到的這個新函數 xpc_connection_set_peer_code_signing_requirement。這個函數的第二個參數接受一個字符串,也就是前文提到的 Code Signing Requirement 語言。

筆者現在其實沒有下最新版的 Beta 系統來驗證具體的代碼實現,不過相信 Apple 此舉是為了解決代碼校驗這個大坑,隱藏具體的 audit_token_t 和 SecCodeRef 等細節,直接讓開發者傳入一個字符串來限制所期望的籤名規則。

未完待續……

不過就算代碼籤名得到解決,其實在某些情況下還是有辦法繞過。首先受信任的 peer 必須開啟 Hardened Runtime,以避免代碼注入的問題

https://developer.apple.com/documentation/security/hardened_runtime

曾經只需要一個 DYLD_INSERT_LIBRARIES 環境變量就可以向命令注入一個 dylib 庫,或者使用其他 dylib 劫持的方式觸發 dlopen 載入惡意代碼。這樣一來校驗 peer 是在主進程上做的,並沒有遞歸對所有的動態庫做檢查。惡意注入的代碼模塊可以藉此繞過檢測,包括最新的 xpc_connection_set_peer_code_signing_requirement API 也有被過的可能。

另外一種情況就是代碼重用問題。例如經典的 return oriented programming,在沒有控制流保護的平臺上一但出現本地可以觸發的代碼執行漏洞,就可以完全以受信任程序的身份執行任意代碼。由於確實沒有引入新的可執行文件,無從檢測。

因此如果有需要調用 XPC Helper 的程序,一定要避免信任腳本解釋器、Electron 等天生就為了執行代碼而設計的框架。框架本身可能存在腳本調用 dlopen 的可能性,此外類似 v8 等腳本引擎還容易受到 patchgap 導致的 nday 攻擊。通過復用代碼冒充可信代碼籤名的繞過基本無解,只能儘量避免出現類似問題。

參考資料


xpc_connection_set_peer_code_signing_requirement https://developer.apple.com/documentation/xpc/3755524-xpc_connection_set_peer_code_sig?language=objc

ObjC 中國 - XPC https://objccn.io/issue-14-4/

Rootpipe - WIkipedia https://en.wikipedia.org/wiki/Rootpipe

The Story Behind CVE-2019-13013 https://blog.obdev.at/what-we-have-learned-from-a-vulnerability/

Code Signing Requirement Language https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/RequirementLang/RequirementLang.html

Hardended Runtime https://developer.apple.com/documentation/security/hardened_runtime

相關焦點

  • 樂高街景大坑終於開始了,本周視頻一覽
    本周(1月4日~1月10日),我們的街景大坑終於開始填了。快點跟著壞雪的腳步,一起來看看我們本周更新了哪些視頻吧!
  • iOS 冰與火之歌 - 利用 XPC 過 App 沙盒
    想要與這些 XPC 服務通訊我們需要創建一個 XPC client,傳輸的內容要與 XPC service 接收的內容對應上,比如系統服務可能會開這樣一個 XPC service:#!然而如果我們傳過去的值並不是一個 xpc_data,networkd 也會當這個值是一個 xpc_data,並傳給_xpc_data_get_bytes_ptr()來進行解析:
  • 升級Php 7.4帶來的兩個大坑
    最近在幫一個朋友張羅一個網站,於是把線上代碼拉回本地做鏡像進行測試。因為web應用有些奇怪的依賴,為了不汙染本機的環境,我就把它部署在Docker中進行測試。Docker的基礎鏡像選擇了激進的Archlinux,搭配上個月底才出爐的Php7.4。
  • 虛擬機VMware安裝macOS Catalina 10.15
    經過一天的摸索,我終於用VMware 安裝上了macOS。有興趣的小夥伴可以按照本教程進行安裝,建議所有軟體和我下文所給的一樣,不然容易出錯。如下圖所示,未解鎖前的VMware創建虛擬機嚮導中沒有macos選項。
  • 一條命令讓腳本幫我安裝MacOS
    最近發現一個很強的項目:myspaghetti/macos-virtualbox一行命令幫你在VirtualBox虛擬機上安裝好Mac Os系統,並且系統是直接從Apple上下載的官方版本,還免去了我們尋找系統鏡像的煩惱.之前也嘗試過用ISO文件安裝,步驟繁瑣,並且安裝好後的系統不知道為什麼十分卡頓.
  • 蘋果iPhone checkra1n越獄,Windows系統解決方案,附工具
    開始安裝虛擬機,然後安裝macos,這個過程全程都有提示。特別是後期安裝usb的時候,如果意外退出,重新運行命令就行。如果不會可以百度一下,安裝macos的過程。最後進入MacOS,安裝愛思助手mac版,裡面就有一鍵越獄了。最後提示一下,xubuntu一定要設置一下電源,屏幕休眠時間,因為啟動虛擬機後,所有的usb設備都只能在虛擬機中運行。整個過程等待的時間有點長,要有細心和耐心。
  • COMBAT2000新款XPC輕型載板戰術背心評測
    前面板下方還有一個獨立的倉位,這應該就是防彈板倉了。在固定防彈板的魔術貼上,設計了長長的織帶提手,用以穿戴戰術手套時方便將魔術貼撕下來。經過一番研究才知道,為了防止後面板被意外掀開,設計了這兩條小織帶起到反扣的保險作用,這個小細節足以讓人眼前一亮。
  • 一鍵腳本在virtualbox虛擬機安裝Macos系統,支持Mac,Linux和Windows
    virtualbox虛擬機安裝archlinux+dde看到一個很有意思的一鍵腳本,可以用在virtualbox搭建macos系統,支持Mac,Linux和Windows[wsl子系統],安裝體驗黑蘋果就簡單很多了。ps:腳本默認會分配4g內存,安裝完之後大概需要60g的空間。如果自己電腦內存比較小就不要輕易使用腳本。
  • OpenCore一般故障排除3[持續更新中]macOS安裝後及其它問題
    當一個ACPI表需要其餘的用於正確引用時,就會發生這種情況,它不接受DSDT的創建,因為我們僅將其用於創建選定的幾個SSDT。: /troubleshooting/troubleshooting.md#bios-reset-or-sent-into-safemode-after-rebootshutdown[4]AMD X570顯卡macOS GPU加速: /troubleshooting/troubleshooting.md#macos-gpu-acceleration-missing-on-amd-x570
  • 亞絲娜終於登場,OP細節你注意到了嗎?
    大家期待的《刀劍神域3》第33集終於更新了,這一集的看點主要有兩個,第一個是整合騎士謝塔和拳鬥士伊斯卡恩的戰鬥,尤其是謝塔這個人,看起來很呆萌,
  • 國產XPC戰術背心先後獲得了國內特警單位的喜歡和認可
    總的來說XPC 2.0做了許多更加專業化的改進,也許與COMBAT2000近幾年在國內警用裝備市場的迅猛發展有關。
  • 如何跨過選購潛水手電的幾個大坑?
    以下是你選購潛水手電之前需要跨過的幾個大坑:亮度流明,是描述光通量的物理單位,衡量手電的亮度自然也不例外。1流明具體有多亮,表述比較複雜,感興趣的可以百度一下,通俗一點說,一個40瓦的普通白熾燈泡,其發光效率大約是每瓦10流明,因此可以發出約400流明的光。那麼說回選擇潛水手電,我們應該選擇多大流明的手電呢?
  • 現在開始:用你的Mac訓練和部署一個圖片分類模型
    如果想了解用機器學習是怎麼解決實際問題的,可以看這篇:如何使用深度學習識別UI界面組件?(https://juejin.im/post/5e781a78e51d45271c3016db)從問題定義、算法選型、樣本準備、模型訓練、模型評估、模型服務部署、到模型應用都有介紹。
  • macOS Monterey 升級初體驗
    收錄於話題 #macos軟體兼容性我所做的第一件事,就是測試我常用軟體的兼容性,經過一段時間的使用,以下軟體可以正常使用:Bartender4Alfred4
  • 關注 不該遺忘的天津:爆炸後一個月 現在情況如何?
    隨著裝有危險品的貨櫃一個個被清走,事故核心區的地表危化品清理工作正接近尾聲。但是誰都知道,這並不是結束。空氣、水、土壤的汙染情況如何?如何清理危化品?問題還有一大堆。工作人員一方面對整個區域進行洗消作業,另一方面密切監測水、土壤、空氣中的氰化物含量。本周,天津市環境監測中心主任鄧小文表示,核心區外圍的空氣品質已經達標。  站在爆炸產生的大坑旁邊,天津市環保局水汙染防治處處長賈麗泉對於空氣已不太擔心,而廢水的治理成了這段時間最難啃的骨頭。大坑之中,廢水氰化物的含量一度超標約一千倍。一個月以來,向大坑中連續投藥的方法取得了成效。
  • 選購潛水手電,不跨過這幾個大坑你怎敢入手?
    如何跨過選購潛水手電的幾個大坑潛水手電是夜潛的必備裝備,白天進行潛水時,如果深潛或者光線不好,手電也能派上用場。而且當水深超過25米左右,丟失的是紅色,橙色,黃色。以下是你選購潛水手電之前需要跨過的幾個大坑:流明,是描述光通量的物理單位,衡量手電的亮度自然也不例外。1流明具體有多亮,表述比較複雜,感興趣的可以百度一下,通俗一點說,一個40瓦的普通白熾燈泡,其發光效率大約是每瓦10流明,因此可以發出約400流明的光。那麼說回選擇潛水手電,我們應該選擇多大流明的手電呢?這是一個很寬泛的問題。
  • 勞雷八通道探地雷達綜合檢測車解決方案助力深圳道路安全
    圖一: 2017年7月25日晚,北京西二旗大街銘科苑北段驚現塌陷大坑,一輛轎車栽進坑中  勞雷為城市道路檢測提供解決方案近年來,隨著城市發展速度加快,城市道路出現越來越多的地面塌陷現象,此現象一般指地表巖、土體在自然或人為因素作用下向下陷落,並在地面形成塌陷坑的一種動力地質現象
  • macOS.Macma後門的分析
    谷歌的報告集中在兩個漏洞的使用上:一個0 day和一個N day(有補丁的已知漏洞)。事實上,在谷歌發布報告時,這兩個漏洞已經被修復了幾個月。而利用這些漏洞投放的惡意軟體卻沒有受到太多關注:一個後門,該後門即使在最新的macOS Monterey的補丁系統上也能正常運行。谷歌將該後門命名為 "Macma",我們也將使用這個名字。
  • 《高能少年團》終於開始走上坡路了,少年們可千萬別辜負了這大好春光啊
    值得點讚的,反倒是填充在環節裡面的細節,比如作為飛行嘉賓的楊迪,高空遊戲的時候給到很明顯的腿抖的細節,再比如大家贊攝像高空作業危險時,給到攝像的鏡頭,還有幾個人終於完成任務到達頂端時,王俊凱說:「沒有誰比誰更高能,只有更努力。」不管是不是刻意設置,滿滿的正能量。
  • macOS Sierra 10.12.2 更新異常的解決方案
    縮寫為SIP,又稱為Rootless技術,從Mac OS X El Capitan系統開始使用。該技術可以保護系統即使以root用戶登錄時,仍然不可改寫部分關鍵的系統文件內容或權限。目的在於避免用戶錯誤操作關鍵系統文件導致系統崩潰,避免系統底層被惡意注入或篡改。