LOADING

加载过慢请开启缓存 浏览器默认开启

CicadasCMS代码审计

2025/4/5 Java

‌知了CMS(CicadasCMS)是一款基于SpringBoot、MyBatis、Beetl等框架开发的内容管理系统‌。它支持自定义内容模型、模板标签、全站静态化等功能,适用于需要高效内容管理和网站建设的场景‌。

任意文件读取

如果path路径的文件存在会创建一个TemplateFile对象,并将文件的名称、路径和内容存储到这个对象中。

如果path参数可控就会导致读取文件内容存储到templateFile.Content

    @Override
    public TemplateFile findByPath(String path) {
        File file = new File(path);
        if(!file.exists()) throw new SystemException("模板不存在请检查!");
        TemplateFile templateFile = new TemplateFile();
        templateFile.setFileName(file.getName());
        templateFile.setFilePath(file.getAbsolutePath());
        templateFile.setContent(this.readTemplateFileContent(file));
        return templateFile;
    }

input路由调用findByPath传递了templateFile.getFilePath(),并且参数可控。

这里只要传递的templateFile.getFilePath()文件存在就会调用findByPath并且将找到的TemplateFile对象添加到模型中,键为 “templateFile”,可以在后续的视图中访问(例如在 JSP 页面中通过 ${templateFile})

    @RequiresPermissions("template:edit")
    @RequestMapping("/input")
    public String input(TemplateFile templateFile,Model model){
        if(templateFile.getFilePath()==null)throw new SystemException("模板路径不能为空!");
        model.addAttribute("templateFile",templateFileService.findByPath(templateFile.getFilePath()));
        return "cms/template_input";
    }

通过视图返回templateFile.fileName、templateFile.filePath、templateFile.content

<div class="bjui-pageHeader">
        <div class="bjui-searchBar">
            <span style="font-size: 14px; padding: 3px;font-weight: 300"> 视图名称 </span><input type="text" class="input-nm" value=" ${templateFile.fileName!}"  readonly size="20" data-rule="required;length(1~128)" >
        </div>
</div>
<div class="bjui-pageContent">
    <form method="post" action="${ctxPath}/system/cms/template/save" id="j_model_form" data-toggle="validate" data-autorefresh="true" data-alertmsg="false">
        <input TYPE="hidden" NAME="filePath" value="${templateFile.filePath!}">
        <div class="form-group">
            <textarea   style="height:460px;width:100%;max-height:550px;" name="content"  data-rule="required;">${templateFile.content!}</textarea>
        </div>

    </form>
    </div>

漏洞复现

GET /system/cms/template/input?filePath=C://windows/win.ini HTTP/1.1
Host: 192.168.31.150
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: text/html, */*; q=0.01
X-Requested-With: XMLHttpRequest
Referer: http://192.168.31.150/system
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: bjui_theme=blue; SESSION=900b23ac-7411-4761-aadd-f080f0e86275
Connection: close

image-20250406175336432

image-20250406174440662

任意文件写入

漏洞位置在TemplateFileServiceImpl.java

这段代码将 TemplateFile 对象中的内容写入到指定路径的文件中。

    @Async
    public  void writeTemplateFileContent(TemplateFile templateFile){
        try {
            OutputStream outputStream = new FileOutputStream(new File(templateFile.getFilePath()));
            OutputStreamWriter os = new OutputStreamWriter(outputStream, "utf-8");
            os.write(templateFile.getContent());
            os.flush();
            os.close();
        }catch (Exception e){
            throw  new SystemException(e.getMessage());
        }
    }

save路由调用了writeTemplateFileContent方法,参数同样可控,这样可以外部传入FilePath和Content来写入文件

    @RequiresPermissions("template:save")
    @RequestMapping("/save")
    @ResponseBody
    public String save(TemplateFile templateFile){
        templateFileService.writeTemplateFileContent(templateFile);
        return JsonUtil.toSUCCESS("模板修改成功","template-tab",false);
    }

漏洞复现

image-20250406180638322

任意文件上传1

UploadComponent.java没有对传递的文件进行过滤。

image-20250406192643111

UploadController.java

/upload接口里面调用的uploadFile进行上传

    @RequestMapping("/upload")
    @ResponseBody
    public String upload(@RequestParam("file") MultipartFile multipartFile,
                         HttpServletRequest request){
        UploadBean result = uploadComponent.uploadFile(multipartFile,request);

        return JsonUtil.toUploadSUCCESS("上传成功!",result.getFileUrl());
    }

漏洞复现

image-20250406193249727

image-20250406193234694

任意文件上传2

/wangEditorUpload也调用了uploadFile,同样存在文件上传漏洞

    @RequestMapping("/wangEditorUpload")
    @ResponseBody
    public String WangEditorUpload(@RequestParam("file") MultipartFile multipartFile,
                         HttpServletRequest request) {
        UploadBean result = uploadComponent.uploadFile(multipartFile,request);
        return result.getFileUrl();

    }

漏洞复现

image-20250406193841492

任意文件上传3

/CKEditorUpload接口也调用了uploadFile,但是接受参数是upload

    @RequestMapping("/CKEditorUpload")
    @ResponseBody
    public String CKEditorUpload(@RequestParam("upload") MultipartFile multipartFile,
                                 HttpServletRequest request) {
        StringBuffer sb=new StringBuffer();
        UploadBean result = uploadComponent.uploadFile(multipartFile,request);
        sb.append("<script type=\"text/javascript\">");
        sb.append("window.parent.CKEDITOR.tools.callFunction("+ request.getParameter("CKEditorFuncNum") + ",'" +result.getFileUrl()+"','')");
        sb.append("</script>");
        return sb.toString();

image-20250406194253044

任意文件下载

UploadController.java

根据key和resType来查找文件并将文件内容返回,然后设置文件名并下载。

根据参数可以知道第一个是key值,第二个是文件类型

image-20250406202644656

根据传入的文件KEY在数据库查找附件记录

image-20250406202700203

在后台没找到这个功能,打算监控数据库,然后请求这个路由,这样就能监测到去那个表查的字段。

请求http://192.168.31.150/res/1.png

看到是在t_sys_attachment表,filekey字段获取的key

image-20250406203159297

image-20250406203300869

构造url:http://192.168.31.150/res/04684acfa9bd4c9a9226c51ed2dd77f4.docx

成功下载:全国少工委关于全队认真学习宣传贯彻党的十九大精神的通知.docx

image-20250406203421807