国产成人毛片毛片久久网_国产午夜激无码av毛片不_国产乱对白精彩在线播放_av资源站中文字幕_亚洲男人的天堂网站_国产成 人 综合 亚洲网_中国国产激情一区_少妇一级淫片免费放_亚洲一本大道av久在线播放_免费观看美女裸体网站

安全播報(bào)

防御吧作為15年知名老牌域名服務(wù)商,CNNIC和CANN雙認(rèn)證域名注冊(cè)商,已經(jīng)
持續(xù)為500多萬個(gè)域名提供服務(wù),包括智能DNS/自由轉(zhuǎn)移/隱私保護(hù)等服務(wù)!
Linux 內(nèi)核提權(quán) DirtyPipe(CVE-2022-0847)漏洞分析
2022-03-16 14:22:39 【

2022年2月23日, Linux內(nèi)核發(fā)布漏洞補(bǔ)丁, 修復(fù)了內(nèi)核5.8及之后版本存在的任意文件覆蓋的漏洞(CVE-2022-0847), 該漏洞可導(dǎo)致普通用戶本地提權(quán)至root特權(quán), 因?yàn)榕c之前出現(xiàn)的DirtyCow(CVE-2016-5195)漏洞原理類似, 該漏洞被命名為DirtyPipe。


在3月7日, 漏洞發(fā)現(xiàn)者M(jìn)ax Kellermann詳細(xì)披露了該漏洞細(xì)節(jié)以及完整POC。Paper中不光解釋了該漏洞的觸發(fā)原因, 還說明了發(fā)現(xiàn)漏洞的故事, 以及形成該漏洞的內(nèi)核代碼演變過程, 非常適合深入研究學(xué)習(xí)。


漏洞影響版本: 5.8 <= Linux內(nèi)核版本 < 5.16.11 / 5.15.25 / 5.10.102



漏洞復(fù)現(xiàn)

在ubuntu-20.04-LTS的虛擬機(jī)中進(jìn)行測(cè)試, 內(nèi)核版本號(hào)5.10.0-1008-oem, 在POC執(zhí)行后成功獲取到root shell




從POC看漏洞利用流程

限于篇幅,這里截取POC的部分代碼


static void prepare_pipe(int p[2])

{

   if (pipe(p)) abort();


   // 獲取Pipe可使用的最大頁面數(shù)量

   const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);

   static char buffer[4096];


   // 任意數(shù)據(jù)填充

   for (unsigned r = pipe_size; r > 0;) {

       unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;

       write(p[1], buffer, n);

       r -= n;

   }


   // 清空Pipe

   for (unsigned r = pipe_size; r > 0;) {

       unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;

       read(p[0], buffer, n);

       r -= n;

   }

}


int main(int argc, char **argv)

{

   ......


   // 只讀打開目標(biāo)文件

   const int fd = open(path, O_RDONLY); // yes, read-only! :-)

   ......

   // 創(chuàng)建Pipe

   int p[2];

   prepare_pipe(p);


   // splice()將文件1字節(jié)數(shù)據(jù)寫入Pipe

   ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);

   ......

   // write()寫入任意數(shù)據(jù)到Pipe

   nbytes = write(p[1], data, data_size);


   // 判斷是否寫入成功

   if (nbytes < 0) {

       perror("write failed");

       return EXIT_FAILURE;

   }

   if ((size_t)nbytes < data_size) {

       fprintf(stderr, "short write\n");

       return EXIT_FAILURE;

   }


   printf("It worked!\n");

   return EXIT_SUCCESS;

}

創(chuàng)建pipe;

使用任意數(shù)據(jù)填充管道(填滿, 而且是填滿Pipe的最大空間);

清空管道內(nèi)數(shù)據(jù);

使用splice()讀取目標(biāo)文件(只讀)的1字節(jié)數(shù)據(jù)發(fā)送至pipe;

write()將任意數(shù)據(jù)繼續(xù)寫入pipe, 此數(shù)據(jù)將會(huì)覆蓋目標(biāo)文件內(nèi)容;

只要挑選合適的目標(biāo)文件(必須要有可讀權(quán)限), 利用漏洞Patch掉關(guān)鍵字段數(shù)據(jù), 即可完成從普通用戶到root用戶的權(quán)限提升, POC使用的是/etc/passwd文件的利用方式。


仔細(xì)閱讀POC可以發(fā)現(xiàn), 該漏洞在覆蓋數(shù)據(jù)時(shí)存在一些限制, 我們將在深入分析漏洞原理之后討論它們。



