记一次某CMS代码审计
字数 1098 2025-08-26 22:11:40
某CMS文件上传漏洞审计与利用教学文档
1. 漏洞概述
本教学文档详细分析了一个小众OA系统的文件上传漏洞,该漏洞源于系统对用户上传文件的后缀名未做有效过滤,且通过修改参数可控制文件存储位置,最终导致攻击者能够上传恶意文件并执行任意代码。
2. 环境准备
2.1 测试环境
- 操作系统:Windows 11
- 开发环境:
- PhpStudy (包含MySQL)
- Redis服务
- IDEA (使用Tomcat 8.0作为服务器)
2.2 初始配置
- 将SQL文件导入到phpStudy的MySQL中
- 启动Redis服务
- 配置好数据库连接环境
3. 漏洞发现过程
3.1 功能点分析
在个人资料处发现图像上传功能,初步测试显示:
- 系统对上传文件的后缀名和内容均未做校验
- 返回上传文件的路径和文件名
- 初始测试无法直接解析上传的文件(文件未实际落地)
3.2 关键上传路径
通过抓包发现上传路径为:/func/upload/uploadImages
4. 代码审计分析
4.1 上传逻辑核心代码
系统根据db参数的值决定文件保存方式:
// 伪代码表示
if (db == GlobalConstant.FILE_UPLOADER_SAVE_FILE) { // 通常为0
// 保存到文件系统
} else if (db == 1) {
// 保存到数据库
}
4.2 文件名生成机制
无论哪种保存方式,文件名生成逻辑相同:
String extend = FileUtils.getExtend(fileName); // 获取文件扩展名
String noextfilename = DateUtils.getDataString(DateUtils.SDF_YYYYMMDDHHMMSS)
+ StringUtil.random(10); // 时间+10位随机数
String myfilename = noextfilename + "." + extend; // 最终文件名
关键问题:未对extend(文件扩展名)进行任何过滤或检查
4.3 文件保存路径控制
当db=0时,文件保存到文件系统:
String realPath = request.getSession().getServletContext().getRealPath("/")
+ "/upload/" + strYYYYMMDD + "/";
String path = "upload/" + strYYYYMMDD + "/";
File file = new File(realPath);
if (!file.exists()) {
file.mkdirs(); // 创建目录
}
文件内容直接复制到新文件:
FileCopyUtils.copy(mf.getBytes(), savefile);
5. 漏洞利用步骤
5.1 利用条件
- 能够访问文件上传功能
- 能够修改
db参数
5.2 利用过程
- 准备一个JSP Webshell文件(如
shell.jsp) - 构造上传请求,关键点:
- 将
db参数值设为0(强制保存到文件系统) - 确保文件扩展名为
.jsp
- 将
- 发送上传请求
5.3 预期结果
- 文件将被保存到Web根目录下的
upload/[日期]/目录中 - 文件名为
[时间戳][10位随机数].jsp - 可通过返回的路径直接访问并执行Webshell
6. 漏洞修复建议
6.1 输入验证
- 对上传文件扩展名进行白名单验证
- 检查文件内容是否与扩展名匹配
6.2 安全存储
- 避免将上传文件存储在Web可访问目录
- 如需Web访问,应配置为不可执行
6.3 参数控制
- 不应允许客户端控制文件存储方式(
db参数) - 如需不同存储方式,应在服务端逻辑中控制
7. 总结
该漏洞展示了典型的未经验证的文件上传风险,结合以下因素导致严重安全问题:
- 未过滤文件扩展名
- 客户端可控的关键参数(
db) - 文件直接保存到Web可访问目录
- 未对文件内容进行验证
通过本教学,安全研究人员可以学习到如何审计文件上传功能,识别类似漏洞模式,并采取适当的防护措施。