云时空ERP系统任意文件上传漏洞分析
字数 1622 2025-08-23 18:31:17
云时空ERP系统任意文件上传漏洞分析教学文档
一、漏洞概述
本教学文档详细分析云时空ERP系统中存在的任意文件上传漏洞,该漏洞允许攻击者绕过安全限制上传任意文件到服务器,可能导致远程代码执行(RCE)等严重后果。
二、系统架构分析
1. 核心路由配置
系统使用WEB-INF/web.xml配置文件定义Servlet组件和过滤器:
- 基于Spring框架进行Web开发
- 整合Apache Shiro进行安全控制
- 配置了字符编码和跨域资源共享(CORS)处理
2. 安全控制机制
系统主要安全控制通过Shiro实现:
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
关键点:
shiroFilter应用于所有URL(/*)- 使用
DelegatingFilterProxy代理到Spring上下文中定义的bean - 自定义的
CustomShiroFilterFactoryBean处理潜在风险字符
3. Shiro权限配置
在spring-context-shiro.xml中定义了权限规则:
/servlet/fileupload/gpy* = anon
表示/servlet/fileupload/gpy*路径不需要认证即可访问,这是漏洞存在的关键配置。
三、漏洞详细分析
1. 文件上传处理流程
-
请求处理:
- 使用
HttpServletRequest读取请求数据 - 处理
multipart/form-data格式数据 DataInputStream in = new DataInputStream(request.getInputStream())直接从输入流读取数据
- 使用
-
文件名提取:
if (s.indexOf("filename=") == -1) { // 表单字段处理 } else { int pos22 = s.indexOf("filename="); String fileFormName = s.substring(pos2, pos22 - 3); String s3 = s.substring(pos22 + "filename=".length() + 1); // 无文件名和后缀过滤 out.print("fileRealName=" + s5 + ""); }- 直接提取文件名,无任何过滤
- 将原始文件名直接写入响应
-
文件存储:
String saveDirectoryPath = curProjectPath + "/uploads" + uploadFolderName + curDate + "/"; File f = new File(saveDirectoryPath + File.separator + s5); DataOutputStream fileout = new DataOutputStream(new FileOutputStream(f)); fileout.write(b3, 0, b3.length - 1);- 存储路径:
web应用根目录/uploads/pics/服务器日期/ - 直接使用用户提供的文件名保存文件
- 无文件内容检查
- 存储路径:
2. 漏洞关键点
-
认证绕过:
- Shiro配置
/servlet/fileupload/gpy* = anon允许匿名访问
- Shiro配置
-
无文件过滤:
- 未检查文件扩展名(尽管定义了
extensionPermit但未使用) - 未对文件名进行安全处理
- 未验证文件内容类型
- 未检查文件扩展名(尽管定义了
-
路径可预测:
- 存储路径包含服务器日期,但日期通过
out.print("date=" + curDate)暴露 - 攻击者可轻松构造完整访问路径
- 存储路径包含服务器日期,但日期通过
四、漏洞复现步骤
-
构造恶意请求:
- 向
/servlet/fileupload/gpy路径发送POST请求 - 内容类型为
multipart/form-data - 包含恶意文件(如webshell.jsp)
- 向
-
获取存储信息:
- 从响应中获取
date参数(服务器日期) - 从响应中获取
fileRealName(原始文件名)
- 从响应中获取
-
访问上传文件:
- 构造访问路径:
http://target/uploads/pics/[date]/[filename] - 验证文件是否可访问
- 构造访问路径:
五、修复建议
-
权限控制:
- 修改Shiro配置,要求认证后才能上传文件
/servlet/fileupload/gpy* = authc -
文件过滤:
// 定义允许的扩展名 private static final Set<String> ALLOWED_EXTENSIONS = Set.of("jpg", "png", "gif"); // 验证文件扩展名 String extension = FilenameUtils.getExtension(filename).toLowerCase(); if (!ALLOWED_EXTENSIONS.contains(extension)) { throw new IllegalArgumentException("不允许的文件类型"); } -
文件名处理:
- 使用UUID生成随机文件名
- 保留原始扩展名
String safeFilename = UUID.randomUUID() + "." + extension; -
内容验证:
- 验证文件魔数(magic number)
- 对图片文件进行图像解析验证
-
存储隔离:
- 将上传文件存储在web根目录之外
- 通过控制器方法提供文件下载
-
路径隐藏:
- 不返回完整的存储路径信息
- 使用文件ID或令牌机制访问文件
六、深入理解
-
漏洞成因本质:
- 认证与授权分离(Shiro配置问题)
- 信任边界失效(直接使用用户输入作为文件路径)
- 缺乏深度防御(多层验证缺失)
-
攻击面扩展:
- 结合路径遍历可实现更灵活的存储位置控制
- 结合SMB配置可能实现网络渗透
- 可发展为持久化后门
-
安全开发要点:
- 最小权限原则
- 输入验证与输出编码
- 安全默认配置
- 不信任任何用户输入
本教学文档详细分析了云时空ERP系统的文件上传漏洞,从系统架构到漏洞细节,再到修复方案,提供了全面的技术视角。理解此类漏洞有助于开发更安全的文件上传功能。