Sleep反沙箱已死?MySleep万岁!

文摘   2024-06-16 17:59   中国香港  

如题,sleep作为一个最经典的延迟执行反沙箱技术,但是现在的大多数沙箱一检测到 sleep 函数,会直接跳过,加速或不去执行 sleep,用来对抗我们的反沙箱技术

POC概念如下:

#include <Windows.h>#include "MinHook.h"#include <stdio.h>#pragma comment(lib, "MinHook.x86.lib")//定义函数指针typedef void (NTAPI* pNtDelayExecution)(IN BOOLEAN   Alertable,  IN PLARGE_INTEGER   DelayInterval  );
//旧的pNtDelayExecution pOldNtDelayExecution = (pNtDelayExecution)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtDelayExecution");
//新的
void NTAPI myNtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval ){
  MessageBoxA(0,"检测到川哥想使用Sleep绕过沙箱","愚蠢的行为",0); pOldNtDelayExecution(Alertable, 0); //使延迟为0,基本上睡眠无效}
void setHook() { if (MH_Initialize() == MB_OK) { MH_CreateHookApi(L"ntdll.dll", "NtDelayExecution", myNtDelayExecution, reinterpret_cast<void**>(&pOldNtDelayExecution)); MH_EnableHook(MH_ALL_HOOKS); }}
void UnHook(){ if (MH_DisableHook(MH_ALL_HOOKS) == MB_OK) { MH_Uninitialize(); }}void main() { //setHook(); Sleep(3000); printf("hello laoxinsec.com");}


有鉴于此。我们可以通过自封装一个"sleep"的手段进行bypass:


基本原理:

KUSER_SHARED_DATA 结构是一个系统内核和用户模式(当然是只读模式)共享的结构,其中包含 Windows 操作系统存储在内存地址中的各种系统参数,该地址自 Windows NT 以来在 Windows 版本中保持不变,位于内存地址(0x7ffe0000),我们可以从用户空间访问该地址。值得注意的是,可以在此结构中的 +0x14 偏移处检查系统时间。

在上面的屏幕截图中看到的那样,SystemTime 成员属于_KSYSTEM_TIME类型。我们可以dt此类型来了解我们需要做什么。

虽然可以读取_KSYSTEM_TIME结构的所有三个组件以实现系统时间的完整读取,但要开发MySleep,我们实际上只需要读取 LowPart 和 High1Time。

制作计时器

利用迄今为止获得的知识来制作一个概念验证

#include <Windows.h>#include <stdio.h>#define KSHARE_DATA_ADDRESS 0x7FFE0000
unsigned long long __get_timestamp(){ const size_t TICKS_PER_SECOND = 10000000; // A tick is 100ns. LARGE_INTEGER time;
time.LowPart = *(DWORD*)(KSHARE_DATA_ADDRESS + 0x14); // Read LowPart as unsigned long. time.HighPart = *(long*)(KSHARE_DATA_ADDRESS + 0x1c); // Read High1Part as long. return (unsigned long long)((time.QuadPart) / TICKS_PER_SECOND);}
void main() { printf("获取时间戳:%u\n", __get_timestamp());}

执行代码,可以从KUser_Shared_Data结构中读取并观察到一个递增值,该值反映了每秒的时间变化

Ok,现在我们可以增加一些计时器逻辑让我们的程序进入睡眠状态,而无需调用任何 WinAPI 或 Native API!!!

#include <Windows.h>#include <stdio.h>#define KSHARE_DATA_ADDRESS 0x7FFE0000
unsigned long long __get_timestamp(){ const size_t TICKS_PER_SECOND = 10000000; // A tick is 100ns. LARGE_INTEGER time;
time.LowPart = *(DWORD*)(KSHARE_DATA_ADDRESS + 0x14); // Read LowPart as unsigned long. time.HighPart = *(long*)(KSHARE_DATA_ADDRESS + 0x1c); // Read High1Part as long. return (unsigned long long)((time.QuadPart) / TICKS_PER_SECOND);}
void main() {
unsigned long long startTime = __get_timestamp(); unsigned long long sleeptime = 10; //休眠10秒 while (sleeptime > (__get_timestamp() - startTime)) {
} //do something......such as payload()?}

此外,KUser_Shared_Data结构包含一些更有趣的东西,可以用它们来获取系统信息,而无需与 Windows API 交互,将在https://www.laoxinsec.com/站点发布继续探讨。

参考链接:https://www.legacyy.xyz/defenseevasion/windows/2022/07/04/abusing-shareduserdata-for-defense-evasion-and-exploitation.html

https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm

https://www.vergiliusproject.com/kernels/x86/windows-10/22h2/_KUSER_SHARED_DATA

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/measure-command?view=powershell-7.4

老鑫安全
真正的大师永远都怀着一颗学徒的心,专注于渗透测试,红蓝对抗,漏洞挖掘等安全技术培训 B站:老鑫安全 知识星球:老鑫安全 官网论坛:https://www.laoxinsec.com