復(fù)現(xiàn)原始Bug

在作者的paper中可以了解到, 發(fā)現(xiàn)該漏洞的起因不是專門的漏洞挖掘工作, 而是關(guān)于日志服務(wù)器多次出現(xiàn)的文件錯(cuò)誤, 用戶下載的包含日志的gzip文件多次出現(xiàn)CRC校驗(yàn)位錯(cuò)誤, 排查后發(fā)現(xiàn)CRC校驗(yàn)位總是被一段ZIP頭覆蓋。


根據(jù)作者介紹, 可以生成ZIP文件的只有主服務(wù)器的一個(gè)負(fù)責(zé)HTTP連接的服務(wù)(為了兼容windows用戶, 需要把gzip封包即時(shí)封包為ZIP文件), 而該服務(wù)沒有寫入gzip文件的權(quán)限。


即主服務(wù)器同時(shí)存在一個(gè)writer進(jìn)程與一個(gè)splicer進(jìn)程, 兩個(gè)進(jìn)程以不同的用戶身份運(yùn)行, splicer進(jìn)程并沒有寫入writer進(jìn)程目標(biāo)文件的權(quán)限, 但存在splicer進(jìn)程的數(shù)據(jù)寫入文件的bug存在。


簡(jiǎn)化兩個(gè)服務(wù)進(jìn)程

根據(jù)描述, 簡(jiǎn)易還原出bug觸發(fā)時(shí)最原本的樣子, poc_p1與poc_p2兩個(gè)程序:




編譯運(yùn)行poc_p1程序, tmpFile內(nèi)容為全A






運(yùn)行poc_p2程序, tmpFile文件時(shí)間戳未改變, 但文件內(nèi)容中出現(xiàn)了B






仔細(xì)觀察每次出現(xiàn)臟數(shù)據(jù)的間隔, 發(fā)現(xiàn)恰好為4096字節(jié), 4kB, 也是系統(tǒng)中一個(gè)頁面的大小




如果將進(jìn)程可使用的全部Pipe大小進(jìn)行一次寫入/讀出操作, tmpFile的內(nèi)容發(fā)生了變化




同時(shí)可以注意到, tmpFile文件后續(xù)并不是全部被B覆蓋, 而是在4096字節(jié)處保留了原本的內(nèi)容




此時(shí)不執(zhí)行任何操作, 重啟系統(tǒng)后, tmpFile將變回全A的狀態(tài), 這說明, poc_p2程序?qū)mpFile文件的修改僅存在于系統(tǒng)的頁面緩存(page cache)中。


以上便是漏洞出現(xiàn)的初始狀態(tài), 要分析其詳細(xì)的原因, 就需要了解造成此狀態(tài)的一些系統(tǒng)機(jī)制。


Pipe、splice()與零拷貝

限于篇幅, 這里簡(jiǎn)要介紹一下該漏洞相關(guān)的系統(tǒng)機(jī)制


CPU管理的最小內(nèi)存單位是一個(gè)頁面(Page), 一個(gè)頁面通常為4kB大小, linux內(nèi)存管理的最底層的一切都是關(guān)于頁面的, 文件IO也是如此, 如果程序從文件中讀取數(shù)據(jù), 內(nèi)核將先把它從磁盤讀取到專屬于內(nèi)核的頁面緩存(Page Cache)中, 后續(xù)再把它從內(nèi)核區(qū)域復(fù)制到用戶程序的內(nèi)存空間中;

如果每一次都把文件數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間, 將會(huì)拖慢系統(tǒng)的運(yùn)行速度, 也會(huì)額外消耗很多內(nèi)存空間, 所以出現(xiàn)了splice()系統(tǒng)調(diào)用, 它的任務(wù)是從文件中獲取數(shù)據(jù)并寫入管道中, 期間一個(gè)特殊的實(shí)現(xiàn)方式便是: 目標(biāo)文件的頁面緩存數(shù)據(jù)不會(huì)直接復(fù)制到Pipe的環(huán)形緩沖區(qū)內(nèi), 而是以索引的方式(即 內(nèi)存頁框地址、偏移量、長(zhǎng)度 所表示的一塊內(nèi)存區(qū)域)復(fù)制到了pipe_buffer的結(jié)構(gòu)體中, 如此就避免了從內(nèi)核空間向用戶空間的數(shù)據(jù)拷貝過程, 所以被稱為”零拷貝”;

