Dirty COW漏洞原理與簡單利用

我將分爲3個部分進行介紹,包括:漏洞的概述,漏洞的成因以及漏洞的利用。


首先是漏洞概述:

Dirty COW漏洞是一種發生在寫時複製競態條件漏洞,它影響所有基於Linux的操作系統,包括Android,這個漏洞2007年起就存在於Linux內核中,直到2016年才被發現和修復。可以利用這個漏洞修改受保護的文件,也可以利用這個漏洞提權。

Dirty COW漏洞是發生在寫時複製競態條件漏洞,我們先看看什麼是競態條件和寫時複製。


image-20200520085510421

競態條件是指一個系統或者進程的輸出依賴於不受控制的事件出現順序或者出現時機。我們看下邊的這個例子:這個php代碼的功能爲從銀行執行取款交易,首先檢查要提取的金額是否少於餘額,如果是,則授權,之後更新餘額並退出。那麼,如果同時有兩個提款請求,則可能會出現競態條件漏洞。比如說,當前餘額是100元,線程1要求提取90元,在服務器更新餘額之前,線程2嘗試提取90元,這將被批准,因爲當前的餘額仍然是100元,因此總共提取了180元,賬戶中的餘額爲10元。


image-20200520091719663

競態條件通常發生在多個進程(線程)同時訪問和操作相同的數據 以及 執行結果取決於特定的順序這兩種情況。那麼如果特權程序具有競態條件漏洞的話,攻擊者就可以通過對不可控事件施加影響來影響特權程序的輸出。


image-20200520092303346

好,我們接下來再看一下寫時複製:寫時複製是一種允許不同進程中的虛擬內存映射到相同物理內存頁面的技術。比如我們使用fork系統調用創建子進程,那麼這個子進程通過使頁表條目指向相同的物理內存來共享父進程內存,當任何進程試圖寫入內存時,會引發異常,OS將爲子進程分配新的物理內存,從父進程複製內容,更改每個進程的頁表使它指向自己的私有內存副本,這就是寫時複製技術


image-20200520093045891

寫時複製執行過程執行三個重要步驟,包括:製作映射內存的副本;更新頁表,使虛擬內存指向新創建的物理地址;寫入內存。由於三個步驟不是原子性的,一個線程在執行這三個步驟過程中可能被其他線程中斷,從而產生潛在的競態條件。


image-20200520093639149

那麼,什麼地方會利用到內核的寫時複製機制呢?我們來看一個比較常見的系統調用mmap(),它是一個將文件或者設備映射到進程內存的系統調用,也就是說對進程內存的讀寫就是對文件的讀寫。

這個系統調用包含圖中的幾個參數:前兩個參數是映射內存區域的起始地址和大小,第三個參數是讀寫方式,即是否可讀是否可寫,第四個參數指定映射的方式,包括map_shared和map_private,map_shared是指當多個線程將同一個文件映射到自己的虛擬地址中,它們都共享同一個物理內存塊,說通俗點就是共享內存,map_private則是將文件映射到進程的私有內存,這個後一頁重點介紹,後兩個參數是映射的文件以及文件內偏移。


image-20200520095037278

map_private參數指定將文件映射到進程的私有內存。從圖中可以看到,兩個進程將同一個文件映射到自己的虛擬內存地址,如果兩個文件都是隻讀的,那麼虛擬內存地址將指向同一個物理內存塊。但是如果一個進程試圖寫入數據,就像圖中的進程2,此時就會發生寫時複製,將物理內存塊複製一個副本,然後更新進程2的頁表指向新的內存塊,最後向物理內存塊的副本中寫入數據。

**這裏需要注意的是,**即使程序是以只讀的方式來做內存映射,map_private允許程序通過WRITE系統調用往物理內存塊的副本中寫入數據,這爲我們後面的利用創造了條件。


image-20200520100410168

前面我們知道了寫時複製時會有競態條件漏洞呢?那麼該如何利用呢,這裏介紹另一個系統調用,madvise(),這個調用通過指定第三個參數爲MADV_DONOTNEED告訴內核不再需要聲明地址部分的內存,內核將釋放該地址的資源,進程的頁表會重新指向原始的物理內存。


image-20200520101026305

組合使用mmap和madvise就可以利用寫時複製的競態條件漏洞,這張圖展示了整個過程。

先看右邊的圖,這是一個進程將只讀文件映射到進程的虛擬內存地址中,當mmap指定參數爲map_private,儘管是隻讀的,仍然可以寫入數據,只不過這時寫到的是原始物理內存的副本。

左邊的圖,步驟A,B,C,是寫時複製的三個步驟,首先創建映射內存的副本,然後將進程頁表指向原始物理內存的副本,最後向副本寫入數據。

那麼當同一個進程的線程1執行寫時複製過程,具體的就是執行完步驟B但還沒執行步驟C,另一個線程2調用了madvice(),那麼進程的頁表將重新指向原始的映射的內存物理塊,線程1繼續執行步驟C會向只讀文件寫入數據。

這就是整個Dirty-cow漏洞的利用過程。


image-20200520102019507

最後,我們看一下漏洞利用。利用的基本思路是在一個進程裏創建兩個線程,一個線程向只讀的映射內存通過Write系統調用寫入數據,這時候發生寫時複製,另外一個線程通過madvise系統調用來丟棄映射內存的私有副本,這兩個線程相互競爭從而向只讀文件寫入數據。


image-20200520102546712

這是我們的主程序,它將指定的只讀文件映射到物理內存塊中,參數是MAP_PRIVATE,然後創建兩個線程。


image-20200520103046832

這個線程通過訪問Linux的/proc文件系統來訪問所在進程的內存地址空間,並通過Write系統調用不斷嘗試向映射的物理內存塊寫入數據,這時候發生寫時複製。


image-20200520103349972

這個線程通過madvise系統調用不斷讓系統釋放原始映射的物理內存塊的副本,這樣總能產生一個時序使得寫時複製的線程將數據寫到原始的映射內存物理塊中。


image-20200520103641554

這是Linux內核版本,當前用戶無root權限。


image-20200520103752745

編譯利用程序。


image-20200520103816618

準備測試文本文件,這個文件對普通用戶是隻讀的。


image-20200520103849916

然後在普通用戶下運行攻擊程序,第一個參數是目標文件,第二個參數是寫入的數據,可以看到成功向只讀文件寫入數據。


image-20200520104051667

第二個復現內容是修改/etc/passwd文件提權,其實這個過程和上一個實驗過程是一樣的,只不過目標文件換成了/etc/passwd,向文件中寫入一行來創建一個新的用戶,將uid設置成0就可以了。下面看一下攻擊結果。


image-20200520104421013

這是環境。


image-20200520104447284

編譯的過程


image-20200520104514966

執行提權程序,參數是設置的root用戶的密碼。


[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hlUALz6H-1589982397859)(C:\Users\luoyu\AppData\Roaming\Typora\typora-user-images\image-20200520104555622.png)]

可以看到,提權成功。


image-20200520104635936

最後總結一下,漏洞需要較早的內核版本,該漏洞可以在低權限下提升對文件的操作權限,也可以獲得root權限。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章