寫在前面的話

本文由安全研究人員Gergely發表于他自己的博客,并在文中詳細介紹了macOS中的一個本地提權漏洞(CVE-2022-26704)。該漏洞已上報給了蘋果安全獎勵計劃ABS,并在上報后的322天拿到了漏洞獎金,目前蘋果已將該漏洞成功修復。

關于漏洞

這個漏洞名為batsignal,是macOS中的一個本地提權漏洞,該漏洞允許研究人員在Spotlight(聚焦搜索功能)中將非特權用戶(包括訪客用戶在內)提升為root權限。

Spotlight介紹

Spotlight是macOS系統中的一個搜索服務,它可以對系統中的磁盤內容進行索引,而它本身對于研究人員來說也是非常有意思的一個研究目標。

Spotlight服務由多個守護進程組成,其中我們最關心的兩個如下:

mds:以root權限運行,擁有全磁盤訪問權限(FDA);
mds_stores:以root權限運行;

這兩個組件所做的事情略有不同,沙盒也不一樣,但都是以root權限運行的,這個才是最重要的。

為了完成搜索任務,Spotlight必須能夠訪問系統上的文件,這可能是這些守護進程以root身份運行的原因。我們現在暫時不去分析該服務是如何實現文件內容解析的,因為我們要先分析一下我發現的一個奇怪情況,即“卷的索引文件存儲在卷上”。

值得注意的是,這是一個典型的速度與安全性的權衡:一方面,隨卷攜帶索引可以保持可用性并保持搜索速度。另一方面,攻擊者可以使用此功能嘗試在計算機上執行遠程代碼,或在本地升級權限。

我們之所以提到這一點,是因為Spotlight確實能夠在本地存儲這些索引文件:它會對網絡卷這樣做,但不會對本地磁盤這樣做。很顯然,macOS的開發人員也意識到了這一點,當然也有可能是為了不讓卷索引占用太多的本地磁盤空間。

漏洞分析

Spotlight會在卷中一個受SIP保護的目錄(名為/.Spotlight-V100)中執行文件操作。我們同時還發現,在掛載的文件系統上單獨運行root守護進程并沒什么,但系統會提示:“只有當你能保證卷是可信的時,這樣做才是安全的”。

據我們所知,在普通的Linux系統上,普通用戶是無法裝載卷的。除此之外,它們不能觸發root守護進程并在新安裝的文件系統上進行操作。但macOS不一樣,在macOS上,磁盤掛載行為無處不在,這也是任何用戶安裝系統后首先要做的事情之一。沒有提示,沒有密碼,沒有問題。正好,也沒有安全保障。

任意的macOS都可以實現以下操作:

1、掛載自己的磁盤鏡像;
2、卸載、更新和移除掛載點;
3、設置union和noowners之類的掛載標記;

這樣一來,攻擊者便有機可乘了:

1、他們可以準備一個惡意鏡像;
2、他們可以對守護進程執行惡意操作,然后修改掛載標記;
3、他們可以直接使用noowners作為掛載標記,并向任何只有root用戶可以寫入的文件中寫入任意內容;

這樣一來,我們就可以輕松解除SIP的保護,因為就文件系統而言,SIP只是一個正則表達式引擎而已。那么,我們該如何解除SIP的保護呢?

用戶裝載卷上的通用SIP繞過

為了保護“/.Spotlight-V100”目錄,SIP將嘗試按名稱來與它匹配,它很可能使用的是mount-relative-regex指令。我們之所以說是“很可能使用”,是因為它允許Spotlight守護進程訪問它。這在mds和mds_stores的沙盒策略中是可用的,但它阻止其他人訪問的機制對我們來說是不可見的。因此,我們沒有把握確定這是同一機制,但這肯定是一個安全的選擇。

現在,我們需要嘗試修改卷名稱,在裝載卷時這是不允許的,但我們可以通過卸載它來繞過SIP。編輯磁盤映像就像編輯其他任何東西一樣:現在它不再是文件系統,它只是一堆字節數據的集合。

我們有在線和離線兩種方法來實現我們的目標,離線意味著可以提前準備好磁盤鏡像,而在線意味著需要在磁盤掛載和目標應用正在運行的時候去修改卷內容。

由于在線方法非常的麻煩,我們這里使用離線方法的來做介紹。使用離線(卸載)磁盤修改方法,我們可以搞定任何受保護的文件/目錄:

1、我們可以刪除、修改和替換任何受保護的文件/目錄;
2、我們可以跟卷root硬連接以便后續訪問;
3、我們可以修改權限;
4、....

在我們修改鏡像之前,我們需要選擇我們的文件系統,這里有很多選擇,但HFS+的效果是最好的。接下來,我們還需要讓文件系統去做一些它們“本不該做”的事情,實現這個目標有兩種方法:

方法一:使用真正的文件系統驅動器

我們可以使用Linux的文件系統驅動器,它也能識別HFS+,而且限制相比macOS的HFS+驅動器要更少。我們還需要使用強制參數才能將鏡像掛載為rw。或者,我們可以使用任何其他可以可靠地寫入我們選擇的文件系統的東西。此時,FUSE會是一個不錯誤的選擇,但我們并沒有測試過。

方法二:直接編輯源代碼

一個更野蠻但有效的解決方案是手動編輯二進制文件,但需要注意的是,這種方法對于任何復雜的(通常是較新的)文件系統來說都是非常困難的,只有像FAT和HFS+這樣簡單的舊版文件系統才適用。

實際上,我們只需要修改文件系統上的一個字符串,就能夠實現我們的目標了。對于HFS+,我們只需要做下列事情:

buf.replace(b’\x31\x00\x30\x00\x30\x00’, b'\x39\x00\x30\x00\x30\x00’)

上述的Python代碼會將100修改為900,并導致.Spotlight-V100 變為 .Spotlight-V900。

上述代碼不是固定的,只要能破壞原始正則表達式就可以了。

下面給出的是我們繞過SIP保護的步驟:

1、創建并掛載一個HFS+磁盤;
2、使用mdutil -i on /MY/VOLUME命令開啟Spotlight,此時/.Spotlight-V100目錄便會在磁盤卷中被創建;
3、卸載磁盤;
4、編輯磁盤二進制源碼,破壞原始正則表達式,將.Spotlight-V100 變改為 .Spotlight-V90;
5、掛載磁盤;
6、在.Spotlight-V90中做任何你想做的事情;
7、卸載磁盤;
8、恢復對二進制源碼的修改;
9、重新掛載磁盤,這一次Spotlight將會運行并執行惡意內容/代碼;

漏洞利用場景

撇開架構錯誤不談,Spotlight中的一個具體缺陷是它寫入文件內容的方式。由于Spotlight認為自己一直會受到SIP的保護,所以在處理文件時就沒有那么的小心了。

在Spotlight中,我們可以通過在卷上寫入“可緩存”文件來觸發不安全的文件寫入。當這種情況發生時,文件的內容將被編入索引,提取的文本將被寫入緩存目錄中的新文件。

此時將會生成一個新的文件:

./mnt/.Spotlight-V100/Store-V2/[UUID]/Cache/0000/0000/0000/[X].txt

其中[UUID]是一個UUID,[X]則是原始文件的索引節點編號。

這里支持很多文件類型,但我選擇使用一個名為payload.pdf的PDF來做測試,其內容如下:

ALL ALL=(ALL) NOPASSWD:ALL

首先,[X].tmp會被寫入,并調用rename()將其重命名為[X].txt,寫入操作將由open()或write()執行,隨后open()便調用符號連接。

這很明顯是一個安全漏洞!

漏洞利用步驟如下:

1、創建一個磁盤;
2、在./mnt上掛載磁盤;
3、將payload.pdf拷貝到磁盤卷;
4、開啟Spotlight;
5、等待Payload.pdf被索引,然后會創建緩存目錄和文件;
6、卸載磁盤;
7、編輯磁盤鏡像內容;
8、掛載磁盤;
9、將Cache緩存目錄移動到磁盤卷根目錄,使用一個符號連接替換它;
10、卸載磁盤;
11、恢復磁盤鏡像內容的修改;
12、掛載磁盤;
13、創建指向/etc/sudoers的硬連接/Library/Caches/com.apple.Spotlight/whatever;
14、在./mnt/Cache/0000/0000/0000/[X].tmp創建指向/Library/Caches/com.apple.Spotlight/whatever的符號連接;
15、從Cache中刪除[X].txt;
16、重新索引;
17、此時,/etc/sudoers將被我們的Payload重寫;

總結

這是一個價值17000美元的安全漏洞,并且已經通過蘋果的漏洞獎勵計劃上報給了蘋果公司。簡而言之,如果攻擊者能夠控制文件系統,那么一切安全保護或安全訪問機制都將“不復存在”。