macOS .Net Applications Injection

Support HackTricks

これは投稿の要約です https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/。詳細はそちらをご覧ください!

.NET Core デバッグ

デバッグセッションの確立

.NETにおけるデバッガとデバッグ対象間の通信の処理は、dbgtransportsession.cppによって管理されています。このコンポーネントは、dbgtransportsession.cpp#L127に見られるように、各.NETプロセスごとに2つの名前付きパイプを設定します。これらはtwowaypipe.cpp#L27を介して開始されます。これらのパイプは**-in-out**でサフィックスされています。

ユーザーの**$TMPDIR**を訪れることで、.Netアプリケーションのデバッグ用のFIFOが見つかります。

DbgTransportSession::TransportWorkerは、デバッガからの通信を管理する責任があります。新しいデバッグセッションを開始するには、デバッガはoutパイプを介してMessageHeader構造体で始まるメッセージを送信する必要があります。この構造体の詳細は.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];
}

新しいセッションをリクエストするために、この構造体は次のように設定され、メッセージタイプを MT_SessionRequest に、プロトコルバージョンを現在のバージョンに設定します:

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

このヘッダーは、その後、write システムコールを使用してターゲットに送信され、セッションの GUID を含む sessionRequestData 構造体が続きます:

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

out パイプでの読み取り操作は、デバッグセッションの確立の成功または失敗を確認します:

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

メモリの読み取り

デバッグセッションが確立されると、MT_ReadMemory メッセージタイプを使用してメモリを読み取ることができます。関数 readMemory は詳細に説明されており、読み取り要求を送信し、応答を取得するために必要な手順を実行します:

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

完全な概念実証(POC)はこちらで入手できます。

メモリの書き込み

同様に、writeMemory関数を使用してメモリに書き込むことができます。このプロセスは、メッセージタイプをMT_WriteMemoryに設定し、データのアドレスと長さを指定し、データを送信することを含みます:

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

関連するPOCはこちらで入手できます。

.NET Core コード実行

コードを実行するには、rwx権限を持つメモリ領域を特定する必要があります。これはvmmap -pagesを使用して行うことができます。

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

関数ポインタを上書きする場所を特定することは必要であり、.NET Coreでは、**Dynamic Function Table (DFT)**をターゲットにすることでこれを行うことができます。このテーブルは、jithelpers.hで詳述されており、JITコンパイルヘルパー関数のためにランタイムによって使用されます。

x64システムでは、シグネチャハンティングを使用してlibcorclr.dll内のシンボル_hlpDynamicFuncTableへの参照を見つけることができます。

MT_GetDCBデバッガ関数は、ヘルパー関数のアドレスm_helperRemoteStartAddrを含む有用な情報を提供し、プロセスメモリ内のlibcorclr.dllの位置を示します。このアドレスは、その後DFTの検索を開始し、関数ポインタをシェルコードのアドレスで上書きするために使用されます。

PowerShellへのインジェクションのための完全なPOCコードはこちらでアクセス可能です。

References

Support HackTricks

Last updated