macOS XPC
AWSハッキングをゼロからヒーローまで学ぶには htARTE (HackTricks AWS Red Team Expert) をご覧ください! HackTricksをサポートする他の方法:
HackTricksにあなたの会社を広告掲載したい場合 やHackTricksをPDFでダウンロードしたい場合 は、サブスクリプションプラン をチェックしてください!
基本情報
XPCは、macOSとiOSで使用されるXNU(macOSに使用されるカーネル)のプロセス間通信を意味し、プロセス間の通信 のためのフレームワークです。XPCは、システム上の異なるプロセス間で安全で非同期のメソッド呼び出し を行うためのメカニズムを提供します。これはAppleのセキュリティパラダイムの一部であり、各コンポーネント がその仕事をするために必要な許可だけ を持って実行される特権分離アプリケーションの作成 を可能にし、侵害されたプロセスからの潜在的な損害を制限します。
XPCはプロセス間通信(IPC)の一形態を使用し、これは同じシステム上で実行されている異なるプログラムがデータを行き来させるための方法のセットです。
XPCの主な利点には以下が含まれます:
セキュリティ : 異なるプロセスに作業を分離することで、各プロセスには必要な許可のみが与えられます。これは、プロセスが侵害されても、害を及ぼす能力が限定されることを意味します。
安定性 : XPCはクラッシュを発生したコンポーネントに隔離するのに役立ちます。プロセスがクラッシュしても、システムの残りの部分に影響を与えることなく再起動することができます。
パフォーマンス : XPCは簡単な並行処理を可能にし、異なるタスクを異なるプロセスで同時に実行できます。
唯一の欠点 は、アプリケーションを複数のプロセスに分離し、XPCを介して通信させることが効率が低い ことです。しかし、今日のシステムではほとんど気づかれず、利点の方が優れています。
アプリケーション固有のXPCサービス
アプリケーションの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サービスがそのInfo.plist ファイルでJoinExistingSession を「True」に設定されている場合は例外です。この場合、XPCサービスはそれを呼び出したアプリケーションと同じセキュリティセッションで実行されます。
XPCサービスは必要に応じてlaunchd によって開始され 、すべてのタスクが完了 するとシステムリソースを解放するためにシャットダウンされます。 アプリケーション固有のXPCコンポーネントはアプリケーションによってのみ利用できるため、潜在的な脆弱性に関連するリスクが減少します。
システム全体のXPCサービス
システム全体のXPCサービスはすべてのユーザーがアクセスできます。これらのサービスは、launchdまたはMachタイプであり、/System/Library/LaunchDaemons
、/Library/LaunchDaemons
、/System/Library/LaunchAgents
、または**/Library/LaunchAgents
などの指定されたディレクトリにあるplistファイルで 定義する必要があります。**
これらのplistファイルにはサービスの名前を示す**MachServices
というキーと、バイナリへのパスを示す Program
**というキーがあります:
Copy 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 イベントメッセージ
アプリケーションは異なるイベントメッセージ に登録 することができ、これにより、そのようなイベントが発生したときにオンデマンドで起動 されるようになります。これらのサービスの設定 は、前述のディレクトリと同じディレクトリ にあるlaunchd plistファイル で行われ、追加の**LaunchEvent
**キーが含まれています。
XPC 接続プロセスチェック
プロセスがXPC接続を介してメソッドを呼び出そうとするとき、XPCサービスはそのプロセスが接続を許可されているかどうかをチェックする必要があります 。以下はそのチェックの一般的な方法とよくある落とし穴です:
page macOS XPC Connecting Process Check XPC 認証
Appleはアプリがいくつかの権限を設定し、それらを取得する方法 を設定することも許可しているので、呼び出しプロセスがそれらを持っていれば、XPCサービスからメソッドを呼び出すことが許可されます :
page macOS XPC Authorization XPC スニファー
XPCメッセージをスニッフするには、Frida を使用するxpcspy を使用できます。
Copy # 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-i d >
## Using filters (i: for input, o: for output)
xpcspy -U < prog-nam e > -t 'i:com.apple.*' -t 'o:com.apple.*' -r
XPC通信C言語コード例
xpc_server.c xyz.hacktricks.service.plist
Copy // 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 ;
}
Copy
</div>
<div data-gb-custom-block data-tag="tab" data-title='xpc_client.c'>
Copy // 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 ;
}
Copy <? 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 >
Copy # 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 コード例
oc_xpc_server.m oc_xpc_client.m xyz.hacktricks.svcoc.plist
Copy // 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
}
Copy // 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;
}
Copy <? 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 >
```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
Copy ## Dylb コード内のクライアント
```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;
}
htARTE (HackTricks AWS Red Team Expert)でAWSハッキングをゼロからヒーローまで学ぶ HackTricksをサポートする他の方法:
HackTricksにあなたの会社を広告したい場合 やHackTricksをPDFでダウンロードしたい場合 は、サブスクリプションプラン をチェックしてください!
Last updated 4 months ago