macOS XPC
Reading time: 14 minutes
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Basic Information
XPC, που σημαίνει XNU (ο πυρήνας που χρησιμοποιείται από το macOS) inter-Process Communication, είναι ένα πλαίσιο για επικοινωνία μεταξύ διεργασιών στο macOS και το iOS. Το XPC παρέχει έναν μηχανισμό για την πραγματοποίηση ασφαλών, ασύγχρονων κλήσεων μεθόδων μεταξύ διαφορετικών διεργασιών στο σύστημα. Είναι μέρος της ασφάλειας της Apple, επιτρέποντας τη δημιουργία εφαρμογών με διαχωρισμένα δικαιώματα όπου κάθε συστατικό εκτελείται με μόνο τα δικαιώματα που χρειάζεται για να κάνει τη δουλειά του, περιορίζοντας έτσι τη δυνητική ζημιά από μια συμβιβασμένη διεργασία.
Το XPC χρησιμοποιεί μια μορφή Επικοινωνίας Μεταξύ Διεργασιών (IPC), η οποία είναι ένα σύνολο μεθόδων για διαφορετικά προγράμματα που εκτελούνται στο ίδιο σύστημα να στέλνουν δεδομένα πίσω και μπροστά.
Τα κύρια οφέλη του XPC περιλαμβάνουν:
- Ασφάλεια: Με τον διαχωρισμό της εργασίας σε διαφορετικές διεργασίες, κάθε διεργασία μπορεί να έχει μόνο τα δικαιώματα που χρειάζεται. Αυτό σημαίνει ότι ακόμη και αν μια διεργασία συμβιβαστεί, έχει περιορισμένη ικανότητα να προκαλέσει ζημιά.
- Σταθερότητα: Το XPC βοηθά στην απομόνωση των κραστών στο συστατικό όπου συμβαίνουν. Αν μια διεργασία κρασάρει, μπορεί να επανεκκινηθεί χωρίς να επηρεάσει το υπόλοιπο σύστημα.
- Απόδοση: Το XPC επιτρέπει εύκολη ταυτόχρονη εκτέλεση, καθώς διαφορετικές εργασίες μπορούν να εκτελούνται ταυτόχρονα σε διαφορετικές διεργασίες.
Η μόνη ανεπιθύμητη συνέπεια είναι ότι ο διαχωρισμός μιας εφαρμογής σε πολλές διεργασίες που επικοινωνούν μέσω XPC είναι λιγότερο αποδοτικός. Αλλά στα σημερινά συστήματα αυτό δεν είναι σχεδόν αισθητό και τα οφέλη είναι καλύτερα.
Application Specific XPC services
Τα XPC συστατικά μιας εφαρμογής είναι μέσα στην ίδια την εφαρμογή. Για παράδειγμα, στο Safari μπορείτε να τα βρείτε σε /Applications/Safari.app/Contents/XPCServices
. Έχουν επέκταση .xpc
(όπως com.apple.Safari.SandboxBroker.xpc
) και είναι επίσης πακέτα με το κύριο δυαδικό αρχείο μέσα σε αυτό: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/MacOS/com.apple.Safari.SandboxBroker
και ένα Info.plist: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/Info.plist
Όπως μπορεί να σκέφτεστε, ένα συστατικό XPC θα έχει διαφορετικά δικαιώματα και προνόμια από τα άλλα συστατικά XPC ή το κύριο δυαδικό αρχείο της εφαρμογής. ΕΚΤΟΣ αν μια υπηρεσία XPC έχει ρυθμιστεί με JoinExistingSession ρυθμισμένο σε “True” στο αρχείο Info.plist της. Σε αυτή την περίπτωση, η υπηρεσία XPC θα εκτελείται στην ίδια ασφαλή συνεδρία με την εφαρμογή που την κάλεσε.
Οι υπηρεσίες XPC ξεκινούνται από launchd όταν απαιτείται και κλείνουν μόλις ολοκληρωθούν όλες οι εργασίες για να απελευθερωθούν οι πόροι του συστήματος. Τα XPC συστατικά που σχετίζονται με την εφαρμογή μπορούν να χρησιμοποιηθούν μόνο από την εφαρμογή, μειώνοντας έτσι τον κίνδυνο που σχετίζεται με πιθανές ευπάθειες.
System Wide XPC services
Οι υπηρεσίες XPC σε επίπεδο συστήματος είναι προσβάσιμες σε όλους τους χρήστες. Αυτές οι υπηρεσίες, είτε launchd είτε τύπου Mach, πρέπει να είναι καθορισμένες σε αρχεία plist που βρίσκονται σε καθορισμένους καταλόγους όπως /System/Library/LaunchDaemons
, /Library/LaunchDaemons
, /System/Library/LaunchAgents
, ή /Library/LaunchAgents
.
Αυτά τα αρχεία plist θα έχουν ένα κλειδί που ονομάζεται MachServices
με το όνομα της υπηρεσίας, και ένα κλειδί που ονομάζεται Program
με τη διαδρομή προς το δυαδικό αρχείο:
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>
Οι διαδικασίες στο LaunchDameons
εκτελούνται από τον root. Έτσι, αν μια διαδικασία χωρίς δικαιώματα μπορεί να επικοινωνήσει με μία από αυτές, θα μπορούσε να είναι σε θέση να κλιμακώσει τα δικαιώματα.
XPC Αντικείμενα
xpc_object_t
Κάθε μήνυμα XPC είναι ένα αντικείμενο λεξικού που απλοποιεί τη σειριοποίηση και την αποσειριοποίηση. Επιπλέον, η libxpc.dylib
δηλώνει τους περισσότερους τύπους δεδομένων, οπότε είναι δυνατό να διασφαλιστεί ότι τα ληφθέντα δεδομένα είναι του αναμενόμενου τύπου. Στο C API, κάθε αντικείμενο είναι ένα xpc_object_t
(και ο τύπος του μπορεί να ελεγχθεί χρησιμοποιώντας xpc_get_type(object)
).
Επιπλέον, η συνάρτηση xpc_copy_description(object)
μπορεί να χρησιμοποιηθεί για να αποκτήσει μια συμβολοσειρά αναπαράστασης του αντικειμένου που μπορεί να είναι χρήσιμη για σκοπούς αποσφαλμάτωσης.
Αυτά τα αντικείμενα έχουν επίσης κάποιες μεθόδους που μπορούν να κληθούν όπως xpc_<object>_copy
, xpc_<object>_equal
, xpc_<object>_hash
, xpc_<object>_serialize
, xpc_<object>_deserialize
...
Τα xpc_object_t
δημιουργούνται καλώντας τη συνάρτηση xpc_<objetType>_create
, η οποία εσωτερικά καλεί το _xpc_base_create(Class, Size)
όπου υποδεικνύεται ο τύπος της κλάσης του αντικειμένου (ένας από τους XPC_TYPE_*
) και το μέγεθός του (κάποια επιπλέον 40B θα προστεθούν στο μέγεθος για μεταδεδομένα). Αυτό σημαίνει ότι τα δεδομένα του αντικειμένου θα ξεκινούν από την απόσταση 40B.
Επομένως, το xpc_<objectType>_t
είναι κάπως μια υποκλάση του xpc_object_t
, η οποία θα ήταν μια υποκλάση του os_object_t*
.
warning
Σημειώστε ότι θα πρέπει να είναι ο προγραμματιστής που χρησιμοποιεί xpc_dictionary_[get/set]_<objectType>
για να αποκτήσει ή να ορίσει τον τύπο και την πραγματική τιμή ενός κλειδιού.
xpc_pipe
Ένα xpc_pipe
είναι ένας σωλήνας FIFO που οι διαδικασίες μπορούν να χρησιμοποιήσουν για να επικοινωνήσουν (η επικοινωνία χρησιμοποιεί μηνύματα Mach).
Είναι δυνατό να δημιουργηθεί ένας XPC server καλώντας xpc_pipe_create()
ή xpc_pipe_create_from_port()
για να τον δημιουργήσει χρησιμοποιώντας μια συγκεκριμένη θύρα Mach. Στη συνέχεια, για να λάβει μηνύματα, είναι δυνατό να καλέσει xpc_pipe_receive
και xpc_pipe_try_receive
.
Σημειώστε ότι το αντικείμενο xpc_pipe
είναι ένα xpc_object_t
με πληροφορίες στη δομή του σχετικά με τις δύο θύρες Mach που χρησιμοποιούνται και το όνομα (αν υπάρχει). Το όνομα, για παράδειγμα, ο daemon secinitd
στο plist του /System/Library/LaunchDaemons/com.apple.secinitd.plist
ρυθμίζει τον σωλήνα που ονομάζεται com.apple.secinitd
.
Ένα παράδειγμα ενός xpc_pipe
είναι ο bootstrap pipe που δημιουργείται από τον launchd
καθιστώντας δυνατή την κοινή χρήση θύρων Mach.
NSXPC*
Αυτά είναι αντικείμενα υψηλού επιπέδου Objective-C που επιτρέπουν την αφαίρεση των συνδέσεων XPC.
Επιπλέον, είναι πιο εύκολο να αποσφαλματωθούν αυτά τα αντικείμενα με το DTrace από τα προηγούμενα.
GCD Queues
Το XPC χρησιμοποιεί GCD για να περάσει μηνύματα, επιπλέον δημιουργεί ορισμένες ουρές εκτέλεσης όπως xpc.transactionq
, xpc.io
, xpc-events.add-listenerq
, xpc.service-instance
...
Υπηρεσίες XPC
Αυτές είναι πακέτα με επέκταση .xpc
που βρίσκονται μέσα στον φάκελο XPCServices
άλλων έργων και στο Info.plist
έχουν τον τύπο πακέτου CFBundlePackageType
ρυθμισμένο σε XPC!
.
Αυτό το αρχείο έχει άλλες ρυθμιστικές κλειδιά όπως ServiceType
που μπορεί να είναι Application, User, System ή _SandboxProfile
που μπορεί να ορίσει ένα sandbox ή _AllowedClients
που μπορεί να υποδεικνύει δικαιώματα ή ID που απαιτούνται για να επικοινωνήσουν με την υπηρεσία. Αυτές και άλλες ρυθμιστικές επιλογές θα είναι χρήσιμες για να ρυθμίσουν την υπηρεσία κατά την εκκίνηση.
Εκκίνηση μιας Υπηρεσίας
Η εφαρμογή προσπαθεί να συνδεθεί με μια υπηρεσία XPC χρησιμοποιώντας xpc_connection_create_mach_service
, στη συνέχεια ο launchd εντοπίζει τον daemon και εκκινεί τον xpcproxy
. Ο xpcproxy
επιβάλλει τις ρυθμισμένες περιορισμούς και δημιουργεί την υπηρεσία με τις παρεχόμενες FDs και θύρες Mach.
Για να βελτιωθεί η ταχύτητα αναζήτησης της υπηρεσίας XPC, χρησιμοποιείται μια κρυφή μνήμη.
Είναι δυνατό να παρακολουθήσετε τις ενέργειες του xpcproxy
χρησιμοποιώντας:
supraudit S -C -o /tmp/output /dev/auditpipe
Η βιβλιοθήκη XPC χρησιμοποιεί kdebug
για να καταγράψει ενέργειες καλώντας xpc_ktrace_pid0
και xpc_ktrace_pid1
. Οι κωδικοί που χρησιμοποιεί δεν είναι τεκμηριωμένοι, επομένως είναι απαραίτητο να τους προσθέσετε στο /usr/share/misc/trace.codes
. Έχουν το πρόθεμα 0x29
και για παράδειγμα ένας είναι 0x29000004
: XPC_serializer_pack
.
Το εργαλείο xpcproxy
χρησιμοποιεί το πρόθεμα 0x22
, για παράδειγμα: 0x2200001c: xpcproxy:will_do_preexec
.
XPC Event Messages
Οι εφαρμογές μπορούν να εγγραφούν σε διάφορα γεγονότα μηνυμάτων, επιτρέποντάς τους να ξεκινούν κατόπιν αιτήματος όταν συμβαίνουν τέτοια γεγονότα. Η ρύθμιση για αυτές τις υπηρεσίες γίνεται σε αρχεία plist του launchd, που βρίσκονται στους ίδιους καταλόγους με τους προηγούμενους και περιέχουν ένα επιπλέον LaunchEvent
κλειδί.
XPC Connecting Process Check
Όταν μια διαδικασία προσπαθεί να καλέσει μια μέθοδο μέσω μιας σύνδεσης XPC, η υπηρεσία XPC θα πρέπει να ελέγξει αν αυτή η διαδικασία επιτρέπεται να συνδεθεί. Ακολουθούν οι κοινές μέθοδοι για να το ελέγξετε και οι κοινές παγίδες:
macOS XPC Connecting Process Check
XPC Authorization
Η Apple επιτρέπει επίσης στις εφαρμογές να ρυθμίζουν ορισμένα δικαιώματα και πώς να τα αποκτούν, έτσι ώστε αν η καλούσα διαδικασία τα έχει, θα επιτρέπεται να καλέσει μια μέθοδο από την υπηρεσία XPC:
XPC Sniffer
Για να καταγράψετε τα μηνύματα XPC, μπορείτε να χρησιμοποιήσετε xpcspy που χρησιμοποιεί 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
Ένα άλλο πιθανό εργαλείο που μπορείτε να χρησιμοποιήσετε είναι το XPoCe2.
Παράδειγμα Κώδικα C για Επικοινωνία 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
XPC Επικοινωνία Παράδειγμα Κώδικα Objective-C
// 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
Πελάτης μέσα σε έναν κώδικα 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
Αυτή η λειτουργία που παρέχεται από το RemoteXPC.framework
(από το libxpc
) επιτρέπει την επικοινωνία μέσω XPC μέσω διαφορετικών hosts.
Οι υπηρεσίες που υποστηρίζουν το remote XPC θα έχουν στο plist τους το κλειδί UsesRemoteXPC όπως είναι η περίπτωση του /System/Library/LaunchDaemons/com.apple.SubmitDiagInfo.plist
. Ωστόσο, αν και η υπηρεσία θα είναι καταχωρημένη με το launchd
, είναι το UserEventAgent
με τα plugins com.apple.remoted.plugin
και com.apple.remoteservicediscovery.events.plugin
που παρέχει τη λειτουργικότητα.
Επιπλέον, το RemoteServiceDiscovery.framework
επιτρέπει την απόκτηση πληροφοριών από το com.apple.remoted.plugin
εκθέτοντας συναρτήσεις όπως get_device
, get_unique_device
, connect
...
Μόλις χρησιμοποιηθεί το connect και συγκεντρωθεί το socket fd
της υπηρεσίας, είναι δυνατή η χρήση της κλάσης remote_xpc_connection_*
.
Είναι δυνατή η απόκτηση πληροφοριών σχετικά με τις απομακρυσμένες υπηρεσίες χρησιμοποιώντας το cli εργαλείο /usr/libexec/remotectl
χρησιμοποιώντας παραμέτρους όπως:
/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
...
Η επικοινωνία μεταξύ του BridgeOS και του κεντρικού υπολογιστή πραγματοποιείται μέσω μιας ειδικής διεπαφής IPv6. Το MultiverseSupport.framework
επιτρέπει τη δημιουργία υποδοχών των οποίων το fd
θα χρησιμοποιηθεί για την επικοινωνία.
Είναι δυνατή η εύρεση αυτών των επικοινωνιών χρησιμοποιώντας το netstat
, nettop
ή την ανοιχτού κώδικα επιλογή, netbottom
.
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.