# macOS MIG - Generador de Interfaz Mach
Aprende a hackear AWS desde cero hasta convertirte en un experto con htARTE (Experto en Equipos Rojos de AWS de HackTricks)! Otras formas de apoyar a HackTricks: * Si deseas ver tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF**, consulta los [**PLANES DE SUSCRIPCI脫N**](https://github.com/sponsors/carlospolop)! * Obt茅n la [**merchandising oficial de PEASS & HackTricks**](https://peass.creator-spring.com) * Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colecci贸n exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) * **脷nete al** 馃挰 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **s铆guenos** en **Twitter** 馃惁 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Comparte tus trucos de hacking enviando PRs a los repositorios de** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
MIG fue creado para **simplificar el proceso de creaci贸n de c贸digo de IPC de Mach**. B谩sicamente **genera el c贸digo necesario** para que el servidor y el cliente se comuniquen con una definici贸n dada. Incluso si el c贸digo generado es feo, un desarrollador solo necesitar谩 importarlo y su c贸digo ser谩 mucho m谩s simple que antes. ### Ejemplo Crea un archivo de definici贸n, en este caso con una funci贸n muy simple: {% 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 #include simpleroutine Subtract( server_port : mach_port_t; n1 : uint32_t; n2 : uint32_t); ``` {% endcode %} Ahora utiliza mig para generar el c贸digo del servidor y del cliente que ser谩n capaces de comunicarse entre s铆 para llamar a la funci贸n Subtract: ```bash mig -header myipcUser.h -sheader myipcServer.h myipc.defs ``` Se crear谩n varios archivos nuevos en el directorio actual. En los archivos **`myipcServer.c`** y **`myipcServer.h`** se puede encontrar la declaraci贸n y definici贸n de la estructura **`SERVERPREFmyipc_subsystem`**, que b谩sicamente define la funci贸n a llamar en funci贸n del ID del mensaje recibido (indicamos un n煤mero de inicio 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)}, } }; ``` {% endtab %} {% tab title="myipcServer.h" %} ### macOS MIG (Mach Interface Generator) El Generador de Interfaz Mach (Mach Interface Generator, MIG) es una herramienta utilizada en macOS para generar c贸digo fuente en C a partir de definiciones de interfaz. Permite la comunicaci贸n entre procesos a trav茅s de llamadas a procedimientos remotos. #### Creaci贸n de una definici贸n de interfaz MIG Para crear una definici贸n de interfaz MIG, se debe definir un archivo `.defs` que contenga las declaraciones de los procedimientos remotos que se desean exponer. Luego, se utiliza la herramienta `mig` para generar el c贸digo fuente en C correspondiente. #### Implementaci贸n de un servidor MIG Una vez que se ha generado el c贸digo fuente en C a partir de la definici贸n de interfaz MIG, se puede implementar un servidor MIG que maneje las llamadas a procedimientos remotos definidos en la interfaz. ```c #include #include #include "myipcServer.h" kern_return_t my_remote_procedure_implementation(mach_port_t server, int data, int *result) { // Implementaci贸n del procedimiento remoto *result = data * 2; return KERN_SUCCESS; } int main() { mach_port_t server = mig_create_server(); mig_server(server); return 0; } ``` En el ejemplo anterior, se muestra la implementaci贸n de un servidor MIG simple que maneja una llamada a un procedimiento remoto para multiplicar un n煤mero por 2. La comunicaci贸n entre procesos a trav茅s de MIG es fundamental en macOS y puede ser utilizada de manera maliciosa para abusar de los privilegios del sistema. Es importante asegurar que las implementaciones de servidores MIG est茅n correctamente protegidas para prevenir posibles vulnerabilidades de seguridad. {% 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 %} Basado en la estructura anterior, la funci贸n **`myipc_server_routine`** obtendr谩 el **ID del mensaje** y devolver谩 la funci贸n adecuada para llamar: ```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; } ``` En este ejemplo solo hemos definido 1 funci贸n en las definiciones, pero si hubi茅ramos definido m谩s funciones, estar铆an dentro del array de **`SERVERPREFmyipc_subsystem`** y la primera se habr铆a asignado al ID **500**, la segunda al ID **501**... De hecho, es posible identificar esta relaci贸n en la estructura **`subsystem_to_name_map_myipc`** de **`myipcServer.h`**: ```c #ifndef subsystem_to_name_map_myipc #define subsystem_to_name_map_myipc \ { "Subtract", 500 } #endif ``` Finalmente, otra funci贸n importante para que el servidor funcione ser谩 **`myipc_server`**, que es la que realmente **llamar谩 a la funci贸n** relacionada con el ID recibido: ```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 routine; OutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0); OutHeadP->msgh_remote_port = InHeadP->msgh_reply_port; /* Tama帽o m铆nimo: 隆routine() lo actualizar谩 si es 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) || ((routine = SERVERPREFmyipc_subsystem.routine[InHeadP->msgh_id - 500].stub_routine) == 0)) { ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record; ((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID; return FALSE; } (*routine) (InHeadP, OutHeadP); return TRUE; } ``` Verifique las l铆neas previamente resaltadas accediendo a la funci贸n a llamar por ID. En el siguiente c贸digo se muestra c贸mo crear un **servidor** y un **cliente** simples donde el cliente puede llamar a las funciones Restar del servidor: {% tabs %} {% tab title="myipc_server.c" %} ```c // gcc myipc_server.c myipcServer.c -o myipc_server #include #include #include #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); } ``` {% endtab %} {% tab title="myipc_client.c" %} ### macOS MIG (Mach Interface Generator) El Generador de Interfaz Mach (MIG) es una herramienta utilizada en macOS para generar c贸digo fuente en C que facilita la comunicaci贸n entre procesos a trav茅s de llamadas a procedimientos remotos. Permite a los procesos enviar mensajes y datos entre s铆 de manera eficiente y segura. En el contexto de la seguridad, los atacantes pueden abusar de las interfaces generadas por MIG para realizar ataques de escalada de privilegios o para comprometer la integridad del sistema. Es fundamental implementar medidas de seguridad adecuadas al utilizar MIG para prevenir posibles vulnerabilidades y proteger la comunicaci贸n entre procesos en macOS. Para m谩s informaci贸n sobre c贸mo protegerse de posibles abusos de procesos en macOS, consulta la secci贸n correspondiente en este libro. ```c #include #include #include #include "myipc.h" int main() { mach_port_t server_port; kern_return_t kr; kr = bootstrap_look_up(bootstrap_port, "com.example.myipc", &server_port); if (kr != KERN_SUCCESS) { printf("Failed to look up server port\n"); return 1; } myipc_function(server_port); return 0; } ``` {% endtab %} ```c // gcc myipc_client.c myipcUser.c -o myipc_client #include #include #include #include #include #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谩lisis Binario Dado que muchos binarios ahora utilizan MIG para exponer puertos mach, es interesante saber c贸mo **identificar que se utiliz贸 MIG** y las **funciones que MIG ejecuta** con cada ID de mensaje. [**jtool2**](../../macos-apps-inspecting-debugging-and-fuzzing/#jtool2) puede analizar la informaci贸n de MIG de un binario Mach-O indicando el ID del mensaje e identificando la funci贸n a ejecutar: ```bash jtool2 -d __DATA.__const myipc_server | grep MIG ``` Se mencion贸 anteriormente que la funci贸n que se encargar谩 de **llamar a la funci贸n correcta dependiendo del ID del mensaje recibido** era `myipc_server`. Sin embargo, generalmente no se tendr谩n los s铆mbolos del binario (nombres de funciones), por lo que es interesante **ver c贸mo se ve decompilado** ya que siempre ser谩 muy similar (el c贸digo de esta funci贸n es independiente de las funciones expuestas): {% tabs %} {% tab title="myipc_server decompiled 1" %}
int _myipc_server(int arg0, int arg1) {
var_10 = arg0;
var_18 = arg1;
// Instrucciones iniciales para encontrar los punteros de funci贸n adecuados
*(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);
// Llamada a sign_extend_64 que puede ayudar a identificar esta funci贸n
// Esto almacena en rax el puntero a la llamada que debe realizarse
// Ver el uso de la direcci贸n 0x100004040 (array de direcciones de funciones)
// 0x1f4 = 500 (el ID de inicio)
            rax = *(sign_extend_64(rax - 0x1f4) * 0x28 + 0x100004040);
            var_20 = rax;
// If - else, el if devuelve falso, mientras que el else llama a la funci贸n correcta y devuelve verdadero
            if (rax == 0x0) {
                    *(var_18 + 0x18) = **_NDR_record;
*(int32_t *)(var_18 + 0x20) = 0xfffffffffffffed1;
var_4 = 0x0;
}
else {
// Direcci贸n calculada que llama a la funci贸n adecuada con 2 argumentos
                    (var_20)(var_10, var_18);
                    var_4 = 0x1;
}
}
else {
*(var_18 + 0x18) = **_NDR_record;
*(int32_t *)(var_18 + 0x20) = 0xfffffffffffffed1;
var_4 = 0x0;
}
rax = var_4;
return rax;
}
{% endtab %} {% tab title="myipc_server decompiled 2" %} Esta es la misma funci贸n decompilada en una versi贸n gratuita diferente de Hopper:
int _myipc_server(int arg0, int arg1) {
r31 = r31 - 0x40;
saved_fp = r29;
stack[-8] = r30;
var_10 = arg0;
var_18 = arg1;
// Instrucciones iniciales para encontrar los punteros de funci贸n adecuados
*(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 (el ID de inicio)
                    r8 = r8 - 0x1f4;
                    asm { smaddl     x8, w8, w9, x10 };
r8 = *(r8 + 0x8);
var_20 = r8;
r8 = r8 - 0x0;
if (r8 != 0x0) {
if (CPU_FLAGS & NE) {
r8 = 0x1;
}
}
// Mismo if else que en la versi贸n anterior
// Ver el uso de la direcci贸n 0x100004040 (array de direcciones de funciones)
                    if ((r8 & 0x1) == 0x0) {
                            *(var_18 + 0x18) = **0x100004000;
                            *(int32_t *)(var_18 + 0x20) = 0xfffffed1;
var_4 = 0x0;
}
else {
// Llamada a la direcci贸n calculada donde deber铆a estar la funci贸n
                            (var_20)(var_10, var_18);
                            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;
}

{% endtab %} {% endtabs %} De hecho, si vas a la funci贸n **`0x100004000`** encontrar谩s el array de estructuras **`routine_descriptor`**. El primer elemento de la estructura es la **direcci贸n** donde est谩 implementada la **funci贸n**, y la **estructura ocupa 0x28 bytes**, por lo que cada 0x28 bytes (comenzando desde el byte 0) puedes obtener 8 bytes y esa ser谩 la **direcci贸n de la funci贸n** que se llamar谩:
Estos datos se pueden extraer [**usando este script de Hopper**](https://github.com/knightsc/hopper/blob/master/scripts/MIG%20Detect.py). * **脷nete al** 馃挰 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de Telegram**](https://t.me/peass) o **s铆guenos** en **Twitter** 馃惁 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Comparte tus trucos de hacking enviando PRs a los repositorios de** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) en GitHub.