转载

JAVA代码审计-JEECG快速开发平台(一)

漏洞: 两个漏洞getshell,无需知道账号密码

0x00 简述

JEECG是一款基于代码生成器的J2EE快速开发平台,开源界“小普元”超越传统商业企业级开发平台。引领新的开发模式(Online Coding模式(自定义表单)->代码生成器模式->手工MERGE智能开发), 可以帮助解决Java项目60%的重复工作,让开发更多关注业务逻辑。

环境安装:

IDEA 已经安装maven

数据库 mysql

源代码 https://github.com/zhangdaiscott/jeecg

tomcat

0x01 安装

  1. 下载源代码 https://github.com/zhangdaiscott/jeecg
  2. 用idea导入项目,之后会自动下载依赖
  3. 修改数据库配置文件,替换账号密码
  4. 需要手动在数据库中创建jeecg数据库,并导入数据
  5. 配置tomcat,启动服务
    JAVA代码审计-JEECG快速开发平台(一)

JAVA代码审计-JEECG快速开发平台(一)

JAVA代码审计-JEECG快速开发平台(一)

修改账号密码

JAVA代码审计-JEECG快速开发平台(一)

需要导入的数据

JAVA代码审计-JEECG快速开发平台(一)

配置tomcat

JAVA代码审计-JEECG快速开发平台(一)

JAVA代码审计-JEECG快速开发平台(一)

JAVA代码审计-JEECG快速开发平台(一)

JAVA代码审计-JEECG快速开发平台(一) 然后启动服务

JAVA代码审计-JEECG快速开发平台(一)

0x01 路由

JEECG快速开发平台基于spring MVC 框架

使用@Controller将一个类声明为控制器类,然后在通过@RequestMapping配置路由映射。

简单举例说明:

/src/main/java/com/jeecg/demo/controller/JfromOrderController.java

要访问JfromOrderController.java类中的方法

首先访问 @RequestMapping(params = "qrcode")

JAVA代码审计-JEECG快速开发平台(一) url: http://localhost:8080/jeecgFormDemoController.do?qrcode

JAVA代码审计-JEECG快速开发平台(一)

然后需要访问: @RequestMapping("/filedeal")

JAVA代码审计-JEECG快速开发平台(一)

url: http://localhost:8080/jeecgFormDemoController/filedeal.do

页面报错,是因为这个请求需要post,是上传文件的文件操作的功能

0x02 漏洞

通过两个漏洞直接getshell,直接上演示

首先先登录(需要活得request包)

访问 http://localhost:8080/jeecgFormDemoController.do?commonUpload 上传文件

JAVA代码审计-JEECG快速开发平台(一)

直接修改文件名后缀:

JAVA代码审计-JEECG快速开发平台(一)

shell上传成功

JAVA代码审计-JEECG快速开发平台(一)

但是需要我们登录后台,要有账号密码,能否绕过登录,直接getshell呢?

权限的判定是通过sessionid,如果我们可以得到一个已经登录的sessionid,就可以上传文件了

JAVA代码审计-JEECG快速开发平台(一)

JEECG快速开发平台存在一个未授权漏洞,也可以说是信息泄露漏洞

http://localhost:8080/webpage/system/druid/websession.json

JAVA代码审计-JEECG快速开发平台(一)

既然获取到了sessionid,将请求包中的session替换

JAVA代码审计-JEECG快速开发平台(一)

0x02 分析

漏洞原因很简单,上传文件没有判断文件名后缀,导致直接getshell

/src/main/java/org/jeecgframework/web/cgform/controller/upload/CgUploadController.java

ajaxSaveFile方法

JAVA代码审计-JEECG快速开发平台(一)

