macOS .Net Applications Injection

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!

Autres façons de soutenir HackTricks :

Il s'agit d'un résumé de l'article https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/. Consultez-le pour plus de détails !

Débogage .NET Core

Établir une session de débogage

La gestion de la communication entre le débogueur et le débogué en .NET est gérée par dbgtransportsession.cpp. Ce composant met en place deux tubes nommés par processus .NET, comme on peut le voir dans dbgtransportsession.cpp#L127, qui sont initiés via twowaypipe.cpp#L27. Ces tubes sont suffixés par -in et -out.

En visitant le répertoire $TMPDIR de l'utilisateur, on peut trouver des FIFO de débogage disponibles pour le débogage des applications .Net.

DbgTransportSession::TransportWorker est responsable de la gestion de la communication depuis un débogueur. Pour initier une nouvelle session de débogage, un débogueur doit envoyer un message via le tube out commençant par une structure MessageHeader, détaillée dans le code source .NET :

struct MessageHeader {
MessageType   m_eType;        // Message type
DWORD         m_cbDataBlock;  // Size of following data block (can be zero)
DWORD         m_dwId;         // Message ID from sender
DWORD         m_dwReplyId;    // Reply-to Message ID
DWORD         m_dwLastSeenId; // Last seen Message ID by sender
DWORD         m_dwReserved;   // Reserved for future (initialize to zero)
union {
struct {
DWORD         m_dwMajorVersion;   // Requested/accepted protocol version
DWORD         m_dwMinorVersion;
} VersionInfo;
...
} TypeSpecificData;
BYTE          m_sMustBeZero[8];
}

Pour demander une nouvelle session, cette structure est remplie comme suit, en définissant le type de message sur MT_SessionRequest et la version du protocole sur la version actuelle :

static const DWORD kCurrentMajorVersion = 2;
static const DWORD kCurrentMinorVersion = 0;

// Configure the message type and version
sSendHeader.m_eType = MT_SessionRequest;
sSendHeader.TypeSpecificData.VersionInfo.m_dwMajorVersion = kCurrentMajorVersion;
sSendHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion = kCurrentMinorVersion;
sSendHeader.m_cbDataBlock = sizeof(SessionRequestData);

Ce titre est ensuite envoyé à la cible en utilisant l'appel système write, suivi de la structure sessionRequestData contenant un GUID pour la session :

write(wr, &sSendHeader, sizeof(MessageHeader));
memset(&sDataBlock.m_sSessionID, 9, sizeof(SessionRequestData));
write(wr, &sDataBlock, sizeof(SessionRequestData));

Une opération de lecture sur le tuyau out confirme le succès ou l'échec de l'établissement de la session de débogage :

read(rd, &sReceiveHeader, sizeof(MessageHeader));

Lecture de la mémoire

Une fois qu'une session de débogage est établie, la mémoire peut être lue en utilisant le type de message MT_ReadMemory. La fonction readMemory est détaillée, effectuant les étapes nécessaires pour envoyer une demande de lecture et récupérer la réponse :

bool readMemory(void *addr, int len, unsigned char **output) {
// Allocation and initialization
...
// Write header and read response
...
// Read the memory from the debuggee
...
return true;
}

Le concept de preuve complet (POC) est disponible ici.

Écriture en mémoire

De même, la mémoire peut être écrite en utilisant la fonction writeMemory. Le processus implique de définir le type de message sur MT_WriteMemory, de spécifier l'adresse et la longueur des données, puis d'envoyer les données :

bool writeMemory(void *addr, int len, unsigned char *input) {
// Increment IDs, set message type, and specify memory location
...
// Write header and data, then read the response
...
// Confirm memory write was successful
...
return true;
}

Le POC associé est disponible ici.

Exécution de code .NET Core

Pour exécuter du code, il est nécessaire d'identifier une région mémoire avec des permissions rwx, ce qui peut être fait en utilisant vmmap -pages:

vmmap -pages [pid]
vmmap -pages 35829 | grep "rwx/rwx"

Trouver un endroit pour écraser un pointeur de fonction est nécessaire, et dans .NET Core, cela peut être fait en ciblant la Table de Fonctions Dynamiques (DFT). Cette table, détaillée dans jithelpers.h, est utilisée par le runtime pour les fonctions d'aide à la compilation JIT.

Pour les systèmes x64, la chasse aux signatures peut être utilisée pour trouver une référence au symbole _hlpDynamicFuncTable dans libcorclr.dll.

La fonction de débogage MT_GetDCB fournit des informations utiles, y compris l'adresse d'une fonction d'aide, m_helperRemoteStartAddr, indiquant l'emplacement de libcorclr.dll dans la mémoire du processus. Cette adresse est ensuite utilisée pour démarrer une recherche de la DFT et écraser un pointeur de fonction avec l'adresse du shellcode.

Le code POC complet pour l'injection dans PowerShell est accessible ici.

Références

Apprenez le piratage AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)!

Autres façons de soutenir HackTricks:

Dernière mise à jour