cve-2021-3156-sudo堆溢出簡單分析


調試方式

首先從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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM