我們會在本文詳細介紹如何使用不同的方法利用 CVE-2022-22583 的技術細節。我們還在本報告中讨論了 CVE-2022-32800 的技術細節。
2022 年 1 月 26 日,蘋果公司修複了 PackageKit 框架中的系統完整性保護 ( SIP ) 繞過漏洞,該漏洞被識别為 CVE-2022-22583。
Perception Point 發布了一篇關于該漏洞及其利用細節的文章後,我們确定我們利用該漏洞的方法與他們的不同。在深入挖掘 CVE-2022-22583 之後,我們還發現了一個新的漏洞 CVE-2022-32800。
這篇文章讨論了我們如何使用不同的方法利用 CVE-2022-22583 的技術細節。關于 SIP 和特殊守護進程服務的權利的更多詳細信息可以在我們上個月的文章中找到。我們還會讨論在 2022 年社區力量安全會議(POC2022)期間向蘋果披露的 15 個以上關鍵 SIP 繞過漏洞中的幾個。
CVE-2022-22583
CVE-2022-22583 的安全漏洞
我們通過進程監控發現了這個漏洞。當我們将 apple 簽名的軟件安裝包 ( PKG ) 文件安裝到 root volume 時,我們注意到以下腳本是由特權 "system_install" 服務生成的:
因為 "system_installd" 服務具有特殊的 "com.apple.rootless.install.heritable" 權限,所以這兩個腳本将在 SIP 繞過上下文中執行。
在看到這兩個腳本位于 "/tmp/PKInstallSandbox.l57ygT" 目錄後,我想到了以下問題:
我們可以修改臨時位置内的腳本嗎?
誰創建了帶有随機後綴的臨時文件夾 "PKInstallSandbox"?
新創建的文件夾是否受 SIP 保護?
在這些問題的啟發下,我們開始了調查。
通過反轉和調試,我們發現臨時文件夾是由 " - [ PKInstallSandbox prepareForCommitReturningError: ] " 函數創建的:
"prepareForCommitXXX" 函數的實現
在第 16 行,它調用另一個函數 "- [ PKInstallSandbox _createDirectory:uniquifying:error: ] ",該函數在内部調用 API"mkdtemp" 來不受任何限制地創建文件夾。
"_createDirectory:uniquifying:" 函數的實現
在看到 "PKInstallSandbox.XXXXXXX" 文件夾未受保護後,我們最初認為它可以被利用和操縱。然而,我們未能直接修改文件夾中的腳本。這是因為子文件夾 "Scripts" 受到限制,它從受限制的沙盒路徑中移動,如上第 25 行所示。
至少有兩種不同的方法來克服這個特殊的挑戰并利用這個安全漏洞。
漏洞 1:使用挂載技巧
第一個漏洞使用挂載技巧。Perception Point 在其文章中對此進行了詳細讨論。根據調查,挂載技巧可以通過以下步驟完成:
創建虛拟映像文件并将其裝載到 "/private/tmp" 上;
使用安裝後腳本安裝 Apple 簽名的軟件包;
等待安裝程序完成腳本目錄的提取,并收集提取路徑的随機部分;
卸載映像文件,這将恢複到提取前的 "/private/tmp" 内容;
創建腳本目錄(使用我們之前獲得的随機路徑),并将我們想要的任何腳本放入其中。
Perception Point 的文章還指出,這裡讨論的漏洞取決于時間,可能不會一直成功。
漏洞 2:使用符号鍊接
我們的漏洞使用了另一種方法:符号鍊接。此漏洞可通過以下步驟實現:
監視 "/tmp/PKInstallSandbox.XXXXXXX" 目錄的創建,并将其替換為指向另一個 "/tmp/fakebox" 位置的符号鍊接,以将受限制的腳本重定向到那裡;
一旦腳本位于 "/tmp/fakebox" 中,請删除符号鍊接并重新創建相同的 "/tmp/PKInstallSandbox.XXXXXXX" 目錄,然後将有效負載腳本放在 "/tmp/pKInstallSandox.XXXXXXX/scripts/pkgid.XXXXXX/" 目錄中;
等待有效負載腳本執行;
此漏洞的完整概念證明已上傳到了 GitHub 上。我們的概念驗證演示也可以在下圖中看到。
使用 symlink 的漏洞演示
即使我們是 root 用戶,也無法在受限目錄 "/Library/Apple" 中創建文件,因為 SIP 狀态已啟用。但是在利用程序的幫助下,我們可以在 SIP 繞過上下文中執行任意命令,并在受限目錄中成功創建文件。
蘋果 CVE-2022-22583 的補丁
"installd" 服務和 "system_installd" 服務的操作方式有點混亂。在下圖中,我們可以看到第 17 行和第 18 行的補丁代碼區分了這兩種服務:
CVE-2022-22583 的補丁
對于蘋果簽署的軟件包,該補丁使用 "OpenPath" 及其自己的受限沙盒路徑。對于其他包,它仍然使用 "/tmp" 目錄中的随機路徑。
安裝沙盒
在介紹 CVE-2022-32800 之前,我們需要了解一些與 " 安裝沙盒 " 相關的概念。
Sandbox Repository
首先,讓我們看一下 "Sandbox Repository",這是一個由 "- [ PKInstallSandboxManager _sandboxRepositoryForDestination:forSystemSoftware:create:error: ] " 函數返回和創建的目錄。
"_sandboxRepositoryForDestination:XXX" 函數的實現
總之,有四種 Sandbox Repository:
安裝目标為 root volume"/":
a. 對于 Apple 簽名的 pkg: /Library/Apple/System/Library/InstallerSandboxes/.PKInstallSandboxManager-SystemSoftware;
b. 其他 pkg: /Library/InstallerSandboxes/.PKInstallSandboxManager;
安裝目标不是 root volume:
a. 對于 apple 簽名的 pkg: $targetVolume/.PKInstallSandboxManager-SystemSoftware;
b. 其他 pkg: $targetVolume/.PKInstallSandboxManager;
需要注意的是,隻有當 apple 簽名包安裝到 root volume 時,Sandbox Repository 才會受到限制。
沙盒路徑
" 沙盒路徑 " 用于在安裝期間存儲腳本和有效載荷等文件。
它是 "Sandbox Repository" 中的一個目錄,由 " [ PKInstallSandboxManager addSandboxPathForDestination:forSystemSoftware: ] _block_invoke" 方法創建:
實現 "addSandboxPathForDestination:XXX" 函數
沙盒路徑有四種,每種路徑都有一個通用唯一标識符 ( UUID ) 名稱,表示它們特定的沙盒狀态:
UUID.sandbox:創建的第一個狀态;
UUID.activeSandbox:激活狀态,正在使用中;
UUID.trashedSandbox:停用狀态,被丢棄;
UUID.orphanedSandbox:孤立狀态,如果磁盤空間不足,将進行清理;
PKInstallSandbox
" PKInstallSandbox " 是一個用于抽象和封裝的 Objective-C 類名:
通過 "- [ PKInstallSandbox initWithSandboxPath:installRequest:error: ] " 方法初始化 "PKInstallSandbox" 的新實例,這取決于沙盒路徑和安裝請求。
請注意,該實例是可序列化的,并且該類實現了 "NSSecureCoding" 協議。"system_installd" 服務可以通過 "- [ PKInstallSandboxManager saveSandboxAsStaged: ] " 方法将實例保存或序列化到沙盒路徑中名為 "SandboxState" 的文件中:
"saveSandboxAsStaged" 函數的實現
"PKInstallSandbox" 實例也可以稍後通過 "- [ PKInstallSandboxManager_sandboxAtPath:matchingRequest:forUse: ] " 方法從 "SandboxState" 文件還原或反序列化:
"sandboxAtPath:matchingRequest:XXX" 函數的實現
注意,在第 57 行有一個檢查,它要求恢複的安裝請求與從安裝客戶端傳遞的安裝請求深度相等。這項檢查給我們的開發程序帶來了一個小小的挑戰。
在安裝之前,"system_installd" 服務需要根據 "- [ PKInstallSandboxManagersandboxForRequest:created:error: ] " 函數中的安裝請求獲取 "PKInstallSandbox" 的實例。
該函數的核心邏輯如下:
首先,它将從 "sandbox Repository" 中枚舉所有帶有 ".ssandbox" 後綴的文件夾,然後從内部的 "SandboxState" 文件中恢複 "PKInstallSandbox" 實例。
枚舉帶有 ".ssandbox" 後綴的所有文件夾
接下來,如果它找不到與安裝請求匹配的 "PKInstallSandbox" 實例,那麼它将枚舉帶有 ".activeSandbox" 後綴的所有文件夾,并嘗試從這些位置還原它們。
枚舉帶有 ".activeSandbox" 後綴的所有文件夾
最後,如果它仍然不能匹配這樣的沙盒,它将創建一個新的 " 沙盒路徑 ",并構造一個新的 "PKInstallSandbox" 實例。
創建一個新的 " 沙盒路徑 " 和實例
CVE-2022-32800
漏洞詳細信息
CVE-2022-32800 漏洞允許攻擊者劫持 "SandboxState" 文件以獲取 SIP 繞過原語。
"SandboxState" 文件存儲在 "Sandbox 路徑 " 中,該路徑位于 "Sandbox Repository" 中。在正常情況下,"Sandbox 存儲庫 " 僅限于 Apple 簽名的軟件包。
但是,如果安裝目标是 DMG(磁盤映像)卷,則根本不限制 "Sandbox Repository"。"SandboxState" 文件也是如此。因此,我們可以制作一個特制的 "SandboxState" 文件,在反序列化過程中劫持新的 "PKInstallSandbox" 實例。然後可以控制 "PKInstallSandbox" 實例的所有成員變量。
漏洞利用
有不同的方法可以利用這個漏洞。例如,在下圖中,我們劫持了成員 "_cleanupPaths",以獲取一個原語來删除任意的 SIP 保護路徑。
安裝完成後,無論是否成功,它都将調用 "- [ PKInstallSandboxManager_removeSandbox: ] " 函數删除沙盒,并删除 "_cleanupPaths" 成員指定的所有文件和文件夾。
"_removeSandbox" 函數的實現
該漏洞的完整概念證明可以在 GitHub 找到,演示視頻可以在此查看。
蘋果 CVE-2022-32800 的補丁
蘋果在 macOS 12.5 中修複了這一安全漏洞。
補丁位于 "- [ PKInstallSandboxManager _sandboxAtPath:matchingRequest:forUse: ] " 函數中 :
CVE-2022-32800 補丁
正如我們在第 38 行檢查中看到的,它在内部調用 "PKSIPFullyProtectedPath" 函數 :
"PKSIPFullyProtectedPath" 函數的實現
對于 Apple 簽名的軟件包,"SandboxState" 文件需要受信任或限制。
安全建議
為了成功地保護系統免受漏洞攻擊,用戶必須定期更新其操作系統。定期應用安全補丁将阻止攻擊者利用漏洞提升權限并發起惡意攻擊。關于此處讨論的漏洞,CVE-2022-22583 于 2022 年 1 月修補,CVE-2022 2-32800 于 2022 年 7 月修補。
最終用戶可以受益于安全解決方案,如趨勢科技 Mac 版防病毒軟件和趨勢科技防護套件,它們有助于檢測和阻止利用此類漏洞的攻擊。