cve-2023-4450

简介

JeecgBoot 是一款基于代码生成器的低代码开发平台,零代码开发!采用前后端分离架构:SpringBoot2.x,Ant Design&Vue,Mybatis-plus,Shiro,JWT。强大的代码生成器让前后端代码一键生成,无需写任何代码! JeecgBoot引领新的开发模式(Online Coding模式-> 代码生成器模式-> 手工MERGE智能开发), 帮助解决Java项目70%的重复工作,让开发更多关注业务逻辑。既能快速提高开发效率,帮助公司节省成本,同时又不失灵活性!JeecgBoot还独创在线开发模式(No代码概念):在线表单配置(表单设计器)、移动配置能力、工作流配置(在线设计流程)、报表配置能力、在线图表配置、插件能力(可插拔)等等!是一款免费的数据可视化报表,含报表和大屏设计,像搭建积木一样在线设计报表!功能涵盖数据报表、打印设计、图表报表、大屏设计等

漏洞描述

JimuReport采用纯Web在线技术,支持多种数据源,如Oracle, MySQL, SQLServer, PostgreSQL等主流的数据库。2023年互联网上披露其存在模板注入漏洞,攻击者可构造恶意请求触发模板注入,造成远程代码执行。2023年8月15日,官方发布更新修复相关漏洞。

漏洞影响版本

JimuReport < 1.6.1

安全版本

JimuReport 1.6.1

环境搭建

用的是1.6.0的

我这里是用docker启动的远程代码调试,官网有写怎么快速docker搭建

在dockerfile哪里改成,然后在docker-compose哪里把调试端口穿出来

1
CMD java -DMYSQL-HOST=jimureport-mysql -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar jimureport-example-1.6.jar 

因为网上都有payload,先漏洞复现,再审计吧

漏洞复现

image-20240113172935481

漏洞分析

从漏洞分析来看,应该是直接把查询的结果插入模版里面了

首先直接定位找到路由吧

在jimureport-spring-boot-starter-1.6.0.jar包里首先看config,在里面初始化的时候发现会丢一个a类的过滤器

image-20240113221943331

从JimuReportConfiguration.class我们可以看见jimu报表对于如下的路由设置了拦截器:

1
2
3
"/jmreport/queryFieldBySql"
"/jmreport/loadTableData",
"/jmreport/dictCodeSearch"

而queryFieldBySql这里路由,在despreport的a/a类中

image-20240113222201198

我们可以打个断点从这里远程调试分析一下

这里i.a就是判断里面有没有存在sql注入的,继续往下g.c感觉没什么意义是null和字符串的都会相当于返回个true,和this.jmBaseConfig.getSaas()默认为fasle.跟我们的漏洞没啥关系

image-20240114153517103

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static boolean c(Object var0) {
if (null == var0) {
return true;
} else if (var0 instanceof CharSequence) {
return a((CharSequence)var0);
} else if (var0 instanceof Map) {
return a((Map)var0);
} else if (var0 instanceof Iterable) {
return a((Iterable)var0);
} else if (var0 instanceof Iterator) {
return a((Iterator)var0);
} else {
return a(var0) ? b(var0) : false;
}
}

而下面的g.d就是看了看感觉是判断自己写的数据源是不是空的,不是就会尝试去连接对应的数据源,跟我们这也没关系,走下一步

1
2
3
4
try {
Map var12 = this.reportDbService.parseReportSql(var2, var3, var4, var5);
return var12.get("message") != null ? Result.OK(var12) : Result.OK("解析成功", var12);
}

这里看函数名就应该猜到是解析sql的意思了跟进下一步到

1
2
3
else {
sql = f.a(sql, var8, (JSONArray)null);
}

跟进a的方法,发现这里又会检查一遍有没有sql注入

image-20240114155655241

然后到b方法

image-20240114155854381

这里的a的方法 是提取输入字符串 sql语句 中所有匹配正则表达式模式 #{word} 的子字符串,并将这些 word 部分存储在一个 HashSet 中返回。这可以用于提取输入字符串中的特定模式,并去除重复的模式。然后将里面的#{xxx}替换为xxx,然后到

1
var0 = a(var2, var0);

image-20240114160852599

这个函数现在匹配符合${ }字的字符串,又来分组,我们传入这里的var0是空,这里也不用分析了,往下调试,到重点了var1 = FreeMarkerUtils.a(var1, var2);

image-20240114162059505

这段代码的主要作用是使用 FreeMarker 模板引擎解析给定的模板字符串 var0,并使用配置、数据模型进行解析,最终返回解析后的字符串结果。其中,配置对象 var2 用于配置引擎属性,数据模型 var1 提供了模板中所需的变量和方法。解析过程中,捕获异常并输出相应的日志信息。
重点是(new Template(“template”, new StringReader(var0), var2)).process(var1, var3);

这里创建了一个新的模版,跟进process,这里就和之前FreeMarker分析一样了会解析这个模版

1
2
3
public void process(Object dataModel, Writer out) throws TemplateException, IOException {
this.createProcessingEnvironment(dataModel, out, (ObjectWrapper)null).process();
}

参考链接

CVE-2023-4450:jeecgboot积木报表系统 模板注入远程代码执行&分析 | ycx’s blog (ilikeoyt.github.io) o(╥﹏╥)o

jeect-boot积木报表漏洞rce分析(CVE-2023-4450) - 先知社区 (aliyun.com)