GITBOOK-3940: change request with no subject merged in GitBook
This commit is contained in:
parent
008b95b536
commit
4f476c2d8e
|
@ -142,7 +142,9 @@
|
|||
* [macOS Dyld Hijacking & DYLD\_INSERT\_LIBRARIES](macos-hardening/macos-security-and-privilege-escalation/macos-dyld-hijacking-and-dyld\_insert\_libraries.md)
|
||||
* [macOS Architecture](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/README.md)
|
||||
* [macOS Bundles](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-bundles.md)
|
||||
* [macOS IPC - Inter Process Communication](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-ipc-inter-process-communication.md)
|
||||
* [macOS IPC - Inter Process Communication](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-ipc-inter-process-communication/README.md)
|
||||
* [macOS XPC Connecting Process Check](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-ipc-inter-process-communication/macos-xpc-connecting-process-check.md)
|
||||
* [macOS XPC Authorization](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-ipc-inter-process-communication/macos-xpc-authorization.md)
|
||||
* [macOS Function Hooking](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-function-hooking.md)
|
||||
* [Universal binaries & Mach-O Format](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/universal-binaries-and-mach-o-format.md)
|
||||
* [macOS MDM](macos-hardening/macos-security-and-privilege-escalation/macos-mdm/README.md)
|
||||
|
|
|
@ -84,8 +84,8 @@ kextunload com.apple.iokit.IOReportFamily
|
|||
|
||||
### IPC - Inter Process Communication
|
||||
|
||||
{% content-ref url="macos-ipc-inter-process-communication.md" %}
|
||||
[macos-ipc-inter-process-communication.md](macos-ipc-inter-process-communication.md)
|
||||
{% content-ref url="macos-ipc-inter-process-communication/" %}
|
||||
[macos-ipc-inter-process-communication](macos-ipc-inter-process-communication/)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Apple Propietary File System (APFS)
|
||||
|
|
|
@ -256,7 +256,7 @@ int main(int argc, const char * argv[]) {
|
|||
|
||||
In this page different ways to hook functions were discussed. However, they involved **running code inside the process to attack**.
|
||||
|
||||
In order to do that the easiest technique to use is to inject a [Dyld via environment variables or hijacking](../macos-dyld-hijacking-and-dyld\_insert\_libraries.md). However, I guess this could also be done via [Dylib process injection](macos-ipc-inter-process-communication.md#dylib-process-injection-via-task-port).
|
||||
In order to do that the easiest technique to use is to inject a [Dyld via environment variables or hijacking](../macos-dyld-hijacking-and-dyld\_insert\_libraries.md). However, I guess this could also be done via [Dylib process injection](macos-ipc-inter-process-communication/#dylib-process-injection-via-task-port).
|
||||
|
||||
However, both options are **limited** to **unprotected** binaries/processes. Check each technique to learn more about the limitations.
|
||||
|
||||
|
|
|
@ -197,8 +197,8 @@ int main() {
|
|||
|
||||
You can grab a shellcode from:
|
||||
|
||||
{% content-ref url="../macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md" %}
|
||||
[arm64-basic-assembly.md](../macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md)
|
||||
{% content-ref url="../../macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md" %}
|
||||
[arm64-basic-assembly.md](../../macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
{% tabs %}
|
||||
|
@ -411,8 +411,8 @@ It was possible to **inject a simple shellcode** to execute a command because it
|
|||
|
||||
You can find **example dylibs** in (for example the one that generates a log and then you can listen to it):
|
||||
|
||||
{% content-ref url="../macos-dyld-hijacking-and-dyld_insert_libraries.md" %}
|
||||
[macos-dyld-hijacking-and-dyld\_insert\_libraries.md](../macos-dyld-hijacking-and-dyld\_insert\_libraries.md)
|
||||
{% content-ref url="../../macos-dyld-hijacking-and-dyld_insert_libraries.md" %}
|
||||
[macos-dyld-hijacking-and-dyld\_insert\_libraries.md](../../macos-dyld-hijacking-and-dyld\_insert\_libraries.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
<details>
|
||||
|
@ -769,72 +769,21 @@ The ones in **`LaunchDameons`** are run by root. So if an unprivileged process c
|
|||
|
||||
Applications can **subscribe** to different event **messages**, enabling them to be **initiated on-demand** when such events happen. The **setup** for these services is done in l**aunchd plist files**, located in the **same directories as the previous ones** and containing an extra **`LaunchEvent`** key.
|
||||
|
||||
### XPC Security
|
||||
### XPC Connecting Process Check
|
||||
|
||||
When a connection is stablished to an XPC service, the server will check if the connection is allowed. These are the checks it would usually perform:
|
||||
When a process tries to call a method from via an XPC connection, the **XPC service should check if that process is allowed to connect**. Here are the common ways to check that and the common pitfalls:
|
||||
|
||||
1. Check if the connecting **process is signed with an Apple-signed** certificate (only given out by Apple).
|
||||
* If this **isn't verified**, an attacker could can create a **fake certificate** to match any other check.
|
||||
2. Check if the connecting process is signed with the **organization’s certificate**, (team ID verification).
|
||||
* If this **isn't verified**, **any developer certificate** from Apple can be used for signing, and connect to the service.
|
||||
3. Check if the connecting process **contains a proper bundle ID**.
|
||||
4. Check if the connecting process has a **proper software version number**.
|
||||
* If this **isn't verified,** an old, insecure clients, vulnerable to process injection could be used to connect to the XPC service even with the other checks in place.
|
||||
5. Check if the connecting process has an **entitlement** that allows it to connect to the service. This is applicable for Apple binaries.
|
||||
6. The **verification** must be **based** on the connecting **client’s audit token** **instead** of its process ID (**PID**) since the former prevents PID reuse attacks.
|
||||
* Developers rarely use the audit token API call since it’s **private**, so Apple could **change** at any time. Additionally, private API usage is not allowed in Mac App Store apps.
|
||||
{% content-ref url="macos-xpc-connecting-process-check.md" %}
|
||||
[macos-xpc-connecting-process-check.md](macos-xpc-connecting-process-check.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
The server will implement this **verification** in a function called **`shouldAcceptNewConnection`**.
|
||||
### XPC Authorization
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```objectivec
|
||||
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
|
||||
//Check connection
|
||||
return YES;
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
Apple also allows apps to **configure some rights and how to get them** so if the calling process have them it would be **allowed to call a method** from the XPC service:
|
||||
|
||||
The object NSXPCConnection has a **private** property **`auditToken`** (the one that should be used but could change) and a the **public** property **`processIdentifier`** (the one that shouldn't be used).
|
||||
|
||||
The connecting process could be verified with something like:
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```objectivec
|
||||
[...]
|
||||
SecRequirementRef requirementRef = NULL;
|
||||
NSString requirementString = @"anchor apple generic and identifier \"xyz.hacktricks.service\" and certificate leaf [subject.CN] = \"TEAMID\" and info [CFBundleShortVersionString] >= \"1.0\"";
|
||||
/* Check:
|
||||
- Signed by a cert signed by Apple
|
||||
- Check the bundle ID
|
||||
- Check the TEAMID of the signing cert
|
||||
- Check the version used
|
||||
*/
|
||||
|
||||
// Check the requirements
|
||||
SecRequirementCreateWithString(requirementString, kSecCSDefaultFlags, &requirementRef);
|
||||
SecCodeCheckValidity(code, kSecCSDefaultFlags, requirementRef);
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
If a developer doesn't want to ceck the version of the client, he could check that the client is not vulnerable to process injection at least:
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```objectivec
|
||||
[...]
|
||||
CFDictionaryRef csInfo = NULL;
|
||||
SecCodeCopySigningInformation(code, kSecCSDynamicInformation, &csInfo);
|
||||
uint32_t csFlags = [((__bridge NSDictionary *)csInfo)[(__bridge NSString *)kSecCodeInfoStatus] intValue];
|
||||
const uint32_t cs_hard = 0x100; // don't load invalid page.
|
||||
const uint32_t cs_kill = 0x200; // Kill process if page is invalid
|
||||
const uint32_t cs_restrict = 0x800; // Prevent debugging
|
||||
const uint32_t cs_require_lv = 0x2000; // Library Validation
|
||||
const uint32_t cs_runtime = 0x10000; // hardened runtime
|
||||
if ((csFlags & (cs_hard | cs_require_lv)) {
|
||||
return Yes; // Accept connection
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
{% content-ref url="macos-xpc-authorization.md" %}
|
||||
[macos-xpc-authorization.md](macos-xpc-authorization.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
### C Code Example
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
# macOS XPC Authorization
|
||||
|
||||
<details>
|
||||
|
||||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||||
|
||||
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
|
||||
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
||||
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Share your hacking tricks by submitting PRs to the** [**hacktricks repo**](https://github.com/carlospolop/hacktricks) **and** [**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
||||
|
||||
## XPC Authorization
|
||||
|
||||
Apple also proposes another way to authenticate if the connecting process has **permissions to call the an exposed XPC method**.
|
||||
|
||||
When an application needs to **execute actions as a privileged user**, instead of running the app as a privileged user it usually installs as root a HelperTool as an XPC service that could be acalled from the app to perform those actions. However, the app calling the service should have enough authorization.
|
||||
|
||||
### ShuoldAcceptNewConnection always YES
|
||||
|
||||
An example could be found in [EvenBetterAuthorizationSample](https://github.com/brenwell/EvenBetterAuthorizationSample). In `App/AppDelegate.m` it tries to **connect** to the **HelperTool**. And in `HelperTool/HelperTool.m` the function **`shouldAcceptNewConnection`** **won't check** any of the requirements indicated previously. It'll always return YES:
|
||||
|
||||
```objectivec
|
||||
- (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:
|
||||
|
||||
{% content-ref url="macos-xpc-connecting-process-check.md" %}
|
||||
[macos-xpc-connecting-process-check.md](macos-xpc-connecting-process-check.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
### Application rights
|
||||
|
||||
However, there is some **authorization going on when a method from the HelperTool is called**.
|
||||
|
||||
The function **`applicationDidFinishLaunching`** from `App/AppDelegate.m` will create an empty authorization reference after the app has started. This should always work.\
|
||||
Then, it will try to **add some rights** to that authorization reference calling `setupAuthorizationRights`:
|
||||
|
||||
```objectivec
|
||||
- (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];
|
||||
}
|
||||
```
|
||||
|
||||
The function `setupAuthorizationRights` from `Common/Common.m` will store in the auth database `/var/db/auth.db` the rights of the application. Note how it will only add the rights that aren't yet in the database:
|
||||
|
||||
```objectivec
|
||||
+ (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.
|
||||
}
|
||||
}];
|
||||
}
|
||||
```
|
||||
|
||||
The function `enumerateRightsUsingBlock` is the one used to get applications permissions, which are defined in `commandInfo`:
|
||||
|
||||
```objectivec
|
||||
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);
|
||||
}];
|
||||
}
|
||||
```
|
||||
|
||||
This means that at the end of this process, the permissions declared inside `commandInfo` will be stored in `/var/db/auth.db`. Note how there you can find for **each method** that will r**equire authentication**, **permission name** and the **`kCommandKeyAuthRightDefault`**. The later one **indicates who can get this right**.
|
||||
|
||||
There are different scopes to indicate who can access a right. They are defined in [AuthorizationDB.h](https://github.com/aosm/Security/blob/master/Security/libsecurity\_authorization/lib/AuthorizationDB.h), but as summary:
|
||||
|
||||
| Name | Value | Description |
|
||||
| ------------------------------------------- | -------------------------- | ------------------------------------------------- |
|
||||
| kAuthorizationRuleClassAllow | allow | Anyone |
|
||||
| kAuthorizationRuleClassDeny | deny | Nobody |
|
||||
| kAuthorizationRuleIsAdmin | is-admin | Current user needs to be an admin |
|
||||
| kAuthorizationRuleAuthenticateAsSessionUser | authenticate-session-owner | Ask user to authenticate. |
|
||||
| kAuthorizationRuleAuthenticateAsAdmin | authenticate-admin | Ask user to authenticate. He needs to be an admin |
|
||||
| kAuthorizationRightRule | rule | Specify rules |
|
||||
| kAuthorizationComment | comment | Specify some extra comments on the right |
|
||||
|
||||
### Rights Verification
|
||||
|
||||
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`**:
|
||||
|
||||
```objectivec
|
||||
- (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 **check the requirements to get the right** to call that method the function `authorizationRightForCommand` will just check the previously comment object **`commandInfo`**.
|
||||
|
||||
In this case, to call the function `readLicenseKeyAuthorization` the `kCommandKeyAuthRightDefault` is defined to `@kAuthorizationRuleClassAllow`. So **anyone can call it**.
|
||||
|
||||
<details>
|
||||
|
||||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||||
|
||||
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
|
||||
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
||||
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Share your hacking tricks by submitting PRs to the** [**hacktricks repo**](https://github.com/carlospolop/hacktricks) **and** [**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
|
@ -0,0 +1,94 @@
|
|||
# macOS XPC Connecting Process Check
|
||||
|
||||
<details>
|
||||
|
||||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||||
|
||||
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
|
||||
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
||||
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Share your hacking tricks by submitting PRs to the** [**hacktricks repo**](https://github.com/carlospolop/hacktricks) **and** [**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
||||
|
||||
## XPC Connecting Process Check
|
||||
|
||||
When a connection is stablished to an XPC service, the server will check if the connection is allowed. These are the checks it would usually perform:
|
||||
|
||||
1. Check if the connecting **process is signed with an Apple-signed** certificate (only given out by Apple).
|
||||
* If this **isn't verified**, an attacker could can create a **fake certificate** to match any other check.
|
||||
2. Check if the connecting process is signed with the **organization’s certificate**, (team ID verification).
|
||||
* If this **isn't verified**, **any developer certificate** from Apple can be used for signing, and connect to the service.
|
||||
3. Check if the connecting process **contains a proper bundle ID**.
|
||||
4. Check if the connecting process has a **proper software version number**.
|
||||
* If this **isn't verified,** an old, insecure clients, vulnerable to process injection could be used to connect to the XPC service even with the other checks in place.
|
||||
5. Check if the connecting process has an **entitlement** that allows it to connect to the service. This is applicable for Apple binaries.
|
||||
6. The **verification** must be **based** on the connecting **client’s audit token** **instead** of its process ID (**PID**) since the former prevents PID reuse attacks.
|
||||
* Developers rarely use the audit token API call since it’s **private**, so Apple could **change** at any time. Additionally, private API usage is not allowed in Mac App Store apps.
|
||||
|
||||
### Code Examples
|
||||
|
||||
The server will implement this **verification** in a function called **`shouldAcceptNewConnection`**.
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```objectivec
|
||||
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
|
||||
//Check connection
|
||||
return YES;
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
The object NSXPCConnection has a **private** property **`auditToken`** (the one that should be used but could change) and a the **public** property **`processIdentifier`** (the one that shouldn't be used).
|
||||
|
||||
The connecting process could be verified with something like:
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```objectivec
|
||||
[...]
|
||||
SecRequirementRef requirementRef = NULL;
|
||||
NSString requirementString = @"anchor apple generic and identifier \"xyz.hacktricks.service\" and certificate leaf [subject.CN] = \"TEAMID\" and info [CFBundleShortVersionString] >= \"1.0\"";
|
||||
/* Check:
|
||||
- Signed by a cert signed by Apple
|
||||
- Check the bundle ID
|
||||
- Check the TEAMID of the signing cert
|
||||
- Check the version used
|
||||
*/
|
||||
|
||||
// Check the requirements
|
||||
SecRequirementCreateWithString(requirementString, kSecCSDefaultFlags, &requirementRef);
|
||||
SecCodeCheckValidity(code, kSecCSDefaultFlags, requirementRef);
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
If a developer doesn't want to check the version of the client, he could check that the client is not vulnerable to process injection at least:
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```objectivec
|
||||
[...]
|
||||
CFDictionaryRef csInfo = NULL;
|
||||
SecCodeCopySigningInformation(code, kSecCSDynamicInformation, &csInfo);
|
||||
uint32_t csFlags = [((__bridge NSDictionary *)csInfo)[(__bridge NSString *)kSecCodeInfoStatus] intValue];
|
||||
const uint32_t cs_hard = 0x100; // don't load invalid page.
|
||||
const uint32_t cs_kill = 0x200; // Kill process if page is invalid
|
||||
const uint32_t cs_restrict = 0x800; // Prevent debugging
|
||||
const uint32_t cs_require_lv = 0x2000; // Library Validation
|
||||
const uint32_t cs_runtime = 0x10000; // hardened runtime
|
||||
if ((csFlags & (cs_hard | cs_require_lv)) {
|
||||
return Yes; // Accept connection
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
<details>
|
||||
|
||||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||||
|
||||
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
|
||||
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
||||
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Share your hacking tricks by submitting PRs to the** [**hacktricks repo**](https://github.com/carlospolop/hacktricks) **and** [**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
Loading…
Reference in New Issue