Injection d'applications .Net sur macOS
Reading time: 5 minutes
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- VĂ©rifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépÎts github.
Ceci est un résumé du post 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é dans .NET est gérée par dbgtransportsession.cpp. Ce composant met en place deux pipes nommés par processus .NET comme vu dans dbgtransportsession.cpp#L127, qui sont initiés via twowaypipe.cpp#L27. Ces pipes sont suffixés par -in
et -out
.
En visitant le $TMPDIR
de l'utilisateur, on peut trouver des FIFOs de débogage disponibles pour le débogage des applications .Net.
DbgTransportSession::TransportWorker est responsable de la gestion de la communication d'un débogueur. Pour initier une nouvelle session de débogage, un débogueur doit envoyer un message via le pipe 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);
Cet en-tĂȘte 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;
}
La preuve de concept complĂšte (POC) est disponible ici.
Ăcriture en mĂ©moire
De mĂȘme, la mĂ©moire peut ĂȘtre Ă©crite en utilisant la fonction writeMemory
. Le processus consiste à définir le type de message sur MT_WriteMemory
, à spécifier l'adresse et la longueur des données, puis à 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 faut 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"
Localiser un endroit pour Ă©craser un pointeur de fonction est nĂ©cessaire, et dans .NET Core, cela peut ĂȘtre fait en ciblant la Dynamic Function Table (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 recherche de signature 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 commencer une recherche pour 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
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- VĂ©rifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépÎts github.