macOS XPC
Reading time: 13 minutes
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- VĂ©rifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépÎts github.
Informations de base
XPC, qui signifie XNU (le noyau utilisĂ© par macOS) inter-Process Communication, est un cadre pour la communication entre processus sur macOS et iOS. XPC fournit un mĂ©canisme pour effectuer des appels de mĂ©thode sĂ»rs et asynchrones entre diffĂ©rents processus sur le systĂšme. C'est une partie du paradigme de sĂ©curitĂ© d'Apple, permettant la crĂ©ation d'applications sĂ©parĂ©es par privilĂšges oĂč chaque composant fonctionne avec seulement les permissions dont il a besoin pour faire son travail, limitant ainsi les dommages potentiels d'un processus compromis.
XPC utilise une forme de communication inter-processus (IPC), qui est un ensemble de mĂ©thodes permettant Ă diffĂ©rents programmes s'exĂ©cutant sur le mĂȘme systĂšme d'Ă©changer des donnĂ©es.
Les principaux avantages de XPC incluent :
- SĂ©curitĂ© : En sĂ©parant le travail en diffĂ©rents processus, chaque processus peut se voir accorder uniquement les permissions dont il a besoin. Cela signifie que mĂȘme si un processus est compromis, il a une capacitĂ© limitĂ©e Ă causer des dommages.
- StabilitĂ© : XPC aide Ă isoler les plantages au composant oĂč ils se produisent. Si un processus plante, il peut ĂȘtre redĂ©marrĂ© sans affecter le reste du systĂšme.
- Performance : XPC permet une concurrence facile, car diffĂ©rentes tĂąches peuvent ĂȘtre exĂ©cutĂ©es simultanĂ©ment dans diffĂ©rents processus.
Le seul inconvénient est que séparer une application en plusieurs processus les faisant communiquer via XPC est moins efficace. Mais dans les systÚmes d'aujourd'hui, cela n'est presque pas perceptible et les avantages sont meilleurs.
Services XPC spécifiques à l'application
Les composants XPC d'une application sont Ă l'intĂ©rieur de l'application elle-mĂȘme. Par exemple, dans Safari, vous pouvez les trouver dans /Applications/Safari.app/Contents/XPCServices
. Ils ont l'extension .xpc
(comme com.apple.Safari.SandboxBroker.xpc
) et sont également des bundles avec le binaire principal à l'intérieur : /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/MacOS/com.apple.Safari.SandboxBroker
et un Info.plist: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/Info.plist
Comme vous pourriez le penser, un composant XPC aura des droits et privilĂšges diffĂ©rents des autres composants XPC ou du binaire principal de l'application. SAUF si un service XPC est configurĂ© avec JoinExistingSession dĂ©fini sur âTrueâ dans son fichier Info.plist. Dans ce cas, le service XPC s'exĂ©cutera dans la mĂȘme session de sĂ©curitĂ© que l'application qui l'a appelĂ©.
Les services XPC sont dĂ©marrĂ©s par launchd lorsque nĂ©cessaire et arrĂȘtĂ©s une fois toutes les tĂąches terminĂ©es pour libĂ©rer des ressources systĂšme. Les composants XPC spĂ©cifiques Ă l'application ne peuvent ĂȘtre utilisĂ©s que par l'application, rĂ©duisant ainsi le risque associĂ© aux vulnĂ©rabilitĂ©s potentielles.
Services XPC Ă l'Ă©chelle du systĂšme
Les services XPC Ă l'Ă©chelle du systĂšme sont accessibles Ă tous les utilisateurs. Ces services, soit launchd soit de type Mach, doivent ĂȘtre dĂ©finis dans des fichiers plist situĂ©s dans des rĂ©pertoires spĂ©cifiĂ©s tels que /System/Library/LaunchDaemons
, /Library/LaunchDaemons
, /System/Library/LaunchAgents
, ou /Library/LaunchAgents
.
Ces fichiers plist auront une clé appelée MachServices
avec le nom du service, et une clé appelée Program
avec le chemin vers le binaire :
cat /Library/LaunchDaemons/com.jamf.management.daemon.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Program</key>
<string>/Library/Application Support/JAMF/Jamf.app/Contents/MacOS/JamfDaemon.app/Contents/MacOS/JamfDaemon</string>
<key>AbandonProcessGroup</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>com.jamf.management.daemon</string>
<key>MachServices</key>
<dict>
<key>com.jamf.management.daemon.aad</key>
<true/>
<key>com.jamf.management.daemon.agent</key>
<true/>
<key>com.jamf.management.daemon.binary</key>
<true/>
<key>com.jamf.management.daemon.selfservice</key>
<true/>
<key>com.jamf.management.daemon.service</key>
<true/>
</dict>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Les éléments dans LaunchDameons
sont exĂ©cutĂ©s par root. Donc, si un processus non privilĂ©giĂ© peut communiquer avec l'un d'eux, il pourrait ĂȘtre capable d'escalader les privilĂšges.
Objets XPC
xpc_object_t
Chaque message XPC est un objet dictionnaire qui simplifie la sérialisation et la désérialisation. De plus, libxpc.dylib
déclare la plupart des types de données, il est donc possible de s'assurer que les données reçues sont du type attendu. Dans l'API C, chaque objet est un xpc_object_t
(et son type peut ĂȘtre vĂ©rifiĂ© en utilisant xpc_get_type(object)
).
De plus, la fonction xpc_copy_description(object)
peut ĂȘtre utilisĂ©e pour obtenir une reprĂ©sentation sous forme de chaĂźne de l'objet, ce qui peut ĂȘtre utile Ă des fins de dĂ©bogage.
Ces objets ont également certaines méthodes à appeler comme xpc_<object>_copy
, xpc_<object>_equal
, xpc_<object>_hash
, xpc_<object>_serialize
, xpc_<object>_deserialize
...
Les xpc_object_t
sont créés en appelant la fonction xpc_<objetType>_create
, qui appelle en interne _xpc_base_create(Class, Size)
oĂč le type de la classe de l'objet (l'un de XPC_TYPE_*
) et sa taille sont indiqués (40B supplémentaires seront ajoutés à la taille pour les métadonnées). Ce qui signifie que les données de l'objet commenceront à l'offset de 40B.
Par conséquent, le xpc_<objectType>_t
est en quelque sorte une sous-classe du xpc_object_t
qui serait une sous-classe de os_object_t*
.
warning
Notez qu'il devrait ĂȘtre le dĂ©veloppeur qui utilise xpc_dictionary_[get/set]_<objectType>
pour obtenir ou définir le type et la valeur réelle d'une clé.
xpc_pipe
Un xpc_pipe
est un tuyau FIFO que les processus peuvent utiliser pour communiquer (la communication utilise des messages Mach).
Il est possible de créer un serveur XPC en appelant xpc_pipe_create()
ou xpc_pipe_create_from_port()
pour le créer en utilisant un port Mach spécifique. Ensuite, pour recevoir des messages, il est possible d'appeler xpc_pipe_receive
et xpc_pipe_try_receive
.
Notez que l'objet xpc_pipe
est un xpc_object_t
avec des informations dans sa structure sur les deux ports Mach utilisés et le nom (le cas échéant). Le nom, par exemple, le démon secinitd
dans son plist /System/Library/LaunchDaemons/com.apple.secinitd.plist
configure le tuyau appelé com.apple.secinitd
.
Un exemple de xpc_pipe
est le bootstrap pipe créé par launchd
rendant possible le partage des ports Mach.
NSXPC*
Ce sont des objets de haut niveau Objective-C qui permettent l'abstraction des connexions XPC.
De plus, il est plus facile de déboguer ces objets avec DTrace que les précédents.
GCD Queues
XPC utilise GCD pour passer des messages, de plus, il génÚre certaines files d'attente de dispatch comme xpc.transactionq
, xpc.io
, xpc-events.add-listenerq
, xpc.service-instance
...
Services XPC
Ce sont des bundles avec l'extension .xpc
situés dans le dossier XPCServices
d'autres projets et dans le Info.plist
, ils ont le CFBundlePackageType
défini sur XPC!
.
Ce fichier a d'autres clés de configuration comme ServiceType
qui peut ĂȘtre Application, User, System ou _SandboxProfile
qui peut définir un sandbox ou _AllowedClients
qui pourrait indiquer des droits ou des ID requis pour contacter le service. Ces options de configuration et d'autres seront utiles pour configurer le service lors de son lancement.
DĂ©marrer un Service
L'application tente de se connecter Ă un service XPC en utilisant xpc_connection_create_mach_service
, puis launchd localise le démon et démarre xpcproxy
. xpcproxy
applique les restrictions configurées et crée le service avec les FDs et ports Mach fournis.
Afin d'améliorer la vitesse de recherche du service XPC, un cache est utilisé.
Il est possible de tracer les actions de xpcproxy
en utilisant :
supraudit S -C -o /tmp/output /dev/auditpipe
La bibliothĂšque XPC utilise kdebug
pour enregistrer des actions en appelant xpc_ktrace_pid0
et xpc_ktrace_pid1
. Les codes qu'elle utilise ne sont pas documentés, il est donc nécessaire de les ajouter dans /usr/share/misc/trace.codes
. Ils ont le préfixe 0x29
et par exemple, l'un d'eux est 0x29000004
: XPC_serializer_pack
.
L'utilitaire xpcproxy
utilise le préfixe 0x22
, par exemple : 0x2200001c: xpcproxy:will_do_preexec
.
Messages d'événements XPC
Les applications peuvent s'abonner Ă diffĂ©rents messages d'Ă©vĂ©nements, leur permettant d'ĂȘtre initiĂ©s Ă la demande lorsque de tels Ă©vĂ©nements se produisent. La configuration de ces services se fait dans les fichiers plist launchd, situĂ©s dans les mĂȘmes rĂ©pertoires que les prĂ©cĂ©dents et contenant une clĂ© LaunchEvent
supplémentaire.
VĂ©rification du processus de connexion XPC
Lorsqu'un processus essaie d'appeler une méthode via une connexion XPC, le service XPC doit vérifier si ce processus est autorisé à se connecter. Voici les méthodes courantes pour vérifier cela et les piÚges courants :
macOS XPC Connecting Process Check
Autorisation XPC
Apple permet également aux applications de configurer certains droits et comment les obtenir, donc si le processus appelant les a, il serait autorisé à appeler une méthode du service XPC :
Sniffer XPC
Pour intercepter les messages XPC, vous pouvez utiliser xpcspy qui utilise Frida.
# Install
pip3 install xpcspy
pip3 install xpcspy --no-deps # To not make xpcspy install Frida 15 and downgrade your Frida installation
# Start sniffing
xpcspy -U -r -W <bundle-id>
## Using filters (i: for input, o: for output)
xpcspy -U <prog-name> -t 'i:com.apple.*' -t 'o:com.apple.*' -r
Un autre outil possible Ă utiliser est XPoCe2.
Exemple de code C pour la communication XPC
// gcc xpc_server.c -o xpc_server
#include <xpc/xpc.h>
static void handle_event(xpc_object_t event) {
if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
// Print received message
const char* received_message = xpc_dictionary_get_string(event, "message");
printf("Received message: %s\n", received_message);
// Create a response dictionary
xpc_object_t response = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(response, "received", "received");
// Send response
xpc_connection_t remote = xpc_dictionary_get_remote_connection(event);
xpc_connection_send_message(remote, response);
// Clean up
xpc_release(response);
}
}
static void handle_connection(xpc_connection_t connection) {
xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
handle_event(event);
});
xpc_connection_resume(connection);
}
int main(int argc, const char *argv[]) {
xpc_connection_t service = xpc_connection_create_mach_service("xyz.hacktricks.service",
dispatch_get_main_queue(),
XPC_CONNECTION_MACH_SERVICE_LISTENER);
if (!service) {
fprintf(stderr, "Failed to create service.\n");
exit(EXIT_FAILURE);
}
xpc_connection_set_event_handler(service, ^(xpc_object_t event) {
xpc_type_t type = xpc_get_type(event);
if (type == XPC_TYPE_CONNECTION) {
handle_connection(event);
}
});
xpc_connection_resume(service);
dispatch_main();
return 0;
}
# Compile the server & client
gcc xpc_server.c -o xpc_server
gcc xpc_client.c -o xpc_client
# Save server on it's location
cp xpc_server /tmp
# Load daemon
sudo cp xyz.hacktricks.service.plist /Library/LaunchDaemons
sudo launchctl load /Library/LaunchDaemons/xyz.hacktricks.service.plist
# Call client
./xpc_client
# Clean
sudo launchctl unload /Library/LaunchDaemons/xyz.hacktricks.service.plist
sudo rm /Library/LaunchDaemons/xyz.hacktricks.service.plist /tmp/xpc_server
Exemple de code Objective-C pour la communication XPC
// gcc -framework Foundation oc_xpc_server.m -o oc_xpc_server
#include <Foundation/Foundation.h>
@protocol MyXPCProtocol
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply;
@end
@interface MyXPCObject : NSObject <MyXPCProtocol>
@end
@implementation MyXPCObject
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply {
NSLog(@"Received message: %@", some_string);
NSString *response = @"Received";
reply(response);
}
@end
@interface MyDelegate : NSObject <NSXPCListenerDelegate>
@end
@implementation MyDelegate
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyXPCProtocol)];
MyXPCObject *my_object = [MyXPCObject new];
newConnection.exportedObject = my_object;
[newConnection resume];
return YES;
}
@end
int main(void) {
NSXPCListener *listener = [[NSXPCListener alloc] initWithMachServiceName:@"xyz.hacktricks.svcoc"];
id <NSXPCListenerDelegate> delegate = [MyDelegate new];
listener.delegate = delegate;
[listener resume];
sleep(10); // Fake something is done and then it ends
}
# Compile the server & client
gcc -framework Foundation oc_xpc_server.m -o oc_xpc_server
gcc -framework Foundation oc_xpc_client.m -o oc_xpc_client
# Save server on it's location
cp oc_xpc_server /tmp
# Load daemon
sudo cp xyz.hacktricks.svcoc.plist /Library/LaunchDaemons
sudo launchctl load /Library/LaunchDaemons/xyz.hacktricks.svcoc.plist
# Call client
./oc_xpc_client
# Clean
sudo launchctl unload /Library/LaunchDaemons/xyz.hacktricks.svcoc.plist
sudo rm /Library/LaunchDaemons/xyz.hacktricks.svcoc.plist /tmp/oc_xpc_server
Client à l'intérieur d'un code Dylb
// gcc -dynamiclib -framework Foundation oc_xpc_client.m -o oc_xpc_client.dylib
// gcc injection example:
// DYLD_INSERT_LIBRARIES=oc_xpc_client.dylib /path/to/vuln/bin
#import <Foundation/Foundation.h>
@protocol MyXPCProtocol
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply;
@end
__attribute__((constructor))
static void customConstructor(int argc, const char **argv)
{
NSString* _serviceName = @"xyz.hacktricks.svcoc";
NSXPCConnection* _agentConnection = [[NSXPCConnection alloc] initWithMachServiceName:_serviceName options:4096];
[_agentConnection setRemoteObjectInterface:[NSXPCInterface interfaceWithProtocol:@protocol(MyXPCProtocol)]];
[_agentConnection resume];
[[_agentConnection remoteObjectProxyWithErrorHandler:^(NSError* error) {
(void)error;
NSLog(@"Connection Failure");
}] sayHello:@"Hello, Server!" withReply:^(NSString *response) {
NSLog(@"Received response: %@", response);
} ];
NSLog(@"Done!");
return;
}
Remote XPC
Cette fonctionnalité fournie par RemoteXPC.framework
(de libxpc
) permet de communiquer via XPC entre différents hÎtes.
Les services qui prennent en charge le XPC distant auront dans leur plist la clé UsesRemoteXPC comme c'est le cas de /System/Library/LaunchDaemons/com.apple.SubmitDiagInfo.plist
. Cependant, bien que le service soit enregistré avec launchd
, c'est UserEventAgent
avec les plugins com.apple.remoted.plugin
et com.apple.remoteservicediscovery.events.plugin
qui fournit la fonctionnalité.
De plus, le RemoteServiceDiscovery.framework
permet d'obtenir des informations Ă partir du com.apple.remoted.plugin
exposant des fonctions telles que get_device
, get_unique_device
, connect
...
Une fois que connect est utilisé et que le socket fd
du service est récupéré, il est possible d'utiliser la classe remote_xpc_connection_*
.
Il est possible d'obtenir des informations sur les services distants en utilisant l'outil cli /usr/libexec/remotectl
avec des paramĂštres tels que :
/usr/libexec/remotectl list # Get bridge devices
/usr/libexec/remotectl show ...# Get device properties and services
/usr/libexec/remotectl dumpstate # Like dump withuot indicateing a servie
/usr/libexec/remotectl [netcat|relay] ... # Expose a service in a port
...
La communication entre BridgeOS et l'hÎte se fait via une interface IPv6 dédiée. Le MultiverseSupport.framework
permet d'Ă©tablir des sockets dont le fd
sera utilisé pour communiquer.
Il est possible de trouver ces communications en utilisant netstat
, nettop
ou l'option open source, netbottom
.
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- VĂ©rifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépÎts github.