用VBoxDbg除錯並理解單執行緒版髒牛
1、序言
髒牛是前幾年比較流行的一個漏洞,網上關於該漏洞的分析也比較多。但是對於像UP主一樣的新手而言,始終未能看到漏洞觸發的第一現場,比如像OOB/UAF等漏洞可以直接通過偵錯程式觀察記憶體看到漏洞確實可以觸發成功。但髒牛卻不是這樣,主要因為雙機除錯Linux的時候,KGDB無法對頁表(實體記憶體)進行讀寫。再加上多執行緒Race也提升了除錯的難度,所以一直沒能感覺很好的看到髒牛觸發的第一現場到底發生了什麼,直到我遇到了VBoxDbg這個偵錯程式。
2、VboxDbg說明
在Windows平臺下,使用Windbg可以對實體記憶體和一些特殊暫存器進行讀寫。但是在Linux核心除錯的時候,就不那麼方便,因為(嚴格來說)KGDB+Linux核心沒有實現這樣的功能。即便可以通過編寫proc偽檔案系統模組來對實體記憶體進行讀寫,但還是沒有Windbg那種方式感覺方便。於是UP主找了各種資料,最後終於發現一款比較好用的偵錯程式VboxDbg。
VBoxDbg是VirtualBox內建的一款偵錯程式,主要用於除錯在VirtualBox內執行的Guest主機。VBoxDbg也可以檢視Guest機器的實體記憶體和GDTR/IDTR等資訊。
3、單執行緒版DirtyCow
髒牛能觸發的一個必要原因是:雙執行緒競爭執行、對第四級頁表中的PTE進行讀寫操作。
為了更好的凸顯髒牛的Race的問題,我把網上的公開POC修改為一個單執行緒版本的髒牛poc,具體如下:
#include
#include
#include
#include
#include
#include
#include
void *map;
int f;
struct stat st;
char *name;
void *worker_write(void *arg)
{
char *str;
str=(char*)arg;
int f=open("/proc/self/mem",O_RDWR);
int i,c=0;
lseek(f,(uintptr_t) map,SEEK_SET);
write(f,str,strlen(str));
printf("procselfmem %d\n\n", c);
}
int main(int argc,char *argv[])
{
if (argc<3)
{
(void)fprintf(stderr, "%s\n","usage: dirtycowtest target_file new_content");
return 1;
}
f=open(argv[1],O_RDONLY); //這裡由於開啟的是root許可權檔案,所以理論上來說使用普通使用者許可權是無法對root檔案進行修改的
fstat(f,&st);
name=argv[1];
map=mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);
printf("mmap %zx\n\n",(uintptr_t) map);
worker_write(argv[2]); //這裡嘗試進行了寫操作
return 0;
}
可以看到,程式碼中只有一個執行緒,且該執行緒僅僅執行了一個write動作。我們等下會用VBoxDbg來模擬第二個執行緒原本的動作(madvise)
4、除錯單執行緒版DirtyCow
除錯的總體思路為:
使用GDB+KGDB在follow_page_mask函式呼叫返回後的第一條核心指令、以及faultin_page函式內部呼叫handle_mm_fault函式返回後的第一條核心指令處分別下記憶體訪問斷點;
使用GDB+KGDB監控使用者態呼叫mmap後返回地址處的記憶體資訊;
在第二次呼叫handle_mm_fault後藉助VBoxDbg手動修改PTE資訊並讓程式執行起來,觀察結果。
由於Dirty Cow與ASLR/KASLR無關,所以在本實驗中為了方便除錯已經手動關閉了ASLR
首先直接執行修改過的dirtycowtest(執行結果如圖1),可以發現,執行後sensitive.txt檔案資訊並未發生改變,同時記錄下mmap返回地址:0x7ffff7ff7000
圖1 直接執行dirtycowtest發現root許可權檔案未被修改
然後再次執行dirtycowtest程式,同時使用GDB+KGDB觀察在__get_user_pages函式內部的執行情況,情況如下(如圖2):
圖2 第一次呼叫follow_page_mask後斷下
可以看到,當前處於剛剛執行完follow_page_mask的時刻(圖2),並且此時由於頁面未被調入實體記憶體中,所以使用者態地址0x7ffff7ff7000處於無法訪問的狀態。且此時執行follow_page_mask的返回結果也為0(表示返回錯誤,未獲取到struct page資訊)。接下來繼續執行,進入到faultin_page函式內部,在handle_mm_fault函式執行完畢後斷下:
圖3 第一次呼叫handle_mm_fault後斷下
此時(圖3)可以看到,地址0x7ffff7ff7000可以被訪問到了(頁表中PTE狀態為present),並且結果為0x000a363534333231(sensitive.txt的檔案內容的二進位制形式表示)。然後繼續執行:
圖4 第二次呼叫follow_page_mask後斷下
當再次執行完follow_page_mask函式時(圖4),發現雖然地址0x7ffff7ff7000可以被訪問了,但follow_page_mask返回值page依然為0。這是由於foll_flags與頁表PTE記錄的許可權資訊不符,因此觸發了一個寫異常。繼續執行:
圖5 第二次呼叫handle_mm_fault後斷下
此時(圖5)是第二次執行完handle_mm_fault函式,也就是此時核心完成了COW頁面的生成過程(但由於是同一程式訪問自身記憶體,所以實際上只有一個物理頁面)。然後就需要使用VBoxDbg進行後續工作了:
首先通過已知的使用者態地址0x7ffff7ff7000,可以計算出在x86_64環境中,其四級頁表的每級偏移分別為:0x7F8、0xFF8、0xDF8、0xFB8。這裡我們要使用到VBoxDbg的四個命令,分別為:
命令描述stop 讓VirtualBox徹底暫停,此時再操作GDB+KGDB並不會看到回顯 dpta 可以解析指定物理PTE資訊 eq 以8位元組為單位長度,修改指定地址內容 g 讓虛擬機器繼續執行,相當於stop命令的反操作
結合cr3暫存器資訊,和上述已知四個頁表的偏移資訊,可以計算出位於第四級頁表中的PTE資訊。然後手動對該PTE清零,即可模擬原本Dirty Cow漏洞exploit中的第二個madvise執行緒工作,具體操作記錄如圖6:
圖6 使用VBoxDbg修改PTE
隨後禁用GDB+KGDB環境中的所有斷點繼續執行,即可從虛擬機器中看到執行結果。對比圖1中的結果可以發現,雖然dirtycowtest程式沒有發生變化,但是確實完成了對sensitive.txt檔案的修改(已修改為111111),結果如圖7:
圖7 利用dirtycowtest成功使用低許可權使用者修改root許可權檔案內容
至此,完成了DirtyCow單執行緒版本的除錯。在進行頁表或實體記憶體除錯等工作時,VBoxDbg有著GDB/KGDB無法比擬的優勢。VBoxDbg還有很多功能,本文無法一一介紹。總體來說,VBoxDbg是一款可以與GDB/KGDB互補的簡單好用的除錯工具。
5、參考文件
Oracle VM VirtualBox®www.virtualbox.org
本文由看雪論壇 OxLucifer 原創,轉載請註明來自看雪社群
原文連結:[原創]用VBoxDbg除錯並理解單執行緒版髒牛(CVE-2016-5195)-『二進位制漏洞』-看雪安全論壇
相關文章
- 用VBoxDbg除錯並理解單執行緒版髒牛(CVE-2016-5195)除錯執行緒
- 如何理解JS的單執行緒?JS執行緒
- gdb多執行緒多程序除錯命令執行緒除錯
- Java執行緒小刀牛試Java執行緒
- redis為什麼用單執行緒不用多執行緒Redis執行緒
- 如何理解執行緒執行緒
- 理解執行緒同步執行緒
- web前端教程:如何理解JavaScript的單執行緒?Web前端JavaScript執行緒
- 程式和執行緒理解執行緒
- 多執行緒:執行緒池理解和使用總結執行緒
- 深入理解JVM(③)執行緒與Java的執行緒JVM執行緒Java
- IDEA多執行緒下空指標斷點除錯Idea執行緒指標斷點除錯
- 26、多執行緒與並行執行緒並行
- 詳談執行緒池的理解和應用執行緒
- SingleThreadExecutor(單執行緒執行器)thread執行緒
- redis 單執行緒Redis執行緒
- cy.visit 執行邏輯的單步除錯除錯
- 深入理解執行緒池的執行流程執行緒
- 併發程式設計-10.使用 Visual Studio 除錯多執行緒應用程式程式設計除錯執行緒
- Node.js 執行緒你理解的可能是錯的Node.js執行緒
- 瀏覽器多執行緒和js單執行緒瀏覽器執行緒JS
- webpack最簡單的入門教程裡bundle.js之執行單步除錯的原理解析WebJS除錯
- Nginx 高階篇(十)並行 併發 單執行緒(廢話篇 )Nginx並行執行緒
- 給執行緒池取一個名稱有助於除錯 - bozho執行緒除錯
- JavaScript單執行緒概念JavaScript執行緒
- Redis--單執行緒Redis執行緒
- Redis-單執行緒Redis執行緒
- 圖解併發與並行-分別從CPU和執行緒的角度理解圖解並行執行緒
- 多執行緒Demo學習(執行緒的同步,簡單的執行緒通訊)執行緒
- [Flutter]啟動:除錯執行Flutter除錯
- Concurrency(一:如何理解多執行緒)執行緒
- 深入理解Flutter多執行緒Flutter執行緒
- java多執行緒之volatile理解Java執行緒
- 深入理解執行緒通訊執行緒
- [Java併發]執行緒的並行等待Java執行緒並行
- 這麼理解執行緒生命週期,是不是很簡單?執行緒
- 多執行緒並行執行,然後彙總結果執行緒並行
- Java多執行緒—執行緒同步(單訊號量互斥)Java執行緒