macOS IPC - Inter Process Communication
Mach-Nachrichten über Ports
Grundlegende Informationen
Mach verwendet Tasks als die kleinste Einheit zum Teilen von Ressourcen, und jeder Task kann mehrere Threads enthalten. Diese Tasks und Threads sind 1:1 auf POSIX-Prozesse und Threads abgebildet.
Die Kommunikation zwischen Tasks erfolgt über die Mach Inter-Process Communication (IPC), wobei einseitige Kommunikationskanäle genutzt werden. Nachrichten werden zwischen Ports übertragen, die eine Art von Nachrichtenwarteschlangen darstellen, die vom Kernel verwaltet werden.
Ein Port ist das Grundelement der Mach-IPC. Es kann verwendet werden, um Nachrichten zu senden und zu empfangen.
Jeder Prozess verfügt über eine IPC-Tabelle, in der die Mach-Ports des Prozesses zu finden sind. Der Name eines Mach-Ports ist tatsächlich eine Nummer (ein Zeiger auf das Kernelobjekt).
Ein Prozess kann auch einen Portnamen mit bestimmten Rechten an einen anderen Task senden, und der Kernel wird diesen Eintrag im IPC-Table des anderen Tasks erscheinen lassen.
Portrechte
Portrechte, die definieren, welche Operationen ein Task ausführen kann, sind entscheidend für diese Kommunikation. Die möglichen Portrechte sind (Definitionen von hier):
Empfangsrecht, das das Empfangen von an den Port gesendeten Nachrichten ermöglicht. Mach-Ports sind MPSC (multiple-producer, single-consumer) Warteschlangen, was bedeutet, dass es nur ein Empfangsrecht für jeden Port im gesamten System geben kann (im Gegensatz zu Pipes, bei denen mehrere Prozesse alle Dateideskriptoren zum Lesenende einer Pipe halten können).
Ein Task mit dem Empfangsrecht kann Nachrichten empfangen und Senderechte erstellen, die es ihm ermöglichen, Nachrichten zu senden. Ursprünglich hatte nur der eigene Task das Empfangsrecht über seinen Port.
Wenn der Besitzer des Empfangsrechts stirbt oder es beendet, wird das Senderecht nutzlos (toter Name).
Senderecht, das das Senden von Nachrichten an den Port ermöglicht.
Das Senderecht kann geklont werden, sodass ein Task, der ein Senderecht besitzt, das Recht klonen und es einem dritten Task gewähren kann.
Beachten Sie, dass Portrechte auch durch Mac-Nachrichten übergeben werden können.
Einmal-Senderecht, das das Senden einer Nachricht an den Port und dann das Verschwinden ermöglicht.
Dieses Recht kann nicht geklont werden, aber es kann verschoben werden.
Portset-Recht, das ein Portset anstelle eines einzelnen Ports kennzeichnet. Das Dequeuing einer Nachricht aus einem Portset dequeues eine Nachricht aus einem der enthaltenen Ports. Portsets können verwendet werden, um gleichzeitig auf mehreren Ports zu lauschen, ähnlich wie
select
/poll
/epoll
/kqueue
in Unix.Toter Name, der kein tatsächliches Portrecht ist, sondern nur ein Platzhalter. Wenn ein Port zerstört wird, werden alle bestehenden Portrechte für den Port zu toten Namen.
Tasks können SEND-Rechte an andere übertragen, sodass sie Nachrichten zurückschicken können. SEND-Rechte können auch geklont werden, sodass ein Task das Recht duplizieren und einem dritten Task geben kann. Dies ermöglicht in Verbindung mit einem Zwischenprozess, der als Bootstrap-Server bekannt ist, eine effektive Kommunikation zwischen Tasks.
Datei-Ports
Datei-Ports ermöglichen es, Dateideskriptoren in Mac-Ports zu kapseln (unter Verwendung von Mach-Portrechten). Es ist möglich, einen fileport
aus einem gegebenen FD mit fileport_makeport
zu erstellen und einen FD aus einem fileport
mit fileport_makefd
zu erstellen.
Aufbau einer Kommunikation
Wie bereits erwähnt, ist es möglich, Rechte über Mach-Nachrichten zu senden, jedoch kann man kein Recht senden, ohne bereits ein Recht zu haben, um eine Mach-Nachricht zu senden. Wie wird also die erste Kommunikation hergestellt?
Dafür ist der Bootstrap-Server (launchd in Mac) beteiligt, da jeder ein SEND-Recht zum Bootstrap-Server erhalten kann, ist es möglich, ihn um ein Recht zu bitten, um eine Nachricht an einen anderen Prozess zu senden:
Task A erstellt einen neuen Port, erhält das Empfangsrecht darüber.
Task A, als Inhaber des Empfangsrechts, erzeugt ein SEND-Recht für den Port.
Task A stellt eine Verbindung mit dem Bootstrap-Server her und sendet ihm das SEND-Recht für den Port, das es zu Beginn generiert hat.
Denken Sie daran, dass jeder ein SEND-Recht zum Bootstrap-Server erhalten kann.
Task A sendet eine
bootstrap_register
-Nachricht an den Bootstrap-Server, um den gegebenen Port mit einem Namen wiecom.apple.taska
zu verknüpfen.Task B interagiert mit dem Bootstrap-Server, um eine Bootstrap-Suche nach dem Dienstnamen (
bootstrap_lookup
) auszuführen. Damit der Bootstrap-Server antworten kann, sendet Task B ihm ein SEND-Recht zu einem zuvor erstellten Port innerhalb der Suchnachricht. Wenn die Suche erfolgreich ist, dupliziert der Server das SEND-Recht, das von Task A erhalten wurde, und überträgt es an Task B.
Denken Sie daran, dass jeder ein SEND-Recht zum Bootstrap-Server erhalten kann.
Mit diesem SEND-Recht ist Task B in der Lage, eine Nachricht an Task A zu senden.
Für eine bidirektionale Kommunikation erstellt Task B normalerweise einen neuen Port mit einem Empfangsrecht und einem SEND-Recht und gibt das SEND-Recht an Task A weiter, damit es Nachrichten an TASK B senden kann (bidirektionale Kommunikation).
Der Bootstrap-Server kann den vom Task beanspruchten Dienstnamen nicht authentifizieren. Dies bedeutet, dass ein Task potenziell jeden Systemtask imitieren könnte, indem er fälschlicherweise einen Autorisierungsdienstnamen beansprucht und dann jede Anfrage genehmigt.
Apple speichert die Namen der systembereitgestellten Dienste in sicheren Konfigurationsdateien, die sich in SIP-geschützten Verzeichnissen befinden: /System/Library/LaunchDaemons
und /System/Library/LaunchAgents
. Neben jedem Dienstnamen wird auch die zugehörige Binärdatei gespeichert. Der Bootstrap-Server erstellt und hält ein Empfangsrecht für jeden dieser Dienstenamen.
Für diese vordefinierten Dienste unterscheidet sich der Suchprozess leicht. Wenn ein Dienstname gesucht wird, startet launchd den Dienst dynamisch. Der neue Ablauf ist wie folgt:
Task B initiiert eine Bootstrap-Suche nach einem Dienstnamen.
launchd überprüft, ob der Task ausgeführt wird, und wenn nicht, startet er ihn.
Task A (der Dienst) führt ein Bootstrap-Check-in (
bootstrap_check_in()
) durch. Hier erstellt der Bootstrap-Server ein SEND-Recht, behält es und überträgt das Empfangsrecht an Task A.launchd dupliziert das SEND-Recht und sendet es an Task B.
Task B erstellt einen neuen Port mit einem Empfangsrecht und einem SEND-Recht und gibt das SEND-Recht an Task A (den Dienst) weiter, damit er Nachrichten an TASK B senden kann (bidirektionale Kommunikation).
Dieser Prozess gilt jedoch nur für vordefinierte Systemaufgaben. Nichtsystemaufgaben funktionieren weiterhin wie ursprünglich beschrieben, was potenziell eine Imitation ermöglichen könnte.
Daher sollte launchd niemals abstürzen, da sonst das gesamte System abstürzt.
Eine Mach-Nachricht
Hier finden Sie weitere Informationen
Die mach_msg
-Funktion, im Wesentlichen ein Systemaufruf, wird zum Senden und Empfangen von Mach-Nachrichten verwendet. Die Funktion erfordert, dass die Nachricht als erstes Argument gesendet wird. Diese Nachricht muss mit einer mach_msg_header_t
-Struktur beginnen, gefolgt vom eigentlichen Nachrichteninhalt. Die Struktur ist wie folgt definiert:
Prozesse, die ein Empfangsrecht besitzen, können Nachrichten über einen Mach-Port empfangen. Umgekehrt erhalten die Sender ein Senderecht oder ein Einmal-Senderecht. Das Einmal-Senderecht dient ausschließlich zum Senden einer einzelnen Nachricht, nach der es ungültig wird.
Das anfängliche Feld msgh_bits
ist eine Bitmap:
Das erste Bit (am signifikantesten) wird verwendet, um anzuzeigen, dass eine Nachricht komplex ist (mehr dazu unten).
Das 3. und 4. Bit werden vom Kernel verwendet.
Die 5 am wenigsten signifikanten Bits des 2. Bytes können für Gutschein verwendet werden: ein weiterer Typ von Port zum Senden von Schlüssel/Wert-Kombinationen.
Die 5 am wenigsten signifikanten Bits des 3. Bytes können für lokalen Port verwendet werden.
Die 5 am wenigsten signifikanten Bits des 4. Bytes können für entfernten Port verwendet werden.
Die Typen, die im Gutschein, lokalen und entfernten Ports angegeben werden können, sind (aus mach/message.h):
Zum Beispiel kann MACH_MSG_TYPE_MAKE_SEND_ONCE
verwendet werden, um anzuzeigen, dass ein Send-once-Recht für diesen Port abgeleitet und übertragen werden soll. Es kann auch MACH_PORT_NULL
angegeben werden, um zu verhindern, dass der Empfänger antworten kann.
Um eine einfache bidirektionale Kommunikation zu erreichen, kann ein Prozess einen Mach-Port im Mach-Nachrichtenkopf namens Antwort-Port (msgh_local_port
) angeben, an den der Empfänger der Nachricht eine Antwort auf diese Nachricht senden kann.
Beachten Sie, dass diese Art der bidirektionalen Kommunikation in XPC-Nachrichten verwendet wird, die eine Antwort erwarten (xpc_connection_send_message_with_reply
und xpc_connection_send_message_with_reply_sync
). Aber normalerweise werden verschiedene Ports erstellt, wie zuvor erklärt, um die bidirektionale Kommunikation zu ermöglichen.
Die anderen Felder des Nachrichtenkopfs sind:
msgh_size
: die Größe des gesamten Pakets.msgh_remote_port
: der Port, über den diese Nachricht gesendet wird.msgh_voucher_port
: Mach-Gutscheine.msgh_id
: die ID dieser Nachricht, die vom Empfänger interpretiert wird.
Beachten Sie, dass Mach-Nachrichten über einen Mach-Port
gesendet werden, der ein Kommunikationskanal für einen einzelnen Empfänger und mehrere Sender ist, der in den Mach-Kernel integriert ist. Mehrere Prozesse können Nachrichten an einen Mach-Port senden, aber zu jedem Zeitpunkt kann nur ein einzelner Prozess daraus lesen.
Nachrichten werden dann durch den mach_msg_header_t
-Kopf gefolgt vom Körper und vom Trailer (falls vorhanden) gebildet und können die Berechtigung erteilen, darauf zu antworten. In diesen Fällen muss der Kernel die Nachricht nur von einer Aufgabe an die andere weiterleiten.
Ein Trailer ist eine vom Kernel zur Nachricht hinzugefügte Information (kann nicht vom Benutzer festgelegt werden), die bei der Nachrichtenempfang mit den Flags MACH_RCV_TRAILER_<trailer_opt>
angefordert werden kann (es gibt verschiedene Informationen, die angefordert werden können).
Komplexe Nachrichten
Es gibt jedoch auch andere komplexere Nachrichten, wie diejenigen, die zusätzliche Portrechte übergeben oder Speicher teilen, bei denen der Kernel auch diese Objekte an den Empfänger senden muss. In diesen Fällen wird das höchstwertige Bit des Kopfs msgh_bits
gesetzt.
Die möglichen Deskriptoren zum Übergeben sind in mach/message.h
definiert:
In 32-Bit sind alle Deskriptoren 12B groß und der Deskriptortyp befindet sich im 11. Deskriptor. In 64-Bit variieren die Größen.
Der Kernel kopiert die Deskriptoren von einer Aufgabe zur anderen, erstellt jedoch zuerst eine Kopie im Kernel-Speicher. Diese Technik, bekannt als "Feng Shui", wurde in mehreren Exploits missbraucht, um den Kernel dazu zu bringen, Daten in seinem Speicher zu kopieren, sodass ein Prozess Deskriptoren an sich selbst senden kann. Dann kann der Prozess die Nachrichten empfangen (der Kernel wird sie freigeben).
Es ist auch möglich, Portrechte an einen anfälligen Prozess zu senden, und die Portrechte werden einfach im Prozess erscheinen (auch wenn er sie nicht verarbeitet).
Mac Ports APIs
Beachten Sie, dass Ports dem Aufgaben-Namespace zugeordnet sind. Um einen Port zu erstellen oder nach einem Port zu suchen, wird auch der Aufgaben-Namespace abgefragt (mehr in mach/mach_port.h
):
mach_port_allocate
|mach_port_construct
: Erstellt einen Port.mach_port_allocate
kann auch ein Port-Set erstellen: Empfangsrecht über eine Gruppe von Ports. Immer wenn eine Nachricht empfangen wird, wird der Port angezeigt, von dem sie stammt.mach_port_allocate_name
: Ändert den Namen des Ports (standardmäßig 32-Bit-Ganzzahl)mach_port_names
: Portnamen von einem Ziel abrufenmach_port_type
: Rechte einer Aufgabe über einen Namen abrufenmach_port_rename
: Benennt einen Port um (wie dup2 für FDs)mach_port_allocate
: Einen neuen EMPFANGENEN, PORT_SET oder DEAD_NAME zuweisenmach_port_insert_right
: Erstellt ein neues Recht in einem Port, in dem Sie EMPFANGEN habenmach_port_...
mach_msg
|mach_msg_overwrite
: Funktionen zum Senden und Empfangen von Mach-Nachrichten. Die Überschreibversion ermöglicht die Angabe eines anderen Puffers für den Nachrichtenempfang (die andere Version wird ihn einfach wiederverwenden).
Debug mach_msg
Da die Funktionen mach_msg
und mach_msg_overwrite
diejenigen sind, die zum Senden und Empfangen von Nachrichten verwendet werden, würde das Setzen eines Haltepunkts auf sie ermöglichen, die gesendeten und empfangenen Nachrichten zu inspizieren.
Starten Sie beispielsweise das Debuggen einer beliebigen Anwendung, die Sie debuggen können, da sie libSystem.B
laden wird, die diese Funktion verwenden wird.
Hole die Werte aus den Registern:
Überprüfen Sie den Nachrichtenkopf und prüfen Sie das erste Argument:
Diese Art von mach_msg_bits_t
ist sehr verbreitet, um eine Antwort zu ermöglichen.
Ports auflisten
Der Name ist der Standardname des Ports (überprüfen Sie, wie er in den ersten 3 Bytes ansteigt). Das ipc-object
ist der verschleierte eindeutige Bezeichner des Ports.
Beachten Sie auch, wie die Ports mit nur dem Recht zum Senden den Besitzer desselben identifizieren (Portname + PID).
Beachten Sie auch die Verwendung von +
, um andere Aufgaben zu kennzeichnen, die mit demselben Port verbunden sind.
Es ist auch möglich, procesxp zu verwenden, um auch die registrierten Dienstnamen anzuzeigen (bei deaktiviertem SIP aufgrund der Notwendigkeit von com.apple.system-task-port
):
Du kannst dieses Tool in iOS installieren, indem du es von http://newosxbook.com/tools/binpack64-256.tar.gz herunterlädst.
Codebeispiel
Beachte, wie der Sender einen Port zuweist, ein Senderecht für den Namen org.darlinghq.example
erstellt und es an den Bootstrap-Server sendet, während der Sender nach dem Senderecht dieses Namens fragte und es verwendete, um eine Nachricht zu senden.
Das folgende Beispiel zeigt, wie ein Prozess eine Nachricht an einen anderen Prozess senden kann. In diesem Fall wird die msgsnd
-Funktion verwendet, um eine Nachricht an die Message Queue mit der ID 1234
zu senden. Die Nachricht besteht aus einem Text und einem Typ. Der Empfängerprozess kann dann die Nachricht von der Queue abrufen und den Inhalt lesen.
Privilegierte Ports
Es gibt einige spezielle Ports, die es ermöglichen, bestimmte sensible Aktionen auszuführen oder auf bestimmte sensible Daten zuzugreifen, falls Aufgaben über die SEND-Berechtigungen verfügen. Dies macht diese Ports aus der Perspektive eines Angreifers sehr interessant, nicht nur wegen der Fähigkeiten, sondern auch, weil es möglich ist, SEND-Berechtigungen über Aufgaben hinweg zu teilen.
Host-Spezialports
Diese Ports werden durch eine Nummer repräsentiert.
SEND-Rechte können durch den Aufruf von host_get_special_port
und RECEIVE-Rechte durch den Aufruf von host_set_special_port
erhalten werden. Beide Aufrufe erfordern jedoch den host_priv
-Port, auf den nur der Root zugreifen kann. Darüber hinaus konnte der Root in der Vergangenheit host_set_special_port
aufrufen und willkürlich übernehmen, was es beispielsweise ermöglichte, Code-Signaturen zu umgehen, indem er HOST_KEXTD_PORT
übernahm (SIP verhindert dies jetzt).
Diese sind in 2 Gruppen unterteilt: Die ersten 7 Ports gehören dem Kernel, wobei die 1 HOST_PORT
, die 2 HOST_PRIV_PORT
, die 3 HOST_IO_MASTER_PORT
und die 7 HOST_MAX_SPECIAL_KERNEL_PORT
sind.
Diejenigen, die mit der Nummer 8 beginnen, sind von Systemdaemons im Besitz und können in host_special_ports.h
deklariert gefunden werden.
Host-Port: Wenn ein Prozess SEND-Privilegien über diesen Port hat, kann er Informationen über das System abrufen, indem er seine Routinen aufruft, wie z.B.:
host_processor_info
: Prozessorinformationen abrufenhost_info
: Hostinformationen abrufenhost_virtual_physical_table_info
: Virtuelle/Physische Seitentabelle (erfordert MACH_VMDEBUG)host_statistics
: Hoststatistiken abrufenmach_memory_info
: Kernel-Speicherlayout abrufenHost-Priv-Port: Ein Prozess mit SEND-Recht über diesen Port kann privilegierte Aktionen ausführen, wie das Anzeigen von Bootdaten oder das Versuchen, eine Kernelerweiterung zu laden. Der Prozess muss Root sein, um diese Berechtigung zu erhalten.
Darüber hinaus sind für den Aufruf der
kext_request
-API weitere Berechtigungen erforderlich, nämlichcom.apple.private.kext*
, die nur Apple-Binärdateien erhalten.Weitere Routinen, die aufgerufen werden können, sind:
host_get_boot_info
:machine_boot_info()
abrufenhost_priv_statistics
: Privilegierte Statistiken abrufenvm_allocate_cpm
: Kontinuierlichen physischen Speicher zuweisenhost_processors
: Senderecht an Hostprozessorenmach_vm_wire
: Speicher resident machenDa Root auf diese Berechtigung zugreifen kann, könnte er
host_set_[special/exception]_port[s]
aufrufen, um Host-Spezial- oder Ausnahmeports zu übernehmen.
Es ist möglich, alle Host-Spezialports anzuzeigen, indem man ausführt:
Aufgaben Spezielle Ports
Diese Ports sind für bekannte Dienste reserviert. Es ist möglich, sie durch Aufruf von task_[get/set]_special_port
zu erhalten/einzustellen. Sie können in task_special_ports.h
gefunden werden:
Von hier:
TASK_KERNEL_PORT[task-self send right]: Der Port, der zur Steuerung dieser Aufgabe verwendet wird. Wird verwendet, um Nachrichten zu senden, die die Aufgabe betreffen. Dies ist der Port, der von mach_task_self (siehe Task Ports unten) zurückgegeben wird.
TASK_BOOTSTRAP_PORT[bootstrap send right]: Der Bootstrap-Port der Aufgabe. Wird verwendet, um Nachrichten zur Rückgabe anderer Systemdienst-Ports zu senden.
TASK_HOST_NAME_PORT[host-self send right]: Der Port, der zur Anforderung von Informationen des enthaltenden Hosts verwendet wird. Dies ist der Port, der von mach_host_self zurückgegeben wird.
TASK_WIRED_LEDGER_PORT[ledger send right]: Der Port, der die Quelle benennt, aus der diese Aufgabe ihren verdrahteten Kernel-Speicher bezieht.
TASK_PAGED_LEDGER_PORT[ledger send right]: Der Port, der die Quelle benennt, aus der diese Aufgabe ihren standardmäßig verwalteten Speicher bezieht.
Task Ports
Ursprünglich hatte Mach keine "Prozesse", sondern "Aufgaben", die eher als Container von Threads betrachtet wurden. Als Mach mit BSD fusioniert wurde, wurde jede Aufgabe mit einem BSD-Prozess korreliert. Daher hat jeder BSD-Prozess die Details, die er benötigt, um ein Prozess zu sein, und jede Mach-Aufgabe hat auch ihre inneren Abläufe (mit Ausnahme der nicht vorhandenen PID 0, die die kernel_task
ist).
Es gibt zwei sehr interessante Funktionen in Bezug darauf:
task_for_pid(Ziel-Aufgabenport, pid, &Aufgabenport_von_pid)
: Erhalten Sie ein SEND-Recht für den Aufgabenport der Aufgabe, die mit der durch diepid
angegebenen Aufgabe korreliert ist, und geben Sie es an den angegebenenZiel-Aufgabenport
weiter (der normalerweise die aufrufende Aufgabe ist, diemach_task_self()
verwendet hat, aber auch ein SEND-Port über eine andere Aufgabe sein könnte).pid_for_task(Aufgabe, &pid)
: Bei Erhalt eines SEND-Rechts für eine Aufgabe wird ermittelt, mit welcher PID diese Aufgabe verbunden ist.
Um Aktionen innerhalb der Aufgabe auszuführen, benötigte die Aufgabe ein SEND
-Recht für sich selbst, indem sie mach_task_self()
aufrief (was die task_self_trap
(28) verwendet). Mit dieser Berechtigung kann eine Aufgabe mehrere Aktionen ausführen, wie z.B.:
task_threads
: SEND-Recht über alle Aufgabenports der Threads der Aufgabe erhaltentask_info
: Informationen über eine Aufgabe erhaltentask_suspend/resume
: Eine Aufgabe aussetzen oder fortsetzentask_[get/set]_special_port
thread_create
: Einen Thread erstellentask_[get/set]_state
: Aufgabenstatus steuernund mehr finden Sie in mach/task.h
Beachten Sie, dass mit einem SEND-Recht über einen Aufgabenport einer anderen Aufgabe es möglich ist, solche Aktionen über eine andere Aufgabe auszuführen.
Darüber hinaus ist der Aufgabenport auch der vm_map
-Port, der es ermöglicht, Speicher innerhalb einer Aufgabe zu lesen und zu manipulieren mit Funktionen wie vm_read()
und vm_write()
. Dies bedeutet im Grunde genommen, dass eine Aufgabe mit SEND-Rechten über den Aufgabenport einer anderen Aufgabe in der Lage sein wird, Code in diese Aufgabe einzuspeisen.
Denken Sie daran, dass, weil der Kernel auch eine Aufgabe ist, wenn es jemandem gelingt, SEND-Berechtigungen über den kernel_task
zu erhalten, wird er in der Lage sein, den Kernel dazu zu bringen, beliebigen Code auszuführen (Jailbreaks).
Rufen Sie
mach_task_self()
auf, um den Namen für diesen Port für die aufrufende Aufgabe zu erhalten. Dieser Port wird nur beimexec()
vererbt; eine neue Aufgabe, die mitfork()
erstellt wurde, erhält einen neuen Aufgabenport (als Sonderfall erhält eine Aufgabe auch nachexec()
in einer suid-Binärdatei einen neuen Aufgabenport). Der einzige Weg, eine Aufgabe zu erstellen und ihren Port zu erhalten, besteht darin, den "Port-Tausch-Tanz" während einesfork()
durchzuführen.Dies sind die Einschränkungen für den Zugriff auf den Port (aus
macos_task_policy
aus der BinärdateiAppleMobileFileIntegrity
):Wenn die App die
com.apple.security.get-task-allow
-Berechtigung hat, können Prozesse des gleichen Benutzers auf den Aufgabenport zugreifen (üblicherweise von Xcode für Debugging hinzugefügt). Der Notarisierungsprozess wird dies nicht für Produktversionen zulassen.Apps mit der
com.apple.system-task-ports
-Berechtigung können den Aufgabenport für jeden Prozess aufrufen, außer dem Kernel. In älteren Versionen wurde diestask_for_pid-allow
genannt. Dies wird nur Apple-Anwendungen gewährt.Root kann auf die Aufgabenports von Anwendungen zugreifen, die nicht mit einer gehärteten Laufzeitumgebung kompiliert wurden (und nicht von Apple stammen).
Der Aufgabenname-Port: Eine nicht privilegierte Version des Aufgabenports. Er verweist auf die Aufgabe, erlaubt jedoch nicht deren Steuerung. Das Einzige, was darüber verfügbar zu sein scheint, ist task_info()
.
Thread-Ports
Threads haben auch zugehörige Ports, die von der aufrufenden Aufgabe mit task_threads
und vom Prozessor mit processor_set_threads
sichtbar sind. Ein SEND-Recht für den Thread-Port ermöglicht die Verwendung der Funktionen des thread_act
-Subsystem, wie z.B.:
thread_terminate
thread_[get/set]_state
act_[get/set]_state
thread_[suspend/resume]
thread_info
...
Jeder Thread kann diesen Port durch Aufruf von mach_thread_sef
erhalten.
Shellcode-Injektion in Thread über Aufgabenport
Sie können einen Shellcode von hier abrufen:
Introduction to ARM64v8macOS IPC (Inter-Process Communication)
macOS IPC Mechanisms
macOS provides several mechanisms for inter-process communication (IPC), including:
Mach Messages: Low-level messaging system used by the kernel and other system services.
XPC Services: High-level API for creating inter-process communication for macOS applications.
Distributed Objects: Apple's legacy IPC mechanism, now deprecated in favor of XPC Services.
IPC Abuse for Privilege Escalation
Attackers can abuse IPC mechanisms to escalate privileges on macOS systems. Common techniques include:
Impersonating XPC Services: Creating malicious XPC services to impersonate legitimate services and gain elevated privileges.
Intercepting Mach Messages: Monitoring and intercepting Mach messages to manipulate inter-process communication and gain unauthorized access.
Exploiting Distributed Objects: Leveraging vulnerabilities in legacy Distributed Objects to escalate privileges.
Mitigation Strategies
To protect against IPC abuse, consider the following mitigation strategies:
Use Code Signing: Ensure all IPC services are properly code-signed to prevent the execution of unsigned or malicious code.
Implement Sandboxing: Utilize sandboxing to restrict the capabilities of IPC services and prevent unauthorized actions.
Monitor IPC Activity: Monitor IPC activity on macOS systems for suspicious behavior or unauthorized communication.
Update Regularly: Keep macOS systems and applications up to date to patch known vulnerabilities in IPC mechanisms.
By understanding macOS IPC mechanisms and implementing proper security measures, you can reduce the risk of privilege escalation through inter-process communication.