macOS .Net Applications Injection
Questo è un riassunto del post https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/. Consultalo per ulteriori dettagli!
Debugging di .NET Core
Avvio di una sessione di debug
La gestione della comunicazione tra il debugger e il debuggee in .NET è gestita da dbgtransportsession.cpp. Questo componente configura due named pipe per ogni processo .NET, come si può vedere in dbgtransportsession.cpp#L127, che vengono iniziate tramite twowaypipe.cpp#L27. Queste pipe sono suffisse con -in
e -out
.
Visitando la directory $TMPDIR
dell'utente, è possibile trovare FIFO di debug disponibili per le applicazioni .Net.
DbgTransportSession::TransportWorker è responsabile della gestione della comunicazione da parte di un debugger. Per avviare una nuova sessione di debug, un debugger deve inviare un messaggio tramite la pipe out
che inizia con una struttura MessageHeader
, dettagliata nel codice sorgente di .NET:
Per richiedere una nuova sessione, questa struttura viene popolata nel seguente modo, impostando il tipo di messaggio su MT_SessionRequest
e la versione del protocollo alla versione corrente:
Quest'intestazione viene quindi inviata al target utilizzando la chiamata di sistema write
, seguita dalla struttura sessionRequestData
che contiene un GUID per la sessione:
Un'operazione di lettura sul tubo out
conferma il successo o il fallimento dell'instaurazione della sessione di debug:
Lettura della memoria
Una volta stabilita una sessione di debug, la memoria può essere letta utilizzando il tipo di messaggio MT_ReadMemory
. La funzione readMemory è dettagliata, eseguendo i passaggi necessari per inviare una richiesta di lettura e recuperare la risposta:
La prova di concetto (POC) completa è disponibile qui.
Scrittura in memoria
Allo stesso modo, la memoria può essere scritta utilizzando la funzione writeMemory
. Il processo prevede di impostare il tipo di messaggio su MT_WriteMemory
, specificare l'indirizzo e la lunghezza dei dati, e quindi inviare i dati:
Il POC associato è disponibile qui.
Esecuzione del codice .NET Core
Per eseguire il codice, è necessario identificare una regione di memoria con le autorizzazioni rwx, che può essere fatto utilizzando vmmap -pages:
È necessario individuare un punto in cui sovrascrivere un puntatore a una funzione e, in .NET Core, ciò può essere fatto mirando alla Dynamic Function Table (DFT). Questa tabella, descritta in jithelpers.h
, viene utilizzata dal runtime per le funzioni helper di compilazione JIT.
Per i sistemi x64, è possibile utilizzare la ricerca della firma per trovare un riferimento al simbolo _hlpDynamicFuncTable
in libcorclr.dll
.
La funzione di debug MT_GetDCB
fornisce informazioni utili, tra cui l'indirizzo di una funzione helper, m_helperRemoteStartAddr
, che indica la posizione di libcorclr.dll
nella memoria del processo. Questo indirizzo viene quindi utilizzato per avviare una ricerca della DFT e sovrascrivere un puntatore a una funzione con l'indirizzo del codice shell.
Il codice POC completo per l'iniezione in PowerShell è accessibile qui.
Riferimenti
Last updated