JAVA代审-publiccms_V4_2024_6

admin 2025年2月19日11:53:00评论18 views字数 6785阅读22分37秒阅读模式
前言

JAVA代审-publiccms_V4_2024_6

本篇文章首发在先知社区,作者C@ig0 (本人)  先知社区名称:caigo 转载原文链接为:https://xz.aliyun.com/news/16780

文章目录
JAVA代审-publiccms_V4_2024_6
项目介绍环境搭建漏洞挖掘   任意文件上传   XSS(存储型)   SSRF最后

项目介绍

200多万行代码修改 持续迭代8年 现代化java cms完整开源,轻松支撑千万数据、千万PV;支持静态 化,服务器端包含,多级缓存,全文搜索复杂搜索,后台支持手机操作; 目前已经拥有全球0.0005% (w3techs提供的数据)的用户,语言支持中、繁、日、英;是一个已走向海外的成熟CMS产品

环境搭建

项目地址:

https://gitee.com/sanluan/PublicCMS/archive/refs/tags/V4.0.202406.d.zip

源码下载到本地后,IDEA打开加载

加载好后,配置tomcat,直接启动即可

JAVA代审-publiccms_V4_2024_6

访问 http://localhost:8080/,按照指引创建对应数据库配置

JAVA代审-publiccms_V4_2024_6

出现下面页面即可

JAVA代审-publiccms_V4_2024_6

安装过程中会自定义账号密码,登入后台

JAVA代审-publiccms_V4_2024_6

漏洞挖掘

这个是最新版,很多漏洞都修了,我找了两处,说实话也比较鸡肋

任意文件上传

在网站后台存在文件操作类功能

JAVA代审-publiccms_V4_2024_6

 这里可以上传文件,我们尝试上传查看对应路由

JAVA代审-publiccms_V4_2024_6

 在上传文件前会触发个check方法,定位代码段查看作用