/**
     * 自动上传保存附件资源的方式
     * @return
     */
    @RequestMapping(params = "ajaxSaveFile")
    @ResponseBody
    public AjaxJson ajaxSaveFile(MultipartHttpServletRequest request) {
        AjaxJson ajaxJson = new AjaxJson();
        Map<String, Object> attributes = new HashMap<String, Object>();
        try {
            Map<String, MultipartFile> fileMap = request.getFileMap();
            String uploadbasepath = ResourceUtil.getConfigByName("uploadpath");
            // 文件数据库保存路径
            String path = uploadbasepath + "/";// 文件保存在硬盘的相对路径
            String realPath = request.getSession().getServletContext().getRealPath("/") + "/" + path;// 文件的硬盘真实路径
            realPath += DateUtils.getDataString(DateUtils.yyyyMMdd) + "/";
            path += DateUtils.getDataString(DateUtils.yyyyMMdd) + "/";
            File file = new File(realPath);
            if (!file.exists()) {
                file.mkdirs();// 创建文件时间子目录
            }
            if(fileMap != null && !fileMap.isEmpty()){
                for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
                    MultipartFile mf = entity.getValue();// 获取上传文件对象
                    String fileName = mf.getOriginalFilename();// 获取文件名
                    String swfName = PinyinUtil.getPinYinHeadChar(oConvertUtils.replaceBlank(FileUtils.getFilePrefix(fileName)));// 取文件名首字母作为SWF文件名
                    String extend = FileUtils.getExtend(fileName);// 获取文件扩展名
                    String noextfilename=DateUtils.getDataString(DateUtils.yyyymmddhhmmss)+StringUtil.random(8);//自定义文件名称
                    String myfilename=noextfilename+"."+extend;//自定义文件名称
                    String savePath = realPath + myfilename;// 文件保存全路径
                    write2Disk(mf, extend, savePath);
                    TSAttachment attachment = new TSAttachment();
                    attachment.setId(UUID.randomUUID().toString().replace("-", ""));
                    attachment.setAttachmenttitle(fileName.substring(0,fileName.lastIndexOf(".")));
                    attachment.setCreatedate(new Timestamp(new Date().getTime()));
                    attachment.setExtend(extend);
                    attachment.setRealpath(path + myfilename);

                    String globalSwfTransformFlag = ResourceUtil.getConfigByName("swf.transform.flag");
                    if("true".equals(globalSwfTransformFlag) && !FileUtils.isPicture(extend)){
                        attachment.setSwfpath( path + FileUtils.getFilePrefix(myfilename) + ".swf");
                        SwfToolsUtil.convert2SWF(savePath);
                    }

                    systemService.save(attachment);
                    attributes.put("url", path + myfilename);
                    attributes.put("name", fileName);
                    attributes.put("swfpath", attachment.getSwfpath());
                    attributes.put("fileid", attachment.getId());

                }
            }
            ajaxJson.setAttributes(attributes);
        } catch (Exception e) {
            e.printStackTrace();
            ajaxJson.setSuccess(false);
            ajaxJson.setMsg(e.getMessage());
        }
        return ajaxJson;
    }
String fileName = mf.getOriginalFilename();// 获取文件名
                    String swfName = PinyinUtil.getPinYinHeadChar(oConvertUtils.replaceBlank(FileUtils.getFilePrefix(fileName)));// 取文件名首字母作为SWF文件名
                    String extend = FileUtils.getExtend(fileName);// 获取文件扩展名
                    String noextfilename=DateUtils.getDataString(DateUtils.yyyymmddhhmmss)+StringUtil.random(8);//自定义文件名称
                    String myfilename=noextfilename+"."+extend;//自定义文件名称
                    String savePath = realPath + myfilename;// 文件保存全路径

获取了文件扩展名,没有进行任何过滤,就进行拼接生成新的文件名,来保存。

0x03 其他

JEECG快速开发平台很合适练习java的代码审计,里面还存在的漏洞有:sql注入、任意文件下载、任意文件删除、EL表达式注入、xss,SSRF漏洞等(这是已经发现的)

原文  https://xz.aliyun.com/t/4405
正文到此结束
Loading...