* 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)!
* **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).
O Mach usa **tarefas** como a **unidade mínima** para compartilhar recursos, e cada tarefa pode conter **várias threads**. Essas **tarefas e threads são mapeadas em um para um com processos e threads POSIX**.
A comunicação entre tarefas ocorre por meio da Comunicação Interprocessos (IPC) do Mach, utilizando canais de comunicação unidirecionais. **As mensagens são transferidas entre portas**, que funcionam como **filas de mensagens** gerenciadas pelo kernel.
Os direitos de porta, que definem quais operações uma tarefa pode executar, são fundamentais para essa comunicação. Os possíveis **direitos de porta** são:
* **Direito de recebimento**, que permite receber mensagens enviadas para a porta. As portas Mach são filas MPSC (múltiplos produtores, único consumidor), o que significa que pode haver apenas **um direito de recebimento para cada porta** em todo o sistema (ao contrário de pipes, onde vários processos podem ter descritores de arquivo para a extremidade de leitura de um pipe).
* Uma **tarefa com o direito de recebimento** pode receber mensagens e **criar direitos de envio**, permitindo o envio de mensagens. Originalmente, apenas a **própria tarefa tem o direito de recebimento sobre sua porta**.
* **Direito de envio**, que permite enviar mensagens para a porta.
* O direito de envio pode ser **clonado**, para que uma tarefa que possui um direito de envio possa clonar o direito e **concedê-lo a uma terceira tarefa**.
* **Direito de envio único**, que permite enviar uma mensagem para a porta e depois desaparece.
* **Direito de conjunto de portas**, que denota um _conjunto de portas_ em vez de uma única porta. Desenfileirar uma mensagem de um conjunto de portas desenfileira uma mensagem de uma das portas que ele contém. Conjuntos de portas podem ser usados para escutar várias portas simultaneamente, de forma semelhante a `select`/`poll`/`epoll`/`kqueue` no Unix.
* **Nome morto**, que não é um direito de porta real, mas apenas um espaço reservado. Quando uma porta é destruída, todos os direitos de porta existentes para a porta se tornam nomes mortos.
**As tarefas podem transferir direitos de ENVIO para outros**, permitindo que eles enviem mensagens de volta. **Os direitos de ENVIO também podem ser clonados, para que uma tarefa possa duplicar e dar o direito a uma terceira tarefa**. Isso, combinado com um processo intermediário conhecido como **servidor de inicialização**, permite uma comunicação eficaz entre tarefas.
1. A tarefa **A** inicia uma **nova porta**, obtendo um **direito de RECEBIMENTO** no processo.
2. A tarefa **A**, sendo a detentora do direito de RECEBIMENTO, **gera um direito de ENVIO para a porta**.
3. A tarefa **A** estabelece uma **conexão** com o **servidor de inicialização**, fornecendo o **nome do serviço da porta** e o **direito de ENVIO** por meio de um procedimento conhecido como registro de inicialização.
4. A tarefa **B** interage com o **servidor de inicialização** para executar uma **busca de inicialização para o serviço**. Se bem-sucedido, o **servidor duplica o direito de ENVIO** recebido da Tarefa A e o **transmite para a Tarefa B**.
5. Ao adquirir um direito de ENVIO, a tarefa **B** é capaz de **formular** uma **mensagem** e enviá-la **para a Tarefa A**.
O servidor de inicialização **não pode autenticar** o nome do serviço reivindicado por uma tarefa. Isso significa que uma **tarefa** poderia potencialmente **se passar por qualquer tarefa do sistema**, como reivindicar falsamente um nome de serviço de autorização e, em seguida, aprovar todas as solicitações.
Em seguida, a Apple armazena os **nomes dos serviços fornecidos pelo sistema** em arquivos de configuração seguros, localizados em diretórios protegidos pelo SIP: `/System/Library/LaunchDaemons` e `/System/Library/LaunchAgents`. Ao lado de cada nome de serviço, o **binário associado também é armazenado**. O servidor de inicialização criará e manterá um **direito de RECEBIMENTO para cada um desses nomes de serviço**.
Para esses serviços predefinidos, o **processo de busca difere um pouco**. Quando um nome de serviço está sendo procurado, o launchd inicia o serviço dinamicamente. O novo fluxo de trabalho é o seguinte:
* O **launchd** verifica se a tarefa está em execução e, se não estiver, a **inicia**.
* 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.
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**.
* **Porta do host**: Se um processo tem o privilégio de **enviar** sobre esta porta, ele pode obter **informações** sobre o **sistema** (por exemplo, `host_processor_info`).
* **Porta privilégiada do host**: Um processo com o direito de **enviar** sobre esta porta pode realizar **ações privilegiadas**, como carregar uma extensão do kernel. O **processo precisa ser root** para obter essa permissão.
* Além disso, para chamar a API **`kext_request`**, é necessário ter outras permissões **`com.apple.private.kext*`**, que são concedidas apenas a binários da Apple.
* **Porta do nome da tarefa**: Uma versão não privilegiada da _porta da tarefa_. Ela faz referência à tarefa, mas não permite controlá-la. A única coisa que parece estar disponível através dela é `task_info()`.
* **Porta da tarefa** (também conhecida como porta do kernel)**:** Com permissão de envio sobre esta porta, é possível controlar a tarefa (ler/escrever memória, criar threads...).
* Chame `mach_task_self()` para **obter o nome** desta porta para a tarefa chamadora. Esta porta é **herdada** apenas através do **`exec()`**; uma nova tarefa criada com `fork()` recebe uma nova porta de tarefa (como um caso especial, uma tarefa também recebe uma nova porta de tarefa após `exec()` em um binário suid). A única maneira de criar uma tarefa e obter sua porta é realizar a ["dança de troca de porta"](https://robert.sesek.com/2014/1/changes\_to\_xnu\_mach\_ipc.html) enquanto faz um `fork()`.
* Se o aplicativo tiver a permissão **`com.apple.security.get-task-allow`**, processos do **mesmo usuário podem acessar a porta da tarefa** (comumente adicionado pelo Xcode para depuração). O processo de **notarização** não permitirá isso em lançamentos de produção.
* Aplicativos com a permissão **`com.apple.system-task-ports`** podem obter a **porta da tarefa para qualquer** processo, exceto o kernel. Em versões mais antigas, era chamada **`task_for_pid-allow`**. Isso é concedido apenas a aplicativos da Apple.
* **Root pode acessar portas de tarefas** de aplicativos **não** compilados com um tempo de execução **fortificado** (e não da Apple).
**Compile** o programa anterior e adicione as **entitlements** para poder injetar código com o mesmo usuário (caso contrário, você precisará usar **sudo**).
No macOS, as **threads** podem ser manipuladas através do **Mach** ou usando a API **posix `pthread`**. A thread que geramos na injeção anterior foi gerada usando a API Mach, portanto, **não é compatível com posix**.
Foi possível **injetar um shellcode simples** para executar um comando porque não era necessário trabalhar com APIs compatíveis com posix, apenas com Mach. Injeções **mais complexas** precisariam que a **thread** também fosse **compatível com posix**.
Portanto, para **melhorar a thread**, ela deve chamar **`pthread_create_from_mach_thread`**, que irá **criar um pthread válido**. Em seguida, esse novo pthread pode **chamar dlopen** para **carregar uma dylib** do sistema, então, em vez de escrever um novo shellcode para executar ações diferentes, é possível carregar bibliotecas personalizadas.
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.
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.
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.
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:
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.
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`**.
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:
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:
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.
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.
-`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.
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.
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.
### 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:
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 */
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:
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:
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" %}
<preclass="language-c"><codeclass="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
// 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:
* 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).