管道(Pipe)是一種經(jīng)典的進(jìn)程間通信方式, 它包含一個(gè)輸入端和一個(gè)輸出端, 程序?qū)?shù)據(jù)從一段輸入, 從另一端讀出; 在內(nèi)核中, 為了實(shí)現(xiàn)這種數(shù)據(jù)通信, 需要以頁面(Page)為單位維護(hù)一個(gè)環(huán)形緩沖區(qū)(被稱為pipe_buffer), 它通常最多包含16個(gè)頁面, 且可以被循環(huán)利用;

當(dāng)一個(gè)程序使用管道寫入數(shù)據(jù)時(shí), pipe_write()調(diào)用會(huì)處理數(shù)據(jù)寫入工作, 默認(rèn)情況下, 多次寫入操作是要寫入環(huán)形緩沖區(qū)的一個(gè)新的頁面的, 但是如果單次寫入操作沒有寫滿一個(gè)頁面大小, 就會(huì)造成內(nèi)存空間的浪費(fèi), 所以pipe_buffer中的每一個(gè)頁面都包含一個(gè)can_merge屬性, 該屬性可以在下一次pipe_write()操作執(zhí)行時(shí), 指示內(nèi)核繼續(xù)向同一個(gè)頁面繼續(xù)寫入數(shù)據(jù), 而不是獲取一個(gè)新的頁面進(jìn)行寫入。

描述漏洞原理

splice()系統(tǒng)調(diào)用將包含文件的頁面緩存(page cache), 鏈接到pipe的環(huán)形緩沖區(qū)(pipe_buffer)時(shí), 在copy_page_to_iter_pipe 和 push_pipe函數(shù)中未能正確清除頁面的"PIPE_BUF_FLAG_CAN_MERGE"屬性, 導(dǎo)致后續(xù)進(jìn)行pipe_write()操作時(shí)錯(cuò)誤的判定"write操作可合并(merge)", 從而將非法數(shù)據(jù)寫入文件頁面緩存, 導(dǎo)致任意文件覆蓋漏洞。

這也就解釋了之前原始bug造成的一些問題:


由于pipe buffer頁面未清空, 所以第一次poc_p2測(cè)試時(shí), tmpFile從4096字節(jié)才開始被覆蓋數(shù)據(jù);

splice()調(diào)用至少需要將文件頁面緩存的第一個(gè)字節(jié)寫入pipe, 才可以完成將page_cache索引到pipe_buffer, 所以第二次poc_p2測(cè)試時(shí), tmpFile并沒有全部被覆蓋為”B”, 而是每隔4096字節(jié)重新出現(xiàn)原始的”A”;

每一次poc_p2寫入的數(shù)據(jù)都是在tmpFile的頁面緩存中, 所以如果沒有其他可寫權(quán)限的程序進(jìn)行write操作, 該頁面并不會(huì)被內(nèi)核標(biāo)記為“dirty”, 也就不會(huì)進(jìn)行頁面緩存寫會(huì)磁盤的操作, 此時(shí)其他進(jìn)程讀文件會(huì)命中頁面緩存, 從而讀取到篡改后到文件數(shù)據(jù), 但重啟后文件會(huì)變回原來的狀態(tài);

也正是因?yàn)閜oc_p2寫入的是tmpFile文件的頁面緩存, 所以無限的循環(huán)會(huì)因文件到尾而寫入失敗, 跳出循環(huán)。


閱讀相關(guān)源碼

要了解漏洞形成的細(xì)節(jié), 以及漏洞為什么不是從splice()引入之初就存在, 還是要從內(nèi)核源碼了解Pipe buffer的can_merge屬性如何迭代發(fā)展至今,


Linux 2.6, 引入了splice()系統(tǒng)調(diào)用;


Linux 4.9, 添加了iov_iter對(duì)Pipe的支持, 其中copy_page_to_iter_pipe()與push_pipe()函數(shù)實(shí)現(xiàn)中缺少對(duì)pipe buffer中flag的初始化操作, 但在當(dāng)時(shí)并無大礙, 因?yàn)榇藭r(shí)的can_merge標(biāo)識(shí)還在ops即pipe_buf_operations結(jié)構(gòu)體中。 如圖, 此時(shí)的buf->ops = &page_cache_pipe_buf_ops操作會(huì)使can_merge屬性為0, 此時(shí)并不會(huì)觸發(fā)漏洞, 但為之后的代碼迭代留下了隱患;




