8.3 KiB
Injeção em Aplicações .Net no macOS
Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!
Outras formas de apoiar o HackTricks:
- Se você deseja ver sua empresa anunciada no HackTricks ou baixar o HackTricks em PDF, verifique os PLANOS DE ASSINATURA!
- Adquira o swag oficial PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Junte-se ao 💬 grupo Discord ou ao grupo telegram ou siga-me no Twitter 🐦 @carlospolopm.
- Compartilhe seus truques de hacking enviando PRs para os HackTricks e HackTricks Cloud repositórios do github.
Este é um resumo do post https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/. Confira para mais detalhes!
Depuração do .NET Core
Estabelecendo uma Sessão de Depuração
O gerenciamento da comunicação entre o depurador e o depurado no .NET é feito por dbgtransportsession.cpp. Este componente configura dois named pipes por processo .NET, como visto em dbgtransportsession.cpp#L127, que são iniciados via twowaypipe.cpp#L27. Esses pipes são sufixados com -in
e -out
.
Ao visitar o $TMPDIR
do usuário, é possível encontrar FIFOs de depuração disponíveis para depurar aplicações .Net.
DbgTransportSession::TransportWorker é responsável por gerenciar a comunicação de um depurador. Para iniciar uma nova sessão de depuração, um depurador deve enviar uma mensagem via o pipe out
começando com uma estrutura MessageHeader
, detalhada no código-fonte do .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];
}
Para solicitar uma nova sessão, esta estrutura é preenchida da seguinte forma, definindo o tipo de mensagem como MT_SessionRequest
e a versão do protocolo como a versão atual:
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);
Este cabeçalho é então enviado para o alvo usando a chamada de sistema write
, seguido pela struct sessionRequestData
contendo um GUID para a sessão:
write(wr, &sSendHeader, sizeof(MessageHeader));
memset(&sDataBlock.m_sSessionID, 9, sizeof(SessionRequestData));
write(wr, &sDataBlock, sizeof(SessionRequestData));
Uma operação de leitura no pipe out
confirma o sucesso ou falha do estabelecimento da sessão de depuração:
read(rd, &sReceiveHeader, sizeof(MessageHeader));
Leitura de Memória
Uma vez estabelecida uma sessão de depuração, a memória pode ser lida usando o tipo de mensagem MT_ReadMemory
. A função readMemory é detalhada, realizando as etapas necessárias para enviar uma solicitação de leitura e recuperar a resposta:
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;
}
O conceito de prova completo (POC) está disponível aqui.
Escrevendo na Memória
Da mesma forma, a memória pode ser escrita usando a função writeMemory
. O processo envolve definir o tipo de mensagem como MT_WriteMemory
, especificar o endereço e o comprimento dos dados e, em seguida, enviar os dados:
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;
}
O POC associado está disponível aqui.
Execução de Código .NET Core
Para executar código, é necessário identificar uma região de memória com permissões rwx, o que pode ser feito usando vmmap -pages:
vmmap -pages [pid]
vmmap -pages 35829 | grep "rwx/rwx"
Encontrar um local para sobrescrever um ponteiro de função é necessário, e no .NET Core, isso pode ser feito direcionando a Tabela de Funções Dinâmicas (DFT). Esta tabela, detalhada em jithelpers.h
, é usada pelo tempo de execução para funções auxiliares de compilação JIT.
Para sistemas x64, a caça de assinaturas pode ser usada para encontrar uma referência ao símbolo _hlpDynamicFuncTable
em libcorclr.dll
.
A função de depuração MT_GetDCB
fornece informações úteis, incluindo o endereço de uma função auxiliar, m_helperRemoteStartAddr
, indicando a localização de libcorclr.dll
na memória do processo. Este endereço é então usado para iniciar a busca pela DFT e sobrescrever um ponteiro de função com o endereço do shellcode.
O código POC completo para injeção no PowerShell está acessível aqui.
Referências
Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!
Outras formas de apoiar o HackTricks:
- Se você deseja ver sua empresa anunciada no HackTricks ou baixar o HackTricks em PDF, verifique os PLANOS DE ASSINATURA!
- Adquira o swag oficial PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Junte-se ao 💬 grupo Discord ou ao grupo telegram ou siga-me no Twitter 🐦 @carlospolopm.
- Compartilhe seus truques de hacking enviando PRs para os repositórios do HackTricks e HackTricks Cloud.