macOS XPC

macOS XPC

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Podstawowe informacje

XPC, co oznacza XNU (jądro używane przez macOS) Inter-Process Communication, to framework do komunikacji między procesami na macOS i iOS. XPC zapewnia mechanizm do bezpiecznych, asynchronicznych wywołań metod między różnymi procesami w systemie. Jest to część paradygmatu bezpieczeństwa Apple, umożliwiająca tworzenie aplikacji z podziałem uprawnień, gdzie każdy komponent działa z tylko tymi uprawnieniami, które są mu potrzebne, ograniczając tym samym potencjalne szkody spowodowane przez skompromitowany proces.

XPC wykorzystuje formę komunikacji międzyprocesowej (IPC), która jest zestawem metod umożliwiających przesyłanie danych między różnymi programami działającymi na tym samym systemie.

Główne korzyści z XPC to:

  1. Bezpieczeństwo: Poprzez rozdzielenie pracy na różne procesy, każdemu procesowi można przyznać tylko te uprawnienia, które są mu potrzebne. Oznacza to, że nawet jeśli proces zostanie skompromitowany, ma ograniczoną zdolność do wyrządzenia szkody.

  2. Stabilność: XPC pomaga izolować awarie do komponentu, w którym występują. Jeśli proces ulegnie awarii, można go ponownie uruchomić, nie wpływając na resztę systemu.

  3. Wydajność: XPC umożliwia łatwą współbieżność, ponieważ różne zadania mogą być wykonywane jednocześnie w różnych procesach.

Jedynym wadą jest to, że rozdzielenie aplikacji na kilka procesów komunikujących się za pomocą XPC jest mniej wydajne. Jednak w dzisiejszych systemach jest to prawie niezauważalne, a korzyści są większe.

Usługi XPC specyficzne dla aplikacji

Komponenty XPC aplikacji znajdują się wewnątrz samej aplikacji. Na przykład w Safari można je znaleźć w /Applications/Safari.app/Contents/XPCServices. Mają rozszerzenie .xpc (np. com.apple.Safari.SandboxBroker.xpc) i są również paczkami z głównym plikiem binarnym wewnątrz: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/MacOS/com.apple.Safari.SandboxBroker oraz Info.plist: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/Info.plist

Jak można się domyślać, komponent XPC będzie miał inne uprawnienia i przywileje niż inne komponenty XPC lub główny plik binarny aplikacji. Z WYJĄTKIEM, jeśli usługa XPC jest skonfigurowana z ustawieniem JoinExistingSession ustawionym na "True" w pliku Info.plist. W tym przypadku usługa XPC będzie działać w tym samym sesji zabezpieczeń co aplikacja, która ją wywołała.

Usługi XPC są uruchamiane przez launchd w razie potrzeby i zamykane, gdy wszystkie zadania są zakończone, aby zwolnić zasoby systemowe. Komponenty XPC specyficzne dla aplikacji mogą być wykorzystywane tylko przez aplikację, co zmniejsza ryzyko związane z potencjalnymi podatnościami.

Usługi XPC na poziomie systemu

Usługi XPC na poziomie systemu są dostępne dla wszystkich użytkowników. Te usługi, zarówno typu launchd, jak i Mach, muszą być zdefiniowane w plikach plist znajdujących się w określonych katalogach, takich jak /System/Library/LaunchDaemons, /Library/LaunchDaemons, /System/Library/LaunchAgents lub /Library/LaunchAgents.

Te pliki plist będą miały klucz o nazwie MachServices z nazwą usługi oraz klucz o nazwie Program z ścieżką do pliku binarnego:

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>

Te znajdujące się w LaunchDameons są uruchamiane przez roota. Jeśli proces bez uprawnień może komunikować się z jednym z nich, może próbować podwyższyć uprawnienia.

Komunikaty zdarzeń XPC

Aplikacje mogą subskrybować różne komunikaty zdarzeń, umożliwiając ich inicjację na żądanie, gdy takie zdarzenia wystąpią. Konfiguracja tych usług odbywa się w plikach plist launchd, znajdujących się w tych samych katalogach i zawierających dodatkowy klucz LaunchEvent.

Sprawdzanie procesu łączącego się przez XPC

Gdy proces próbuje wywołać metodę za pośrednictwem połączenia XPC, usługa XPC powinna sprawdzić, czy ten proces ma uprawnienia do połączenia. Oto powszechne sposoby sprawdzania tego oraz powszechne pułapki:

pagemacOS XPC Connecting Process Check

Autoryzacja XPC

Apple pozwala również aplikacjom konfigurować pewne prawa i sposób ich uzyskania, dzięki czemu jeśli wywołujący proces je posiada, będzie mógł wywołać metodę z usługi XPC:

pagemacOS XPC Authorization

Sniffer XPC

Aby podsłuchiwać komunikaty XPC, można użyć xpcspy, który korzysta z 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

Przykład kodu C do komunikacji 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

Przykład kodu XPC Communication w 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
}

```bash # 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

## Klient wewnątrz kodu Dylb

The Client inside a Dylb code is a technique used in macOS privilege escalation to abuse the XPC service. XPC (Cross-Process Communication) is a mechanism that allows processes to communicate with each other in macOS.

To exploit this technique, the attacker first needs to identify a vulnerable XPC service. This can be done by analyzing the target application or system. Once a vulnerable XPC service is identified, the attacker can create a client inside a Dylb code to interact with the XPC service.

The Dylb code is a dynamic library that is injected into the target process. It allows the attacker to hook into the XPC service and intercept its function calls. By doing so, the attacker can manipulate the data being sent or received by the XPC service.

The client inside the Dylb code can be used to escalate privileges by abusing the XPC service's functionality. For example, the attacker can modify the parameters of a function call to bypass security checks or execute arbitrary code with elevated privileges.

To implement this technique, the attacker needs to have knowledge of macOS internals, XPC service vulnerabilities, and dynamic library injection techniques. It requires advanced skills in macOS exploitation and privilege escalation.

It is important to note that this technique is highly intrusive and can potentially crash the target process or system if not implemented correctly. Therefore, it should only be used in controlled environments for legitimate security testing purposes.
```objectivec
// 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;
}
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated