近日,Qualys 安全團(tuán)隊(duì)發(fā)布安全公告稱(chēng),在 Polkit 的 Pkexec 程序中發(fā)現(xiàn)了一個(gè)本地權(quán)限提升漏洞CVE-2021-4034。Qualys安全團(tuán)隊(duì)在其博客文章中完整介紹了 Polkit 漏洞的細(xì)節(jié)。筆者在這里將以導(dǎo)讀的形式,為大家解讀一下這篇Qualys安全團(tuán)隊(duì)關(guān)于 Polkit 漏洞的精彩分析,揭開(kāi)這個(gè)漏洞的神秘面紗。
Polkit是一個(gè)應(yīng)用程序級(jí)別的工具集,通過(guò)定義和審核權(quán)限規(guī)則,實(shí)現(xiàn)不同優(yōu)先級(jí)進(jìn)程間的通訊:控制決策集中在統(tǒng)一的框架之中,決定低優(yōu)先級(jí)進(jìn)程是否有權(quán)訪(fǎng)問(wèn)高優(yōu)先級(jí)進(jìn)程。
Polkit在系統(tǒng)層級(jí)進(jìn)行權(quán)限控制,提供了一個(gè)低優(yōu)先級(jí)進(jìn)程和高優(yōu)先級(jí)進(jìn)程進(jìn)行通訊的系統(tǒng)。和 sudo 等程序不同,Polkit 并沒(méi)有賦予進(jìn)程完全的 root 權(quán)限,而是通過(guò)一個(gè)集中的策略系統(tǒng)進(jìn)行更精細(xì)的授權(quán)。
Polkit定義出一系列操作,例如運(yùn)行 GParted, 并將用戶(hù)按照群組或用戶(hù)名進(jìn)行劃分,例如 wheel 群組用戶(hù)。然后定義每個(gè)操作是否可以由某些用戶(hù)執(zhí)行,執(zhí)行操作前是否需要一些額外的確認(rèn),例如通過(guò)輸入密碼確認(rèn)用戶(hù)是不是屬于某個(gè)群組。
由于Polkit的 Pkexec工具中存在一處本地權(quán)限提升漏洞,致使攻擊者可以通過(guò)控制環(huán)境變量,從而誘導(dǎo)Pkexec執(zhí)行任意代碼。利用成功后,可導(dǎo)致非特權(quán)用戶(hù)獲得管理員權(quán)限。
Pkexec是一個(gè)用來(lái)允許授權(quán)用戶(hù)以其他用戶(hù)身份執(zhí)行program的工具,其參數(shù)如下圖:
在Pkexec工具的 main() 函數(shù)中,首先會(huì)使用如下圖代碼處理所接收的命令行參數(shù):
Pkexec工具將判斷傳入的參數(shù)是否為絕對(duì)路徑,如果給出非絕對(duì)路徑,Pkexec工具也將嘗試在 path 中定位program,具體的做法是在PATH 環(huán)境變量的目錄中搜索要執(zhí)行的program。具體的代碼見(jiàn)下圖紅框處:
如果命令行參數(shù)argc的數(shù)量為 0,這意味著如果傳遞給execve()的參數(shù)列表 argv為空,即 {NULL},那么 argv[0]將為 NULL,是參數(shù)列表的終止符,這將導(dǎo)致:
Pkexec代碼中第 534 行,整數(shù) n 設(shè)置為 1;
第 610 行,從 argv[1] 越界讀取指針路徑;
第 639 行,指針 s 被越界寫(xiě)入argv[1] ;
但是從這個(gè)越界的 argv[1] 中讀取和寫(xiě)入的到底是什么呢?
要回答這個(gè)問(wèn)題,我們需要知道的是:當(dāng)execve() 一個(gè)新program時(shí),kernel將我們的參數(shù)、環(huán)境變量字符串以及指針(argv 和 envp)復(fù)制到新program堆棧的末尾,如下圖:
由于argv和envp 指針在內(nèi)存中是連續(xù)的,如果 argc 為 0,那么越界argv[1] 實(shí)際上是 envp[0],即為指向我們的第一個(gè)環(huán)境變量“value”的指針。最終導(dǎo)致:
Pkexec代碼中第610行,將要執(zhí)行的程序的路徑從argv[1](即envp[0])中越界讀取,并指向“value”;
由于“value”不是以斜線(xiàn)開(kāi)頭,因此進(jìn)入 629 行的if分支,并在第 632 行將這個(gè) “value”傳遞給 g_find_program_in_path()
隨后,g_find_program_in_path() 在PATH 環(huán)境變量目錄中搜索一個(gè)名為“value”的可執(zhí)行文件。如果找到這樣的可執(zhí)行文件,則將其完整路徑返回給 pkexec的 main() 函數(shù)。
最后,這個(gè)完整路徑被越界寫(xiě)入 argv[1](即 envp[0]),從而覆蓋了我們的第一個(gè)環(huán)境變量,見(jiàn)下圖紅框處:
所以準(zhǔn)確的說(shuō):如果我們的 PATH 環(huán)境變量是“PATH=name”,并且如果目錄“name”存在(在當(dāng)前工作目錄中)并且包含一個(gè)名為“value”的可執(zhí)行文件,則寫(xiě)入一個(gè)指向字符串“name/value”的指針越界到 envp[0];
“PATH=name=.”,并且目錄是“name=.” 存在并包含一個(gè)名為“value”的可執(zhí)行文件,然后將指向字符串“name=./value”的指針越界寫(xiě)入 envp[0]。
換言之:這種越界寫(xiě)入允許我們將一個(gè)“不安全”的環(huán)境變量(例如,LD_PRELOAD)重新引入 pkexec 的環(huán)境。這些“不安全”變量通常在調(diào)用 main() 函數(shù)之前已經(jīng)被ld.so從 SUID 程序的環(huán)境中刪除。
此次漏洞雖然需要在本地觸發(fā),但Polkit作為系統(tǒng)預(yù)裝工具,影響眾多 Linux 發(fā)行版,并且漏洞利用簡(jiǎn)單且穩(wěn)定,可以很好的應(yīng)用于“權(quán)限提升”這個(gè)攻擊階段中,因此應(yīng)該得到重視。
筆者對(duì)漏洞進(jìn)行分析后,從筆者的角度對(duì)此次Pkexec漏洞提出如下三個(gè)觀(guān)點(diǎn):
1、此次存在漏洞的Pkexec工具自身比較特殊,有SUID權(quán)限。利用有SUID權(quán)限的工具進(jìn)行提權(quán)歷史上已有案例。此類(lèi)工具應(yīng)該強(qiáng)化檢查,防止高權(quán)限錯(cuò)誤傳遞。
2、在Unix的衍生系統(tǒng)BSD以及Windows系統(tǒng)中不會(huì)存在同類(lèi)問(wèn)題,因?yàn)檫@些OS永遠(yuǎn)不會(huì)出現(xiàn)argc=0的情況。
3、此次漏洞在更早之前曾被發(fā)現(xiàn)(大約是2013年被發(fā)現(xiàn)),但一直認(rèn)為是無(wú)關(guān)緊要的bug,直到近期才被發(fā)現(xiàn)利用方式,所以軟件的bug和vul的邊界需要得到研究人員的重視。
本文以導(dǎo)讀的形式,為大家?guī)?lái)了Qualys安全團(tuán)隊(duì)關(guān)于 polkit 漏洞的精彩分析,希望讀者可以對(duì)此漏洞有著更深入的了解與認(rèn)識(shí)。