Linux 5.1, 由于在眾多類型的pipe_buffer中, 只有anon_pipe_buf_ops這一種情況的can_merge屬性是為1的(can_merge字段在結(jié)構(gòu)體中占一個(gè)int大小的空間), 所以, 將pipe_buf_operations結(jié)構(gòu)體中的can_merge屬性刪除, 并且把merge操作時(shí)的判斷改為指針判斷, 合情合理。正是如此, copy_page_to_iter_pipe()中對(duì)buf->ops的初始化操作已經(jīng)不包含can_merge屬性初始化的功能了, 只是push_write()中merge操作的判斷依然正常, 所以依然不會(huì)觸發(fā)漏洞;




page_cache_pipe_buf_ops類型也在此時(shí)被修改




然后是新的判斷can_merge的操作, 直接判斷是不是anon_pipe_buf_ops類型即可




Linux 5.8中, 把各種類型的pipe_buf_operations結(jié)構(gòu)體進(jìn)行合并, 正式把can_merge標(biāo)記改為PIPE_BUF_FLAG_CAN_MERGE合并進(jìn)入flag屬性中, 知道此時(shí), 4.9補(bǔ)丁中沒有flag字段初始化的隱患才真正生效


合并后的anon_pipe_buf_ops不能再與can_merge強(qiáng)關(guān)聯(lián)




再次修改了merge操作的判斷方式




添加新的PIPE_BUF_FLAG_CAN_MERGE定義, 合并進(jìn)入pipe buffer的flag字段



內(nèi)核漏洞補(bǔ)丁, 在copy_page_to_iter_pipe()和push_pipe()調(diào)用中專門添加了對(duì)buffer中flag的初始化。


拓展與總結(jié)

關(guān)于該漏洞的一些限制:


顯而易見的, 被覆寫的目標(biāo)文件必須擁有可讀權(quán)限, 否則splice()無法進(jìn)行;

由于是在pipe_buffer中覆寫頁面緩存的數(shù)據(jù), 又需要splice()讀取至少1字節(jié)的數(shù)據(jù)進(jìn)入管道, 所以覆蓋時(shí), 每個(gè)頁面的第一個(gè)字節(jié)是不可修改的, 同樣的原因, 單次寫入的數(shù)據(jù)量也不能大于4kB;

由于需要寫入的頁面都是內(nèi)核通過文件IO讀取的page cache, 所以任意寫入文件只能是單純的“覆寫”, 不能調(diào)整文件的大小;

該漏洞之所以被命名為DirtyPipe, 對(duì)比CVE-2016-5195(DirtyCOW), 是因?yàn)閮蓚(gè)漏洞觸發(fā)的點(diǎn)都在于linux內(nèi)核對(duì)文件讀寫操作的優(yōu)化(寫時(shí)拷貝/零拷貝); 而DirtyPipe的利用方式要比DirtyCOW的更加簡(jiǎn)單, 是因?yàn)镈irtyCOW的漏洞觸發(fā)需要進(jìn)行條件競(jìng)爭(zhēng), 而DirtyPipe可以通過操作順序直接觸發(fā);


值得注意的是, 該內(nèi)核漏洞不僅影響了linux各個(gè)發(fā)行版, Android或其他使用linux內(nèi)核的IoT系統(tǒng)同樣會(huì)受到影響; 另外, 該漏洞任意覆蓋數(shù)據(jù)不只是影響用戶或系統(tǒng)文件, 塊設(shè)備、只讀掛在的鏡像等數(shù)據(jù)一樣會(huì)受到影響, 基于此, 實(shí)現(xiàn)容器穿透也是有可能的。


】【打印關(guān)閉】 【返回頂部
分享到QQ空間
分享到: 
上一篇網(wǎng)絡(luò)安全 kali web安全「滲透測(cè)試.. 下一篇NFC竟也存在高危漏洞,看他如何分..

立足首都,輻射全球,防御吧專注云防御及云計(jì)算服務(wù)15年!

聯(lián)系我們

服務(wù)熱線:13051179500 18910191973
企業(yè)QQ:1245940436
技術(shù)支持:010-56159998
E-Mail:xihedata.com
Copyright ? 2003-2016 fangyuba. 防御吧(完美解決防御與加速) 版權(quán)所有 增值許可:京B2-20140042號(hào)
售前咨詢
公司總機(jī):18910191973
24小時(shí)電話:010-56159998
投訴電話:18910191973
值班售后/技術(shù)支持
售后服務(wù)/財(cái)務(wù)
備案專員
緊急電話:18610088800