@RequestMapping("check")@Csrf@ResponseBodypublicbooleancheck(@RequestAttribute SysSite site, @RequestParam("fileNames[]"String[] fileNames, String path) {if (null != fileNames) {  //if 判断我们上传的文件名是否为null for (String fileName : fileNames) {   //for 获取我们上传的文件名String filepath = CommonUtils.joinString(path, Constants.SEPARATOR, fileName); //使用joinString 拼接完整文件路径if (CmsFileUtils.exists(siteComponent.getWebFilePath(site.getId(), filepath))) { //使用exists 判断文件是否存在return true; } } } return false;

 我们接着上传

JAVA代审-publiccms_V4_2024_6

 定位对应代码段

    @RequestMapping("doUpload")    @Csrf    public String upload(@RequestAttribute SysSite site, @SessionAttribute SysUser admin, MultipartFile[] files, String path,            boolean privatefile, boolean overwrite, HttpServletRequest request, ModelMap model) {if (null != files) {  //if判断文件名是否为null            try {for (MultipartFile file : files) {   //for 循环获取我们上传的文件                    String originalName = file.getOriginalFilename(); //获取文件名:shell.jspf                    String suffix = CmsFileUtils.getSuffix(originalName);  //获取文件后缀:jspf                    String filepath = CommonUtils.joinString(path, Constants.SEPARATOR, originalName);                    // 这里拼接我们上传的路径: + / + shell.jspf //path没写所以是空                    String fuleFilePath = siteComponent.getWebFilePath(site.getId(), filepath);                    //getWebFilePath是自定义方法,是使用joinString拼接完整路径,并且限制了../防止了目录穿越if(ArrayUtils.contains(safeConfigComponent.getSafeSuffix(site), suffix)) {                        //对文件后缀进行白名单判断if (overwrite || !CmsFileUtils.exists(fuleFilePath)) {                                  //判断文件是否存在if (CmsFileUtils.exists(fuleFilePath)) {                                             String historyFilePath = siteComponent.getWebHistoryFilePath(site.getId(), filepath, true);                                try {                                    CmsFileUtils.copyFileToFile(historyFilePath, historyFilePath);                                } catch (IOException e1) {                                }                            }大概意思就是这样,那么这处限制了目录穿越,限制了文件后缀并且是白名单检查,字典如下(断点调试可以得到)[".mp3"".wav"".mid"".flv"".swf", 其他 +38]允许上传常规文件,有html,zip等等这里发现可以上传zip,并且有解压zip的功能,尝试上传zip,解压抓包查看对应路由                            CmsFileUtils.upload(file, fuleFilePath);                            //使用upload方法上传文件if (CmsFileUtils.isSafe(fuleFilePath, suffix)) {                                //.isSafe方法来检查文件,检查后缀,针对SVG & PDF                                FileUploadResult uploadResult = CmsFileUtils.getFileSize(fuleFilePath, originalName, suffix);                                //记录文件上传日志                                logUploadService.save(new LogUpload(site.getId(), admin.getId(),                                        LogLoginService.CHANNEL_WEB_MANAGER, originalName, privatefile, CmsFileUtils.getFileType(CmsFileUtils.getSuffix(originalName)), file.getSize(),                                        uploadResult.getWidth(), uploadResult.getHeight(), RequestUtils.getIpAddress(request),                                        CommonUtils.getDate(), filepath));                            } else {                                //处理不安全的文件                                CmsFileUtils.delete(fuleFilePath);                                model.addAttribute(CommonConstants.ERROR, "verify.custom.file.unsafe");return CommonConstants.TEMPLATE_ERROR;                            }                        }                    } else {                        model.addAttribute(CommonConstants.ERROR, "verify.custom.fileType");return CommonConstants.TEMPLATE_ERROR;                    }                }            } catch (IOException e) {                model.addAttribute(CommonConstants.ERROR, e.getMessage());                log.error(e.getMessage(), e);return CommonConstants.TEMPLATE_ERROR;            }        }return CommonConstants.TEMPLATE_DONE;    }

 大概意思就是这样,那么这处限制了目录穿越,限制了文件后缀并且是白名单检查,字典如下(断点调 试可以得到)

[".mp3", ".wav", ".mid", ".flv", ".swf", 其他 +38]

允许上传常规文件,有html,zip等等

这里发现可以上传zip,并且有解压zip的功能,尝试上传zip,解压抓包查看对应路由

JAVA代审-publiccms_V4_2024_6

 定位对应代码段

publicStringdoUnzip(@RequestAttribute SysSite site, @SessionAttributeSysUser admin, String path, String encoding,boolean here, boolean overwrite, HttpServletRequest request, ModelMap model) {if (CommonUtils.notEmpty(path) && path.toLowerCase().endsWith(".zip")) {//获取并判断文件后缀是否为zip            String filepath = siteComponent.getWebFilePath(site.getId(), path);            //拼接文件完整路径            if (CmsFileUtils.isFile(filepath)) {                //判断文件是否存在                try {                    if (here) {                        ZipUtils.unzipHere(filepath, encoding, overwrite, (f, e) -> {                            String historyFilePath = siteComponent.getTemplateHistoryFilePath(site.getId(), e.getName(), true);                            try { CmsFileUtils.copyInputStreamToFile(f.getInputStream(e), historyFilePath);                            } catch (IOException e1) {                            }                            return true;                        });                    } else {                        ZipUtils.unzip(filepath, encoding, overwrite, (f, e) -> {                            String historyFilePath = siteComponent.getWebHistoryFilePath(site.getId(), e.getName(), true);                            try { CmsFileUtils.copyInputStreamToFile(f.getInputStream(e), historyFilePath);                            } catch (IOException e1) {                            }                            return true;                        });                    }                } catch (IOException e) {                    model.addAttribute(CommonConstants.ERROR, e.getMessage());                    log.error(e.getMessage(), e);} } logOperateService .save(new LogOperate(site.getId(), admin.getId(), admin.getDeptId(), LogLoginService.CHANNEL_WEB_MANAGER, "unzip.web.webfile", RequestUtils.getIpAddress(request), CommonUtils.getDate(), path)); } return CommonConstants.TEMPLATE_DONE; }

 代码比较短,貌似只判断了zip本身,没有对zip中的文件进行判断,可以断点调试下

JAVA代审-publiccms_V4_2024_6

会使用unzip解压文件,接着跟

JAVA代审-publiccms_V4_2024_6

 会限制..,防止了目录穿越,后续没有对zip中的文件后缀进行校验,于是可以上传任意文件,但是很可惜不能目录穿越

只能上传在datapubliccmswebsite_1 目录下

JAVA代审-publiccms_V4_2024_6

XSS(存储型)

这个我只能说鸡肋的很,在网站后台可以修改模板文件

JAVA代审-publiccms_V4_2024_6

在早些版本这一处是有SSTI的,但是最新版修复了,但是可以执行JS代码

JAVA代审-publiccms_V4_2024_6
JAVA代审-publiccms_V4_2024_6

SSRF

全局搜索 .execute( 定位到一处Controller层代码

PublicCMS-V4publiccms-parentpubliccms coresrcmainjavacompubliccmscontrolleradminsysUeditorAdminController.java

@RequestMapping(params = "action=" + ACTION_CATCHIMAGE) //路由?actio=catchimage @ResponseBody public Map<String, Object> catchimage(@RequestAttribute SysSite site, @SessionAttribute SysUser admin, HttpServletRequest request) { try (CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(Constants.defaultRequestConfig) .build()) { String[] files = request.getParameterValues(FIELD_NAME + "[]");获取file[]参数中的值赋值给filesimageif (CommonUtils.notEmpty(files)) { //判断内容是否为空List<Map<String, Object>> list = new ArrayList<>();for (String image : files) { //循环遍历files,赋值和image HttpGet httpget = new HttpGet(image); //创建http请求,地址为CloseableHttpResponse response = httpclient.execute(httpget);  //发送http请求HttpEntity entity = response.getEntity();

我们尝试构造路由,这个功能在后台

文件头部有上级路由 ueditor ,加上功能点路由,完整路由为

请求地址通过file[]传入,post,get都行,get记得[]url编码

JAVA代审-publiccms_V4_2024_6
JAVA代审-publiccms_V4_2024_6
这套系统版本比较新,也给提交过很多漏洞,导致多数漏洞都给修了,漏洞比较少,zip解压那处我之前挖的时候网上没有资料,当时没提有点可惜,师傅们可以在下去挖挖。

 

原文始发于微信公众号(菜狗安全):JAVA代审-publiccms_V4_2024_6

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

发表评论

匿名网友 填写信息