其他
HEVD 内核漏洞之未初始化栈变量
本文为看雪论坛优秀文章
看雪论坛作者ID:Saturn丶
上一篇研究了一下基础的内核整数溢出漏洞,漏洞利用还有瑕疵,但是原理上还是比较清楚的,后续有时间继续研究,这篇我们继续下一个内核漏洞:未初始化栈变量。
实验环境:
Win10专业版+VMware Workstation 15 Pro+Win7 x86 sp1
实验工具:
VS2015+Windbg+KmdManager+DbgViewer
漏洞原理
顾名思义,即内核函数栈中局部变量未初始化。
分析:
{
ULONG Value;
FunctionPointer Callback;
ULONG Buffer[58];
} UNINITIALIZED_MEMORY_STACK, *PUNINITIALIZED_MEMORY_STACK;
NTSTATUS
TriggerUninitializedMemoryStack( _In_ PVOID UserBuffer)
{
ULONG UserValue = 0;
ULONG MagicValue = 0xBAD0B0B0;
NTSTATUS Status = STATUS_SUCCESS;
//安全版本
UNINITIALIZED_MEMORY_STACK UninitializedMemory = { 0 };
//漏洞版本
UNINITIALIZED_MEMORY_STACK UninitializedMemory;
PAGED_CODE();
__try
{
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);
DbgPrint("[+] Triggering Uninitialized Memory in Stack\n");
// Call the callback function
if (UninitializedMemory.Callback)
{
UninitializedMemory.Callback();
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
Status = GetExceptionCode();
DbgPrint("[-] Exception Code: 0x%X\n", Status);
}
return Status;
}
漏洞利用
NtMapUserPhysicalPages (
__in PVOID VirtualAddress,
__in ULONG_PTR NumberOfPages,
__in_ecount_opt(NumberOfPages) PULONG_PTR UserPfnArray
)
(...)
ULONG_PTR StackArray[COPY_STACK_SIZE];
//
// This local stack size definition is deliberately large as ISVs have told
// us they expect to typically do up to this amount.
//
#define COPY_STACK_SIZE 1024
if ( (unsigned int)NumberOfPages > 0xFFFFF )
return -1073741584;
BaseAddressa = (unsigned int)BaseAddress & 0xFFFFF000;
v33 = ((_DWORD)NumberOfPages << 12) + BaseAddressa - 1;
if ( v33 <= BaseAddressa )
return -1073741584;
v4 = &P;//栈地址
v39 = 0;
v37 = &P;
if ( PageFrameNumbers )
{
if ( !NumberOfPages )
return 0;
if ( (unsigned int)NumberOfPages > 0x400 )//如果要超过1024,就要扩展池,不过这里不用
{
v4 = (char *)ExAllocatePoolWithTag(0, 4 * (_DWORD)NumberOfPages, 0x77526D4Du);
v37 = v4;
if ( !v4 )
return -1073741670;
}
v5 = MiCaptureUlongPtrArray((int)NumberOfPages, (unsigned int)PageFrameNumbers, v4);//v4 要拷贝的目标 内核栈 a2,要覆盖的EoPBuffer 长度是4*NumberOfPages
{
size_t v3; // ecx@1
v3 = 4 * a1; //长度
if ( v3 )
{
if ( a2 & 3 )
ExRaiseDatatypeMisalignment();
if ( v3 + a2 > (unsigned int)MmUserProbeAddress || v3 + a2 < a2 )
*(_BYTE *)MmUserProbeAddress = 0;
}
memcpy(a3, (const void *)a2, v3);
return 0;
}
(1)将shellcode放在内存任意位置
(2)使用指向shellcode的指针喷射内核栈
(3)触发未初始化变量漏洞
(4)调用执行
漏洞反思
//安全版本
UNINITIALIZED_MEMORY_STACK UninitializedMemory = { 0 };
链接:
1、j00ru关于NtMapUserPhysicalPages和内核堆栈喷射技术:
https://j00ru.vexillium.org/2011/05/windows-kernel-stack-spraying-techniques/
2、fuzzsecurity:
https://www.fuzzysecurity.com/tutorials/expDev/17.html
3、玉涵师傅的翻译:
https://bbs.pediy.com/thread-225179.htm
- End -
看雪ID:Saturn丶
https://bbs.pediy.com/user-831334.htm
*本文由看雪论坛Saturn丶原创,转载请注明来自看雪社区
进阶安全圈,不得不读的一本书
推荐文章++++
* Linux Kernel Exploit 内核漏洞学习(3)-Bypass-Smep
﹀
﹀
﹀
官方微博:看雪安全
商务合作请发邮件至:wsc@kanxue.com