如果觉得该文章有帮助的,麻烦师傅们可以搜索下微信公众号:良月安全。点个关注,感谢师傅们的支持。
免责声明
本号所发布的所有内容,包括但不限于信息、工具、项目以及文章,均旨在提供学习与研究之用。所有工具安全性自测。如因此产生的一切不良后果与文章作者和本公众号无关。如有涉及公司与个人敏感信息,侵权烦请告知,我们会立即删除并致歉。
漏洞简介
e-mobile可满足企业日常管理中的绝大部分管理需求, 诸如市场销售、项目、采购、研发、客服、财务、人事、行政等;同时e-mobile可帮助企业实现面向不同用户量身定制的移动办公入口,包括企业员工、供应商、代理商、 合作伙伴、投资费以及终端客户等整个供应链条上的关系主体,满足为企业全方位的移动办公需求。泛微e-mobile为企业提供成熟APP应用库,各应用组件之间通过信息调用实现高效协同。移动应用前台统一展现操作,后台多个系统支持,用户无需切换登陆,即可在移动终端实现 跨平台、跨系统的统一操作。攻击者可通过文件读取漏洞获取敏感信息。
漏洞分析
截取了下相关代码分析。
@GetMapping({"/client/cdnfile/**"})
@ResponseBody
public void getCdnFile(HttpServletRequest request, HttpServletResponse response) throws Exception {
String servletPath = StringUtils.defaultIfBlank(request.getServletPath(), ""); // 获取请求路径,没有则为空
if (servletPath.contains("?")) {
servletPath = servletPath.split("?")[0];
} // 判断是否传参,只获取路径部分
if (servletPath.contains("/client/cdnfile/")) {
servletPath = servletPath.substring(servletPath.indexOf("/client/cdnfile/"));
servletPath = servletPath.replace("/client/cdnfile/", "");
} // 截去/client/cdnfile/部分
File file = null;
String fileName = "";
String mimeType = "";
if (servletPath.startsWith("3")) { // 处理3开头的路径,基于32位fileId获取文件
String fileId = servletPath.substring(1, 33);
SysBaseFileEntity baseFile = FileUtils.getFileInfo(fileId);
if (baseFile == null) {
response.sendRedirect("/common/images/ecfiledownloadpd.png");
return;
}
if (StringUtils.isNotBlank(baseFile.getPath())) {
file = new File(baseFile.getPath());
}
if ((file == null || !file.exists()) && (new Integer(1)).equals(baseFile.getBackupStatus()) && StringUtils.isNotBlank(baseFile.getBackupPath())) {
file = new File(baseFile.getBackupPath());
}
fileName = StringUtils.defaultIfBlank(baseFile.getName(), "");
mimeType = baseFile.getContentType();
} else {
if (servletPath.startsWith("1")) { // 处理1开头的路径,替换处理/
if (!servletPath.contains("7upload")) {
servletPath = servletPath.replaceFirst("/", ":\\\\");
}
servletPath = servletPath.replaceAll("/", "\\\\");
}
servletPath = servletPath.substring(1); // 删出第一个字符
if (servletPath.startsWith("7upload")) { // 如果路径以 7upload 开头,则获取上传路径的配置,并拼接完整路径
SysBaseSettingEntity baseSetting = SysCacheUtils.getBaseSetting();
servletPath = servletPath.replaceFirst("7upload", "");
servletPath = baseSetting.getUploadPath() + servletPath;
} else if (servletPath.contains(":") && !servletPath.contains(":\\")) {
servletPath = servletPath.replace(":", ":\\");
}
file = new File(servletPath);
if (file.isDirectory()) { // 如果是目录,则获取该目录下的第一个文件进行处理
File[] fs = file.listFiles();
if (fs.length > 0) {
file = fs[0];
}
}
fileName = StringUtils.defaultIfBlank(file.getName(), "");
Path path = file.toPath();
mimeType = Files.probeContentType(path);
}
if (StringUtils.isBlank(request.getHeader("Range"))) { // 处理文件下载
FileUtils.normalRender(request, response, new FileInputStream(file), file.length(), fileName, mimeType);
} else {
FileUtils.rangeRender(request, response, new FileInputStream(file), file.length(), fileName, mimeType);
}
if (file.getAbsolutePath().startsWith(FileUtils.getTempFileDir())) { // 清理文件
org.apache.commons.io.FileUtils.forceDelete(file.getParentFile());
}
}