21 KiB
macOS XPC
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Temel Bilgiler
XPC, macOS tarafından kullanılan XNU (çekirdek) arasındaki İletişim için bir çerçevedir ve macOS ve iOS'ta işlemler arası iletişim sağlar. XPC, sistemdeki farklı işlemler arasında güvenli, asenkron yöntem çağrıları yapma mekanizması sunar. Bu, her bir bileşenin işini yapmak için gereken izinlerle çalıştığı ayrılmış ayrıcalıklarla uygulamalar oluşturulmasına olanak tanıyarak, tehlikeye atılmış bir işlemin potansiyel zararını sınırlamaktadır.
XPC, aynı sistemde çalışan farklı programların veri göndermesi ve alması için bir dizi yöntem olan İşlemler Arası İletişim (IPC) biçimini kullanır.
XPC'nin başlıca faydaları şunlardır:
- Güvenlik: Çalışmayı farklı işlemlere ayırarak, her bir işleme yalnızca ihtiyaç duyduğu izinler verilebilir. Bu, bir işlem tehlikeye atılsa bile, zarar verme yeteneğinin sınırlı olduğu anlamına gelir.
- Kararlılık: XPC, çökme durumlarını meydana geldiği bileşene izole etmeye yardımcı olur. Bir işlem çökerse, sistemin geri kalanını etkilemeden yeniden başlatılabilir.
- Performans: XPC, farklı görevlerin farklı işlemlerde aynı anda çalıştırılmasına olanak tanıyarak kolay bir eşzamanlılık sağlar.
Tek dezavantaj, bir uygulamayı birkaç işleme ayırmanın ve bunların XPC aracılığıyla iletişim kurmasının daha az verimli olmasıdır. Ancak günümüz sistemlerinde bu neredeyse fark edilmez ve faydalar daha iyidir.
Uygulama Özel XPC hizmetleri
Bir uygulamanın XPC bileşenleri uygulamanın kendisinin içindedir. Örneğin, Safari'de bunları /Applications/Safari.app/Contents/XPCServices
dizininde bulabilirsiniz. .xpc
uzantısına sahiptirler (örneğin com.apple.Safari.SandboxBroker.xpc
) ve ana ikili dosya ile birlikte paketlenmiştir: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/MacOS/com.apple.Safari.SandboxBroker
ve bir Info.plist: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/Info.plist
Bir XPC bileşeninin diğer XPC bileşenlerinden veya ana uygulama ikili dosyasından farklı haklara ve ayrıcalıklara sahip olacağını düşünebilirsiniz. EXCEPT bir XPC hizmeti, Info.plist dosyasında JoinExistingSession True olarak ayarlandığında. Bu durumda, XPC hizmeti, onu çağıran uygulama ile aynı güvenlik oturumunda çalışacaktır.
XPC hizmetleri, gerektiğinde launchd tarafından başlatılır ve tüm görevler tamamlandığında sistem kaynaklarını serbest bırakmak için kapalı tutulur. Uygulama özel XPC bileşenleri yalnızca uygulama tarafından kullanılabilir, böylece potansiyel güvenlik açıklarıyla ilişkili riski azaltır.
Sistem Genelinde XPC hizmetleri
Sistem genelindeki XPC hizmetleri tüm kullanıcılar tarafından erişilebilir. Bu hizmetler, ya launchd ya da Mach türünde olup, /System/Library/LaunchDaemons
, /Library/LaunchDaemons
, /System/Library/LaunchAgents
veya /Library/LaunchAgents
gibi belirli dizinlerde bulunan plist dosyalarında tanımlanmalıdır.
Bu plist dosyalarında, hizmetin adıyla birlikte MachServices
adında bir anahtar ve ikili dosyanın yolunu içeren Program
adında bir anahtar bulunacaktır:
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>
The ones in LaunchDameons
root tarafından çalıştırılır. Yani, yetkisiz bir işlem bunlardan biriyle iletişim kurabiliyorsa, yetkileri artırma olanağına sahip olabilir.
XPC Nesneleri
xpc_object_t
Her XPC mesajı, serileştirme ve serileştirmeyi basitleştiren bir sözlük nesnesidir. Ayrıca, libxpc.dylib
çoğu veri türünü tanımlar, bu nedenle alınan verilerin beklenen türde olması sağlanabilir. C API'sinde her nesne bir xpc_object_t
'dir (ve türü xpc_get_type(object)
kullanılarak kontrol edilebilir).
Ayrıca, xpc_copy_description(object)
fonksiyonu, hata ayıklama amaçları için yararlı olabilecek nesnenin bir dize temsilini almak için kullanılabilir.
Bu nesnelerin ayrıca xpc_<object>_copy
, xpc_<object>_equal
, xpc_<object>_hash
, xpc_<object>_serialize
, xpc_<object>_deserialize
gibi çağrılacak bazı yöntemleri vardır...
xpc_object_t
nesneleri, xpc_<objetType>_create
fonksiyonu çağrılarak oluşturulur; bu, içsel olarak _xpc_base_create(Class, Size)
fonksiyonunu çağırır ve burada nesnenin sınıf türü (bir XPC_TYPE_*
türü) ve boyutu belirtilir (metadata için ekstra 40B eklenir). Bu, nesnenin verilerinin 40B'lik bir ofsetten başlayacağı anlamına gelir.
Bu nedenle, xpc_<objectType>_t
, xpc_object_t
'nin bir alt sınıfı gibi bir şeydir ve bu da os_object_t*
'nin bir alt sınıfı olacaktır.
{% hint style="warning" %}
Anahtarın türünü ve gerçek değerini almak veya ayarlamak için xpc_dictionary_[get/set]_<objectType>
kullananın geliştirici olması gerektiğini unutmayın.
{% endhint %}
xpc_pipe
Bir xpc_pipe
, işlemlerin iletişim kurmak için kullanabileceği bir FIFO borusudur (iletişim Mach mesajlarını kullanır).
Bir XPC sunucusu oluşturmak için xpc_pipe_create()
veya belirli bir Mach portu kullanarak oluşturmak için xpc_pipe_create_from_port()
çağrısı yapılabilir. Ardından, mesajları almak için xpc_pipe_receive
ve xpc_pipe_try_receive
çağrılabilir.
xpc_pipe
nesnesinin, kullanılan iki Mach portu ve adı (varsa) hakkında bilgileri içeren bir xpc_object_t
olduğunu unutmayın. Örneğin, plist'inde /System/Library/LaunchDaemons/com.apple.secinitd.plist
bulunan secinitd
daemon'u, com.apple.secinitd
adında bir boru yapılandırır.
Bir xpc_pipe
örneği, Mach portlarını paylaşmayı mümkün kılan launchd
tarafından oluşturulan bootstrap pipe'dır.
NSXPC*
Bunlar, XPC bağlantılarının soyutlanmasını sağlayan Objective-C yüksek seviyeli nesnelerdir.
Ayrıca, bu nesneleri DTrace ile hata ayıklamak, önceki nesnelerden daha kolaydır.
GCD Kuyrukları
XPC, mesajları iletmek için GCD kullanır, ayrıca xpc.transactionq
, xpc.io
, xpc-events.add-listenerq
, xpc.service-instance
gibi belirli dağıtım kuyrukları oluşturur...
XPC Hizmetleri
Bunlar, diğer projelerin XPCServices
klasöründe bulunan .xpc
uzantılı paketlerdir ve Info.plist
dosyasında CFBundlePackageType
XPC!
olarak ayarlanmıştır.
Bu dosya, uygulama, kullanıcı, sistem veya bir sandbox tanımlayabilen _SandboxProfile
gibi diğer yapılandırma anahtarlarına sahiptir veya hizmete erişmek için gerekli olan haklar veya kimlikleri belirtebilecek _AllowedClients
anahtarına sahiptir. Bu ve diğer yapılandırma seçenekleri, hizmet başlatıldığında yapılandırmak için yararlı olacaktır.
Bir Hizmeti Başlatma
Uygulama, xpc_connection_create_mach_service
kullanarak bir XPC hizmetine bağlanmaya çalışır, ardından launchd daemon'u bulur ve xpcproxy
'yi başlatır. xpcproxy
, yapılandırılmış kısıtlamaları uygular ve sağlanan FD'ler ve Mach portları ile hizmeti başlatır.
XPC hizmetinin arama hızını artırmak için bir önbellek kullanılır.
xpcproxy
'nin eylemlerini izlemek mümkündür:
supraudit S -C -o /tmp/output /dev/auditpipe
XPC kütüphanesi, xpc_ktrace_pid0
ve xpc_ktrace_pid1
çağrılarıyla eylemleri günlüğe kaydetmek için kdebug
kullanır. Kullandığı kodlar belgelenmemiştir, bu nedenle bunları /usr/share/misc/trace.codes
dosyasına eklemek gereklidir. 0x29
ön ekine sahiptirler ve örneğin biri 0x29000004
: XPC_serializer_pack
'dır.
xpcproxy
aracı 0x22
ön ekini kullanır, örneğin: 0x2200001c: xpcproxy:will_do_preexec
.
XPC Olay Mesajları
Uygulamalar, böyle olaylar gerçekleştiğinde talep üzerine başlatılmalarını sağlayan farklı olay mesajlarına abone olabilirler. Bu hizmetlerin kurulumu, önceki dosyalarla aynı dizinlerde bulunan launchd plist dosyalarında yapılır ve ekstra bir LaunchEvent
anahtarı içerir.
XPC Bağlantı Süreci Kontrolü
Bir süreç, bir XPC bağlantısı aracılığıyla bir yöntemi çağırmaya çalıştığında, XPC hizmeti o sürecin bağlanmasına izin verilip verilmediğini kontrol etmelidir. Bunu kontrol etmenin yaygın yolları ve yaygın tuzaklar şunlardır:
{% content-ref url="macos-xpc-connecting-process-check/" %} macos-xpc-connecting-process-check {% endcontent-ref %}
XPC Yetkilendirmesi
Apple, uygulamaların bazı hakları yapılandırmalarına ve bunları nasıl alacaklarına izin verir, böylece çağıran süreç bu haklara sahipse, XPC hizmetinden bir yöntemi çağırmasına izin verilir:
{% content-ref url="macos-xpc-authorization.md" %} macos-xpc-authorization.md {% endcontent-ref %}
XPC Sniffer
XPC mesajlarını dinlemek için xpcspy kullanabilirsiniz, bu araç Frida kullanır.
# 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
Başka bir kullanılabilir araç XPoCe2.
XPC İletişim C Kodu Örneği
{% tabs %} {% tab title="xpc_server.c" %}
// 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;
}
{% endtab %}
{% tab title="xpc_client.c" %}
// gcc xpc_client.c -o xpc_client
#include <xpc/xpc.h>
int main(int argc, const char *argv[]) {
xpc_connection_t connection = xpc_connection_create_mach_service("xyz.hacktricks.service", NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
// Print received message
const char* received_message = xpc_dictionary_get_string(event, "received");
printf("Received message: %s\n", received_message);
}
});
xpc_connection_resume(connection);
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(message, "message", "Hello, Server!");
xpc_connection_send_message(connection, message);
dispatch_main();
return 0;
}
{% endtab %}
{% tab title="xyz.hacktricks.service.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>Label</key>
<string>xyz.hacktricks.service</string>
<key>MachServices</key>
<dict>
<key>xyz.hacktricks.service</key>
<true/>
</dict>
<key>Program</key>
<string>/tmp/xpc_server</string>
<key>ProgramArguments</key>
<array>
<string>/tmp/xpc_server</string>
</array>
</dict>
</plist>
{% endtab %} {% endtabs %}
# 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 İletişimi Objective-C Kod Örneği
{% tabs %} {% tab title="oc_xpc_server.m" %}
// 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
}
{% endtab %}
{% tab title="oc_xpc_client.m" %}
// gcc -framework Foundation oc_xpc_client.m -o oc_xpc_client
#include <Foundation/Foundation.h>
@protocol MyXPCProtocol
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply;
@end
int main(void) {
NSXPCConnection *connection = [[NSXPCConnection alloc] initWithMachServiceName:@"xyz.hacktricks.svcoc" options:NSXPCConnectionPrivileged];
connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyXPCProtocol)];
[connection resume];
[[connection remoteObjectProxy] sayHello:@"Hello, Server!" withReply:^(NSString *response) {
NSLog(@"Received response: %@", response);
}];
[[NSRunLoop currentRunLoop] run];
return 0;
}
{% endtab %}
{% tab title="xyz.hacktricks.svcoc.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>Label</key>
<string>xyz.hacktricks.svcoc</string>
<key>MachServices</key>
<dict>
<key>xyz.hacktricks.svcoc</key>
<true/>
</dict>
<key>Program</key>
<string>/tmp/oc_xpc_server</string>
<key>ProgramArguments</key>
<array>
<string>/tmp/oc_xpc_server</string>
</array>
</dict>
</plist>
{% endtab %} {% endtabs %}
# 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 kodu içindeki İstemci
// 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
(from libxpc
) tarafından sağlanan bu işlevsellik, farklı ana bilgisayarlar aracılığıyla XPC ile iletişim kurmayı sağlar.
Uzaktan XPC'yi destekleyen hizmetler, plist'lerinde UsesRemoteXPC
anahtarına sahip olacaktır; bu, /System/Library/LaunchDaemons/com.apple.SubmitDiagInfo.plist
dosyasında olduğu gibi. Ancak, hizmet launchd
ile kaydedilmiş olsa da, işlevselliği sağlayan UserEventAgent
'dir; bu, com.apple.remoted.plugin
ve com.apple.remoteservicediscovery.events.plugin
eklentilerini içerir.
Ayrıca, RemoteServiceDiscovery.framework
, com.apple.remoted.plugin
'den bilgi almayı sağlar ve get_device
, get_unique_device
, connect
gibi işlevleri açığa çıkarır...
Bağlantı kullanıldığında ve hizmetin soket fd
'si toplandığında, remote_xpc_connection_*
sınıfı kullanılabilir.
Uzaktan hizmetler hakkında bilgi almak için /usr/libexec/remotectl
cli aracını kullanarak şu parametreler ile bilgi almak mümkündür:
/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 ile ana bilgisayar arasındaki iletişim, özel bir IPv6 arayüzü üzerinden gerçekleşir. MultiverseSupport.framework
, iletişim için kullanılacak fd
'ye sahip soketlerin kurulmasına olanak tanır.
Bu iletişimleri netstat
, nettop
veya açık kaynak seçeneği netbottom
kullanarak bulmak mümkündür.
{% hint style="success" %}
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.