macOS .Net Applications Injection

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Unterstützen Sie HackTricks

Dies ist eine Zusammenfassung des Beitrags https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/. Überprüfen Sie ihn für weitere Details!

.NET Core Debugging

Einrichten einer Debugging-Sitzung

Die Handhabung der Kommunikation zwischen Debugger und Debuggee in .NET wird von dbgtransportsession.cpp verwaltet. Diese Komponente richtet zwei benannte Pipes pro .NET-Prozess ein, wie in dbgtransportsession.cpp#L127 zu sehen ist, die über twowaypipe.cpp#L27 initiiert werden. Diese Pipes sind mit -in und -out suffixiert.

Durch den Besuch des $TMPDIR des Benutzers kann man Debugging-FIFOs finden, die für das Debuggen von .Net-Anwendungen verfügbar sind.

DbgTransportSession::TransportWorker ist verantwortlich für die Verwaltung der Kommunikation von einem Debugger. Um eine neue Debugging-Sitzung zu initiieren, muss ein Debugger eine Nachricht über die out-Pipe senden, die mit einer MessageHeader-Struktur beginnt, die im .NET-Quellcode detailliert beschrieben ist:

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

Um eine neue Sitzung anzufordern, wird diese Struktur wie folgt ausgefüllt, wobei der Nachrichtentyp auf MT_SessionRequest und die Protokollversion auf die aktuelle Version gesetzt wird:

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

Dieser Header wird dann über den write syscall an das Ziel gesendet, gefolgt von der sessionRequestData Struktur, die eine GUID für die Sitzung enthält:

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

Ein Lesevorgang auf dem out-Pipe bestätigt den Erfolg oder Misserfolg der Einrichtung der Debugging-Sitzung:

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

Lesen des Speichers

Sobald eine Debugging-Sitzung eingerichtet ist, kann der Speicher mit dem MT_ReadMemory Nachrichtentyp gelesen werden. Die Funktion readMemory ist detailliert und führt die notwendigen Schritte aus, um eine Leseanforderung zu senden und die Antwort abzurufen:

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

Der vollständige Proof of Concept (POC) ist hier verfügbar.

Schreiben in den Speicher

Ähnlich kann der Speicher mit der Funktion writeMemory beschrieben werden. Der Prozess umfasst das Setzen des Nachrichtentyps auf MT_WriteMemory, das Festlegen der Adresse und der Länge der Daten und das anschließende Senden der Daten:

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

Der zugehörige POC ist hier verfügbar.

.NET Core Codeausführung

Um Code auszuführen, muss man einen Speicherbereich mit rwx-Berechtigungen identifizieren, was mit vmmap -pages: durchgeführt werden kann.

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

Einen Ort zu finden, um einen Funktionszeiger zu überschreiben, ist notwendig, und in .NET Core kann dies durch das Anvisieren der Dynamic Function Table (DFT) erfolgen. Diese Tabelle, die in jithelpers.h detailliert beschrieben ist, wird von der Laufzeit für JIT-Kompilierungs-Hilfsfunktionen verwendet.

Für x64-Systeme kann die Signatur-Suche verwendet werden, um einen Verweis auf das Symbol _hlpDynamicFuncTable in libcorclr.dll zu finden.

Die Debugger-Funktion MT_GetDCB liefert nützliche Informationen, einschließlich der Adresse einer Hilfsfunktion, m_helperRemoteStartAddr, die den Standort von libcorclr.dll im Prozessspeicher angibt. Diese Adresse wird dann verwendet, um eine Suche nach der DFT zu starten und einen Funktionszeiger mit der Adresse des Shellcodes zu überschreiben.

Der vollständige POC-Code für die Injektion in PowerShell ist hier zugänglich.

References

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Last updated