从零到英雄学习AWS黑客技术,通过 htARTE (HackTricks AWS Red Team Expert) ! 支持HackTricks的其他方式:
如果您想在HackTricks中看到您的公司广告 或以PDF格式下载HackTricks ,请查看订阅计划 !
基本信息
XPC,代表XNU(macOS使用的内核)进程间通信,是macOS和iOS上进程间通信 的框架。XPC提供了一种机制,用于在系统上的不同进程之间进行安全的、异步的方法调用 。它是苹果安全范式的一部分,允许创建权限分离的应用程序 ,其中每个组件 仅运行具有执行其工作所需的权限 ,从而限制了被攻破进程的潜在损害。
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类型,都需要在指定目录中的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 事件消息
应用程序可以订阅 不同的事件消息 ,使它们能够在这些事件发生时按需启动 。这些服务的设置 是在 launchd plist 文件 中完成的,这些文件位于与前面提到的目录相同 ,并包含一个额外的 LaunchEvent
键。
XPC 连接进程检查
当一个进程尝试通过 XPC 连接调用方法时,XPC 服务应该检查该进程是否被允许连接 。以下是常见的检查方式和常见的陷阱:
macOS XPC Connecting Process Check XPC 授权
苹果还允许应用程序配置一些权限以及如何获取它们 ,所以如果调用进程拥有这些权限,它将被允许调用 XPC 服务的方法:
macOS XPC Authorization XPC 嗅探器
要嗅探 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-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 xpc_client.c xyz.hacktricks.service.plist
复制 // 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 ;
}
复制 // 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 ;
}
复制 <? 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 >
复制 # 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
复制 // 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
}
复制 // 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;
}
复制 <? 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
复制 ## 客户端在 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;
}
从零开始学习AWS黑客攻击直至成为专家,通过 htARTE (HackTricks AWS Red Team Expert) ! 支持HackTricks的其他方式:
如果您希望在HackTricks中看到您的公司广告 或下载HackTricks的PDF版本 ,请查看订阅计划 !