hacktricks/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-.net-applications-injection.md
2024-02-11 01:46:25 +00:00

8.3 KiB

Wstrzykiwanie aplikacji .Net w macOS

Dowiedz się, jak hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

To jest streszczenie postu https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/. Sprawdź go, aby uzyskać więcej szczegółów!

Debugowanie .NET Core

Ustanawianie sesji debugowania

Komunikacja między debugerem a debugowanym programem w .NET jest zarządzana przez dbgtransportsession.cpp. Ten komponent ustawia dwa nazwane potoki dla każdego procesu .NET, jak widać w dbgtransportsession.cpp#L127, które są inicjowane za pomocą twowaypipe.cpp#L27. Te potoki mają przyrostki -in i -out.

Przez odwiedzenie folderu $TMPDIR użytkownik może znaleźć dostępne potoki debugowania dla aplikacji .Net.

DbgTransportSession::TransportWorker jest odpowiedzialny za zarządzanie komunikacją z debugerem. Aby rozpocząć nową sesję debugowania, debuger musi wysłać wiadomość za pomocą potoku out, zaczynając od struktury MessageHeader, szczegółowo opisanej w kodzie źródłowym .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];
}

Aby poprosić o nową sesję, ta struktura jest wypełniana w następujący sposób, ustawiając typ wiadomości na MT_SessionRequest i wersję protokołu na bieżącą wersję:

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);

Ten nagłówek jest następnie wysyłany do celu za pomocą wywołania systemowego write, a następnie struktura sessionRequestData zawierająca GUID sesji:

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

Operacja odczytu na rurze out potwierdza powodzenie lub niepowodzenie ustanowienia sesji debugowania:

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

Odczytywanie pamięci

Po ustanowieniu sesji debugowania, pamięć można odczytać za pomocą typu wiadomości MT_ReadMemory. Funkcja readMemory jest szczegółowo opisana i wykonuje niezbędne kroki, aby wysłać żądanie odczytu i odebrać odpowiedź:

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;
}

Pełny dowód koncepcji (POC) jest dostępny tutaj.

Zapisywanie do pamięci

Podobnie, pamięć można zapisać za pomocą funkcji writeMemory. Proces polega na ustawieniu typu wiadomości na MT_WriteMemory, określeniu adresu i długości danych, a następnie wysłaniu danych:

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;
}

Powiązany POC jest dostępny tutaj.

Wykonanie kodu .NET Core

Aby wykonać kod, należy zidentyfikować obszar pamięci z uprawnieniami rwx, co można zrobić za pomocą polecenia vmmap -pages:

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

Zlokalizowanie miejsca do nadpisania wskaźnika funkcji jest konieczne, a w .NET Core można to zrobić, docelowo kierując się do Dynamic Function Table (DFT). Ta tabela, szczegółowo opisana w jithelpers.h, jest używana przez środowisko wykonawcze do funkcji pomocniczych kompilacji JIT.

Dla systemów x64 można użyć metody poszukiwania sygnatury, aby znaleźć odniesienie do symbolu _hlpDynamicFuncTable w libcorclr.dll.

Funkcja debugera MT_GetDCB dostarcza przydatnych informacji, w tym adresu funkcji pomocniczej m_helperRemoteStartAddr, wskazującego na lokalizację libcorclr.dll w pamięci procesu. Ten adres jest następnie używany do rozpoczęcia poszukiwania DFT i nadpisania wskaźnika funkcji adresem kodu shell.

Pełny kod POC do wstrzykiwania w PowerShell jest dostępny tutaj.

Odwołania

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks: