mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-27 23:20:49 +00:00
Translated ['macos-hardening/macos-security-and-privilege-escalation/mac
This commit is contained in:
parent
5ef667bf31
commit
e38dab51f8
2 changed files with 89 additions and 99 deletions
|
@ -18,9 +18,9 @@ Outras maneiras de apoiar o HackTricks:
|
|||
|
||||
### Informações Básicas
|
||||
|
||||
O Mach usa **tarefas** como a **unidade mais pequena** para compartilhar recursos, e cada tarefa pode conter **múltiplas threads**. Essas **tarefas e threads são mapeadas em uma relação 1:1 com processos e threads POSIX**.
|
||||
O Mach usa **tarefas** como a **unidade mais pequena** para compartilhar recursos, e cada tarefa pode conter **múltiplas threads**. Essas **tarefas e threads são mapeadas em um para um com processos e threads POSIX**.
|
||||
|
||||
A comunicação entre tarefas ocorre via Comunicação entre Processos Mach (IPC), utilizando canais de comunicação unidirecional. **As mensagens são transferidas entre portas**, que funcionam como **filas de mensagens** gerenciadas pelo kernel.
|
||||
A comunicação entre tarefas ocorre via Comunicação entre Processos Mach (IPC), utilizando canais de comunicação unidirecional. **As mensagens são transferidas entre portas**, que atuam como **filas de mensagens** gerenciadas pelo kernel.
|
||||
|
||||
Uma **porta** é o **elemento básico** do IPC do Mach. Ela pode ser usada para **enviar mensagens e recebê-las**.
|
||||
|
||||
|
@ -39,7 +39,7 @@ Os direitos de porta, que definem quais operações uma tarefa pode realizar, s
|
|||
* 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**.
|
||||
* Note que os **direitos de porta** também podem ser **passados** por mensagens Mac.
|
||||
* **Direito de Envio-único**, que permite enviar uma mensagem para a porta e depois desaparece.
|
||||
* Este direito **não pode** ser **clonado**, mas pode ser **movido**.
|
||||
* Este direito **não** pode ser **clonado**, mas pode ser **movido**.
|
||||
* **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. Os conjuntos de portas podem ser usados para escutar várias portas simultaneamente, muito parecido com `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.
|
||||
|
||||
|
@ -53,19 +53,19 @@ Portas de arquivo permitem encapsular descritores de arquivo em portas Mac (usan
|
|||
|
||||
Como mencionado anteriormente, é possível enviar direitos usando mensagens Mach, no entanto, você **não pode enviar um direito sem já ter um direito** para enviar uma mensagem Mach. Então, como é estabelecida a primeira comunicação?
|
||||
|
||||
Para isso, o **servidor de inicialização** (**launchd** no Mac) está envolvido, como **qualquer pessoa pode obter um DIREITO DE ENVIO para o servidor de inicialização**, é possível pedir a ele um direito para enviar uma mensagem para outro processo:
|
||||
Para isso, o **servidor de inicialização** (**launchd** no mac) está envolvido, como **todos podem obter um DIREITO DE ENVIO para o servidor de inicialização**, é possível pedir a ele um direito para enviar uma mensagem para outro processo:
|
||||
|
||||
1. A Tarefa **A** cria uma **nova porta**, obtendo o **direito de RECEBER** sobre ela.
|
||||
2. A Tarefa **A**, sendo a detentora do direito de RECEBER, **gera um DIREITO DE ENVIO para a porta**.
|
||||
3. A Tarefa **A** estabelece uma **conexão** com o **servidor de inicialização**, e **envia a ele o DIREITO DE ENVIO** para a porta que gerou no início.
|
||||
* Lembre-se de que qualquer pessoa pode obter um DIREITO DE ENVIO para o servidor de inicialização.
|
||||
* Lembre-se de que qualquer um pode obter um DIREITO DE ENVIO para o servidor de inicialização.
|
||||
4. A Tarefa A envia uma mensagem `bootstrap_register` para o servidor de inicialização para **associar a porta fornecida a um nome** como `com.apple.taska`
|
||||
5. A Tarefa **B** interage com o **servidor de inicialização** para executar uma **busca de inicialização para o nome do serviço** (`bootstrap_lookup`). Para que o servidor de inicialização possa responder, a tarefa B enviará um **DIREITO DE ENVIO para uma porta que ela criou anteriormente** dentro da mensagem de busca. Se a busca for bem-sucedida, o **servidor duplica o DIREITO DE ENVIO** recebido da Tarefa A e **transmite para a Tarefa B**.
|
||||
* Lembre-se de que qualquer pessoa pode obter um DIREITO DE ENVIO para o servidor de inicialização.
|
||||
* Lembre-se de que qualquer um pode obter um DIREITO DE ENVIO para o servidor de inicialização.
|
||||
6. Com este DIREITO DE ENVIO, a **Tarefa B** é capaz de **enviar** uma **mensagem** **para a Tarefa A**.
|
||||
7. Para uma comunicação bidirecional, geralmente a tarefa **B** gera uma nova porta com um **direito de RECEBER** e um **direito de ENVIO**, e dá o **direito de ENVIO para a Tarefa A** para que ela possa enviar mensagens para a TAREFA B (comunicação bidirecional).
|
||||
7. Para uma comunicação bidirecional, geralmente a tarefa **B** gera uma nova porta com um **direito de RECEBER** e um **DIREITO DE ENVIO**, e dá o **DIREITO DE ENVIO para a Tarefa A** para que ela possa enviar mensagens para a TAREFA B (comunicação bidirecional).
|
||||
|
||||
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 **fingir ser qualquer tarefa do sistema**, como falsamente **reivindicar um nome de serviço de autorização** e então aprovar cada solicitação.
|
||||
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 **falsificar qualquer tarefa do sistema**, como **reivindicar falsamente um nome de serviço de autorização** e então aprovar cada solicitação.
|
||||
|
||||
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 RECEBER para cada um desses nomes de serviço**.
|
||||
|
||||
|
@ -74,13 +74,13 @@ Para esses serviços predefinidos, o **processo de busca difere ligeiramente**.
|
|||
* A Tarefa **B** inicia uma **busca de inicialização** para um nome de serviço.
|
||||
* **launchd** verifica se a tarefa está em execução e, se não estiver, a **inicia**.
|
||||
* A Tarefa **A** (o serviço) executa um **check-in de inicialização** (`bootstrap_check_in()`). Aqui, o **servidor de inicialização** cria um DIREITO DE ENVIO, o retém e **transfere o DIREITO DE RECEBER para a Tarefa A**.
|
||||
* O launchd duplica o **DIREITO DE ENVIO e envia para a Tarefa B**.
|
||||
* A Tarefa **B** gera uma nova porta com um **direito de RECEBER** e um **direito de ENVIO**, e dá o **direito de ENVIO para a Tarefa A** (o serviço) para que ela possa enviar mensagens para a TAREFA B (comunicação bidirecional).
|
||||
* launchd duplica o **DIREITO DE ENVIO e envia para a Tarefa B**.
|
||||
* A Tarefa **B** gera uma nova porta com um **direito de RECEBER** e um **DIREITO DE ENVIO**, e dá o **DIREITO DE ENVIO para a Tarefa A** (o serviço) para que ela possa enviar mensagens para a TAREFA B (comunicação bidirecional).
|
||||
|
||||
No entanto, esse processo se aplica apenas a tarefas de sistema predefinidas. Tarefas não do sistema ainda operam conforme descrito originalmente, o que poderia potencialmente permitir a falsificação.
|
||||
|
||||
{% hint style="danger" %}
|
||||
Portanto, o launchd nunca deve falhar, ou o sistema inteiro falhará.
|
||||
Portanto, o launchd nunca deve falhar, ou todo o sistema falhará.
|
||||
{% endhint %}
|
||||
### Uma Mensagem Mach
|
||||
|
||||
|
@ -97,7 +97,7 @@ mach_port_name_t msgh_voucher_port;
|
|||
mach_msg_id_t msgh_id;
|
||||
} mach_msg_header_t;
|
||||
```
|
||||
Processos que possuem um _**direito de recebimento**_ podem receber mensagens em uma porta Mach. Por outro lado, os **remetentes** recebem um _**direito de envio**_ ou um _**direito de envio único**_. O direito de envio único é exclusivo para enviar uma única mensagem, após o que se torna inválido.
|
||||
Os processos que possuem um _**direito de recebimento**_ podem receber mensagens em uma porta Mach. Por outro lado, os **remetentes** recebem um _**direito de envio**_ ou um _**direito de envio-único**_. O direito de envio-único é exclusivamente para enviar uma única mensagem, após o que se torna inválido.
|
||||
|
||||
O campo inicial **`msgh_bits`** é um mapa de bits:
|
||||
|
||||
|
@ -122,21 +122,21 @@ Os tipos que podem ser especificados no voucher, portas locais e remotas são (d
|
|||
```
|
||||
Por exemplo, `MACH_MSG_TYPE_MAKE_SEND_ONCE` pode ser usado para **indicar** que um **direito** de **envio-único** deve ser derivado e transferido para esta porta. Também pode ser especificado `MACH_PORT_NULL` para impedir que o destinatário possa responder.
|
||||
|
||||
Para alcançar uma **comunicação bidirecional** fácil, um processo pode especificar uma **porta mach** no **cabeçalho da mensagem mach** chamada de _porta de resposta_ (**`msgh_local_port`**) onde o **receptor** da mensagem pode **enviar uma resposta** a esta mensagem.
|
||||
Para alcançar uma **comunicação bidirecional** fácil, um processo pode especificar uma **porta mach** no cabeçalho da mensagem mach chamada _porta de resposta_ (**`msgh_local_port`**) onde o **receptor** da mensagem pode **enviar uma resposta** a esta mensagem.
|
||||
|
||||
{% hint style="success" %}
|
||||
Note que esse tipo de comunicação bidirecional é usada em mensagens XPC que esperam uma resposta (`xpc_connection_send_message_with_reply` e `xpc_connection_send_message_with_reply_sync`). Mas **geralmente são criadas portas diferentes** como explicado anteriormente para criar a comunicação bidirecional.
|
||||
Note que esse tipo de comunicação bidirecional é usado em mensagens XPC que esperam uma resposta (`xpc_connection_send_message_with_reply` e `xpc_connection_send_message_with_reply_sync`). Mas **geralmente são criadas portas diferentes** como explicado anteriormente para criar a comunicação bidirecional.
|
||||
{% endhint %}
|
||||
|
||||
Os outros campos do cabeçalho da mensagem são:
|
||||
|
||||
- `msgh_size`: o tamanho do pacote inteiro.
|
||||
- `msgh_size`: o tamanho de todo o pacote.
|
||||
- `msgh_remote_port`: a porta para a qual esta mensagem é enviada.
|
||||
- `msgh_voucher_port`: [vouchers mach](https://robert.sesek.com/2023/6/mach\_vouchers.html).
|
||||
- `msgh_id`: o ID desta mensagem, que é interpretado pelo receptor.
|
||||
|
||||
{% hint style="danger" %}
|
||||
Note que **mensagens mach são enviadas por uma `porta mach`**, que é um canal de comunicação de **um único receptor** e **múltiplos remetentes** incorporado no kernel mach. **Múltiplos processos** podem **enviar mensagens** para uma porta mach, mas em qualquer momento apenas **um único processo pode ler** dela.
|
||||
Note que **mensagens mach são enviadas por uma `porta mach`**, que é um canal de comunicação de **um receptor**, **múltiplos remetentes** incorporado no kernel mach. **Múltiplos processos** podem **enviar mensagens** para uma porta mach, mas em qualquer momento apenas **um processo pode ler** dela.
|
||||
{% endhint %}
|
||||
|
||||
As mensagens são então formadas pelo cabeçalho **`mach_msg_header_t`** seguido pelo **corpo** e pelo **trailer** (se houver) e pode conceder permissão para responder a ela. Nestes casos, o kernel só precisa passar a mensagem de uma tarefa para a outra.
|
||||
|
@ -164,12 +164,12 @@ unsigned int pad3 : 24;
|
|||
mach_msg_descriptor_type_t type : 8;
|
||||
} mach_msg_type_descriptor_t;
|
||||
```
|
||||
Em 32 bits, todos os descritores têm 12B e o tipo de descritor está no 11º. Em 64 bits, os tamanhos variam.
|
||||
Em 32 bits, todos os descritores têm 12 bytes e o tipo de descritor está no 11º byte. Em 64 bits, os tamanhos variam.
|
||||
|
||||
{% hint style="danger" %}
|
||||
O kernel copiará os descritores de uma tarefa para a outra, mas primeiro **criará uma cópia na memória do kernel**. Essa técnica, conhecida como "Feng Shui", tem sido abusada em vários exploits para fazer o **kernel copiar dados em sua memória** fazendo um processo enviar descritores para si mesmo. Em seguida, o processo pode receber as mensagens (o kernel as liberará).
|
||||
O kernel copiará os descritores de uma tarefa para a outra, mas primeiro **criará uma cópia na memória do kernel**. Essa técnica, conhecida como "Feng Shui", tem sido abusada em vários exploits para fazer o **kernel copiar dados em sua memória**, fazendo com que um processo envie descritores para si mesmo. Em seguida, o processo pode receber as mensagens (o kernel as liberará).
|
||||
|
||||
Também é possível **enviar direitos de porta para um processo vulnerável**, e os direitos da porta aparecerão no processo (mesmo que ele não os esteja manipulando).
|
||||
Também é possível **enviar direitos de porta para um processo vulnerável**, e os direitos da porta simplesmente aparecerão no processo (mesmo que ele não os esteja manipulando).
|
||||
{% endhint %}
|
||||
|
||||
### APIs de Portas do Mac
|
||||
|
@ -182,12 +182,12 @@ Observe que as portas estão associadas ao namespace da tarefa, então para cria
|
|||
* `mach_port_names`: Obter nomes de porta de um alvo
|
||||
* `mach_port_type`: Obter direitos de uma tarefa sobre um nome
|
||||
* `mach_port_rename`: Renomear uma porta (como dup2 para FDs)
|
||||
* `mach_port_allocate`: Alocar um novo RECEBER, CONJUNTO_DE_PORTAS ou DEAD_NAME
|
||||
* `mach_port_insert_right`: Criar um novo direito em uma porta onde você tem RECEBER
|
||||
* `mach_port_allocate`: Alocar um novo RECEIVE, PORT\_SET ou DEAD\_NAME
|
||||
* `mach_port_insert_right`: Criar um novo direito em uma porta onde você tem RECEIVE
|
||||
* `mach_port_...`
|
||||
* **`mach_msg`** | **`mach_msg_overwrite`**: Funções usadas para **enviar e receber mensagens mach**. A versão de sobrescrita permite especificar um buffer diferente para a recepção da mensagem (a outra versão apenas o reutilizará).
|
||||
|
||||
### Depuração mach\_msg
|
||||
### Depurar mach\_msg
|
||||
|
||||
Como as funções **`mach_msg`** e **`mach_msg_overwrite`** são as usadas para enviar e receber mensagens, definir um ponto de interrupção nelas permitiria inspecionar as mensagens enviadas e recebidas.
|
||||
|
||||
|
@ -220,7 +220,7 @@ quadro #8: 0x000000018e59e6ac libSystem.B.dylib`libSystem_initializer + 236
|
|||
quadro #9: 0x0000000181a1d5c8 dyld`função de invocação para bloco em dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 168
|
||||
</code></pre>
|
||||
|
||||
Para obter os argumentos de **`mach_msg`** verifique os registradores. Estes são os argumentos (de [mach/message.h](https://opensource.apple.com/source/xnu/xnu-7195.81.3/osfmk/mach/message.h.auto.html)):
|
||||
Para obter os argumentos de **`mach_msg`**, verifique os registradores. Estes são os argumentos (de [mach/message.h](https://opensource.apple.com/source/xnu/xnu-7195.81.3/osfmk/mach/message.h.auto.html)):
|
||||
```c
|
||||
__WATCHOS_PROHIBITED __TVOS_PROHIBITED
|
||||
extern mach_msg_return_t mach_msg(
|
||||
|
@ -243,7 +243,7 @@ x4 = 0x0000000000001f03 ;mach_port_name_t (rcv_name)
|
|||
x5 = 0x0000000000000000 ;mach_msg_timeout_t (timeout)
|
||||
x6 = 0x0000000000000000 ;mach_port_name_t (notify)
|
||||
```
|
||||
Verifique o cabeçalho da mensagem verificando o primeiro argumento:
|
||||
Inspeccione o cabeçalho da mensagem verificando o primeiro argumento:
|
||||
```armasm
|
||||
(lldb) x/6w $x0
|
||||
0x124e04ce8: 0x00131513 0x00000388 0x00000807 0x00001f03
|
||||
|
@ -296,7 +296,7 @@ Pode instalar esta ferramenta no iOS fazendo o download em [http://newosxbook.co
|
|||
|
||||
### 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 solicitava o **direito de envio** desse nome e o usava para **enviar uma mensagem**.
|
||||
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**.
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="receiver.c" %}
|
||||
|
@ -426,13 +426,13 @@ printf("Sent a message\n");
|
|||
|
||||
- **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 de privilégio do host**: Um processo com direito de **Enviar** sobre esta porta pode realizar **ações privilegiadas** como carregar uma extensão de kernel. O **processo precisa ser root** para obter essa permissão.
|
||||
- Além disso, para chamar a API **`kext_request`**, é necessário ter outras autorizações **`com.apple.private.kext*`** que são concedidas apenas a binários da Apple.
|
||||
- Além disso, para chamar a API **`kext_request`**, é necessário ter outros direitos **`com.apple.private.kext*`** que são concedidos 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 do chamador. Esta porta é apenas **herdada** através do **`exec()`**; uma nova tarefa criada com `fork()` obtém uma nova porta de tarefa (como um caso especial, uma tarefa também obtém uma nova porta de tarefa após `exec()` em um binário suid). A única maneira de iniciar uma tarefa e obter sua porta é realizar a ["dança de troca de portas"](https://robert.sesek.com/2014/1/changes\_to\_xnu\_mach\_ipc.html) enquanto faz um `fork()`.
|
||||
- Estas são as restrições para acessar a porta (do `macos_task_policy` do binário `AppleMobileFileIntegrity`):
|
||||
- Se o aplicativo tem a **autorizaçã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 autorização **`com.apple.system-task-ports`** podem obter a **porta da tarefa de qualquer** processo, exceto o kernel. Em versões mais antigas, era chamado de **`task_for_pid-allow`**. Isso é concedido apenas a aplicativos da Apple.
|
||||
- Se o aplicativo tem o **direito `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 o direito **`com.apple.system-task-ports`** podem obter a **porta da tarefa de qualquer** processo, exceto o kernel. Em versões mais antigas, era chamado **`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).
|
||||
|
||||
### Injeção de Shellcode em thread via Porta da Tarefa
|
||||
|
@ -473,7 +473,7 @@ return 0;
|
|||
```
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="entitlements.plist" %}Arquivo de propriedades que contém informações sobre as permissões concedidas a um aplicativo macOS. Essas permissões podem incluir acesso a recursos protegidos do sistema, como câmera, microfone, localização, etc. É importante revisar e gerenciar adequadamente as permissões concedidas a um aplicativo para garantir a segurança e privacidade do sistema.{% endtab %}
|
||||
{% tab title="entitlements.plist" %}
|
||||
```xml
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
|
@ -486,7 +486,7 @@ return 0;
|
|||
{% endtab %}
|
||||
{% endtabs %}
|
||||
|
||||
**Compile** o programa anterior e adicione as **permissões** para poder injetar código com o mesmo usuário (caso contrário, será necessário usar **sudo**).
|
||||
**Compile** o programa anterior e adicione os **privilégios** para poder injetar código com o mesmo usuário (caso contrário, será necessário usar **sudo**).
|
||||
|
||||
<details>
|
||||
|
||||
|
@ -908,7 +908,7 @@ return (-3);
|
|||
|
||||
|
||||
// Set the permissions on the allocated code memory
|
||||
```plaintext
|
||||
```c
|
||||
kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
|
@ -980,11 +980,7 @@ fprintf(stderr,"Dylib não encontrado\n");
|
|||
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
### macOS IPC (Comunicação entre Processos)
|
||||
|
||||
A Comunicação entre Processos (IPC) é um mecanismo essencial para que os processos possam trocar dados e informações entre si. No macOS, existem várias formas de IPC, como notificações por push, Apple Events, XPC e IPC baseado em porta. Esses mecanismos podem ser explorados por atacantes em potencial para realizar escalonamento de privilégios e outros tipos de ataques. É fundamental entender como esses mecanismos funcionam e como podem ser protegidos para garantir a segurança do sistema.
|
||||
</details>
|
||||
```bash
|
||||
gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector
|
||||
./inject <pid-of-mysleep> </path/to/lib.dylib>
|
||||
|
@ -1001,7 +997,7 @@ Nesta técnica, uma thread do processo é sequestrada:
|
|||
|
||||
### Informação Básica
|
||||
|
||||
XPC, que significa Comunicação entre Processos XNU (o kernel usado pelo macOS), é um framework para **comunicação entre processos** no macOS e iOS. 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 separação de privilégios** onde cada **componente** é executado com **apenas as permissões necessárias** para realizar seu trabalho, limitando assim o dano potencial de um processo comprometido.
|
||||
XPC, que significa Comunicação entre Processos XNU (o kernel usado pelo macOS), é um framework para **comunicação entre processos** no macOS e iOS. 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 o dano potencial de um processo comprometido.
|
||||
|
||||
Para mais informações sobre como essa **comunicação funciona** e como ela **pode ser vulnerável**, verifique:
|
||||
|
||||
|
@ -1011,7 +1007,9 @@ Para mais informações sobre como essa **comunicação funciona** e como ela **
|
|||
|
||||
## 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 o servidor e o cliente se comunicarem com uma definição fornecida. 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**. Isso ocorre porque muito do trabalho para programar RPC envolve as mesmas ações (empacotar argumentos, enviar a mensagem, desempacotar os dados no servidor...).
|
||||
|
||||
O MIG basicamente **gera o código necessário** para que o servidor e o cliente se comuniquem com uma definição fornecida (em IDL - Linguagem de Definição de Interface -). 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.
|
||||
|
||||
Para mais informações, verifique:
|
||||
|
||||
|
|
|
@ -4,17 +4,36 @@
|
|||
|
||||
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Outras maneiras de apoiar o HackTricks:
|
||||
Outras formas de apoiar o HackTricks:
|
||||
|
||||
- Se você deseja ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
- Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
- 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)
|
||||
- **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
- **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
||||
* Se você quiser ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Adquira o [**oficial PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
||||
* 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)
|
||||
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
||||
|
||||
</details>
|
||||
|
||||
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 fornecida. 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.
|
||||
## Informações Básicas
|
||||
|
||||
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 fornecida. 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.
|
||||
|
||||
A definição é especificada na Linguagem de Definição de Interface (IDL) usando a extensão `.defs`.
|
||||
|
||||
Essas definições têm 5 seções:
|
||||
|
||||
* **Declaração de subsistema**: A palavra-chave subsistema é usada para indicar o **nome** e o **id**. Também é possível marcá-lo como **`KernelServer`** se o servidor deve ser executado no kernel.
|
||||
* **Inclusões e importações**: O MIG usa o pré-processador C, então é capaz de usar importações. Além disso, é possível usar `uimport` e `simport` para código gerado pelo usuário ou servidor.
|
||||
* **Declarações de tipo**: É possível definir tipos de dados, embora geralmente importe `mach_types.defs` e `std_types.defs`. Para tipos personalizados, pode ser usada alguma sintaxe:
|
||||
* \[i`n/out]tran`: Função que precisa ser traduzida de uma mensagem de entrada ou para uma mensagem de saída
|
||||
* `c[user/server]type`: Mapeamento para outro tipo C.
|
||||
* `destructor`: Chama esta função quando o tipo é liberado.
|
||||
* **Operações**: Estas são as definições dos métodos RPC. Existem 5 tipos diferentes:
|
||||
* `routine`: Espera resposta
|
||||
* `simpleroutine`: Não espera resposta
|
||||
* `procedure`: Espera resposta
|
||||
* `simpleprocedure`: Não espera resposta
|
||||
* `function`: Espera resposta
|
||||
|
||||
### Exemplo
|
||||
|
||||
|
@ -37,7 +56,9 @@ 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:
|
||||
Observe que o primeiro **argumento é a porta a ser vinculada** e o MIG irá **lidar automaticamente com a porta de resposta** (a menos que seja chamado `mig_get_reply_port()` no código do cliente). Além disso, o **ID das operações** será **sequencial** começando pelo ID do subsistema indicado (então, se uma operação for descontinuada, ela é excluída e `skip` é usado para ainda usar seu ID).
|
||||
|
||||
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 Subtrair:
|
||||
```bash
|
||||
mig -header myipcUser.h -sheader myipcServer.h myipc.defs
|
||||
```
|
||||
|
@ -64,19 +85,7 @@ myipc_server_routine,
|
|||
```
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="myipcServer.h" %}
|
||||
|
||||
### macOS MIG (Mach Interface Generator)
|
||||
|
||||
O macOS MIG (Mach Interface Generator) é uma ferramenta usada para gerar interfaces de comunicação entre processos em sistemas baseados em Mach. Ele simplifica a comunicação entre processos e fornece uma maneira eficiente de passar mensagens entre processos. O MIG é amplamente utilizado em sistemas macOS para comunicação entre processos e é uma parte essencial da arquitetura de comunicação do kernel do macOS.
|
||||
|
||||
#### Vantagens do macOS MIG:
|
||||
|
||||
- Facilita a comunicação entre processos
|
||||
- Eficiente na passagem de mensagens entre processos
|
||||
- Parte integrante da arquitetura de comunicação do kernel do macOS
|
||||
|
||||
Ao explorar vulnerabilidades de segurança em sistemas macOS, entender o funcionamento do MIG pode ser útil para identificar possíveis vetores de ataque e entender como os processos se comunicam no sistema.
|
||||
{% tab title="myipcServer.h" %}
|
||||
```c
|
||||
/* Description of this subsystem, for use in direct RPC */
|
||||
extern const struct SERVERPREFmyipc_subsystem {
|
||||
|
@ -109,7 +118,7 @@ return SERVERPREFmyipc_subsystem.routine[msgh_id].stub_routine;
|
|||
```
|
||||
Neste exemplo, apenas definimos 1 função nas definições, mas se tivéssemos definido mais funções, elas estariam dentro do array de **`SERVERPREFmyipc_subsystem`** e a primeira teria sido 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`**:
|
||||
Na verdade, é possível identificar essa relação na struct **`subsystem_to_name_map_myipc`** de **`myipcServer.h`**:
|
||||
```c
|
||||
#ifndef subsystem_to_name_map_myipc
|
||||
#define subsystem_to_name_map_myipc \
|
||||
|
@ -141,17 +150,17 @@ OutHeadP->msgh_id = InHeadP->msgh_id + 100;
|
|||
OutHeadP->msgh_reserved = 0;
|
||||
|
||||
if ((InHeadP->msgh_id > 500) || (InHeadP->msgh_id < 500) ||
|
||||
((routine = SERVERPREFmyipc_subsystem.routine[InHeadP->msgh_id - 500].stub_routine) == 0)) {
|
||||
((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
|
||||
<strong> ((routine = SERVERPREFmyipc_subsystem.routine[InHeadP->msgh_id - 500].stub_routine) == 0)) {
|
||||
</strong> ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
|
||||
((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
|
||||
return FALSE;
|
||||
}
|
||||
(*routine) (InHeadP, OutHeadP);
|
||||
return TRUE;
|
||||
<strong> (*routine) (InHeadP, OutHeadP);
|
||||
</strong> return TRUE;
|
||||
}
|
||||
```
|
||||
|
||||
Verifique as linhas anteriormente destacadas acessando a função a ser chamada por ID.
|
||||
Verifique as linhas anteriormente destacadas acessando a função a ser chamada pelo ID.
|
||||
|
||||
A seguir está o código para criar um **servidor** e um **cliente** simples onde o cliente pode chamar as funções Subtrair do servidor:
|
||||
|
||||
|
@ -189,35 +198,7 @@ mach_msg_server(myipc_server, sizeof(union __RequestUnion__SERVERPREFmyipc_subsy
|
|||
```
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="myipc_client.c" %}
|
||||
|
||||
## Cliente myipc
|
||||
|
||||
Este é um exemplo de código de cliente para se comunicar com o servidor myipc.
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <mach/mach.h>
|
||||
#include <servers/bootstrap.h>
|
||||
#include "myipc.h"
|
||||
|
||||
int main() {
|
||||
mach_port_t server_port;
|
||||
kern_return_t ret;
|
||||
|
||||
ret = bootstrap_look_up(bootstrap_port, "com.example.myipc", &server_port);
|
||||
if (ret != KERN_SUCCESS) {
|
||||
printf("Erro ao procurar o serviço myipc: %s\n", mach_error_string(ret));
|
||||
return 1;
|
||||
}
|
||||
|
||||
myipc_hello(server_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
{% endtab %}
|
||||
{% tab title="myipc_client.c" %}
|
||||
```c
|
||||
// gcc myipc_client.c myipcUser.c -o myipc_client
|
||||
|
||||
|
@ -253,7 +234,7 @@ jtool2 -d __DATA.__const myipc_server | grep MIG
|
|||
Foi mencionado anteriormente que a função que irá **chamar a função correta dependendo do ID da mensagem recebida** era `myipc_server`. No entanto, geralmente você não terá os símbolos do binário (nomes de funções), então é interessante **ver como ela se parece decompilada**, pois sempre será muito semelhante (o código desta função é independente das funções expostas):
|
||||
|
||||
{% tabs %}
|
||||
{% tab title="myipc_server decompilada 1" %}
|
||||
{% tab title="myipc_server decompiled 1" %}
|
||||
<pre class="language-c"><code class="lang-c">int _myipc_server(int arg0, int arg1) {
|
||||
var_10 = arg0;
|
||||
var_18 = arg1;
|
||||
|
@ -272,7 +253,7 @@ rax = *(int32_t *)(var_10 + 0x14);
|
|||
// 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 se retornar falso, enquanto o senão chama a função correta e retorna verdadeiro
|
||||
// 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;
|
||||
|
@ -295,7 +276,7 @@ return rax;
|
|||
</code></pre>
|
||||
{% endtab %}
|
||||
|
||||
{% tab title="myipc_server decompilada 2" %}
|
||||
{% tab title="myipc_server decompiled 2" %}
|
||||
Esta é a mesma função decompilada em uma versão gratuita diferente do Hopper:
|
||||
|
||||
<pre class="language-c"><code class="lang-c">int _myipc_server(int arg0, int arg1) {
|
||||
|
@ -371,13 +352,24 @@ return r0;
|
|||
{% 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:
|
||||
Na verdade, se você for para a função **`0x100004000`**, você 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 (35).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
<figure><img src="../../../../.gitbook/assets/image (36).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).
|
||||
* **Compartilhe seus truques de hacking enviando PRs para os repositórios do** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) no GitHub.
|
||||
|
||||
<details>
|
||||
|
||||
<summary><strong>Aprenda hacking na AWS do zero ao avançado com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||||
|
||||
Outras formas de apoiar o HackTricks:
|
||||
|
||||
* Se você quiser ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
||||
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
* Descubra [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou nos siga no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||||
* **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do GitHub.
|
||||
|
||||
</details>
|
||||
|
|
Loading…
Reference in a new issue