jeect-boot积木报表漏洞rce分析(CVE-2023-4450)
2023-12-29 15:49:29 Author: xz.aliyun.com(查看原文) 阅读量:9 收藏

一.漏洞复现

这里使用的漏洞环境时vulhub的jeect-boot。靶场介绍说是:

以下的 Jimureport 组件库中都存在,由于未授权的 API /jmreport/queryFieldBySql 使用了 freemarker 解析 SQL 语句从而导致了 RCE 漏洞的产生。

POST /jeecg-boot/jmreport/queryFieldBySql HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: curl/7.88.1
Accept: */*
Content-Type: application/json
Content-Length: 121
Connection: close

{
    "sql": "<#assign ex=\"freemarker.template.utility.Execute\"?new()>${ex(\"touch /tmp/success\")}",
    "type": "0"
}

二.漏洞跟踪分析

这里的漏洞环境搭建是使用了jeecg-boot 3.5.3环境,从github下载即可,配置mysql和redis数据库,随后使用idea启动调试。

拦截器路由

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

"/jmreport/queryFieldBySql"
"/jmreport/loadTableData",
"/jmreport/dictCodeSearch"

入口点路由(/queryFieldBySql)

可以发现他的具体代码在这个位置的a.class

首先从json中解析到了sql,把这个变量的参数放到i.a(var2)去执行,跟进这里:

可以发现是做sql注入拦截的,waf一样的存在。继续往下走

在这里进行执行了,传入了var2,var3,var4,var5

他们分别是在json中传入的参数:

sql
dbSource
paramArray
type

但是在payload中传入的只有:sql和type=0(这里type内容是什么都可以,但要有type这个,可以为空,但一定要穿进去)

然后继续跟Map var12 = this.reportDbService.parseReportSql(var2, var3, var4, var5);

这里传入的var2是:

<#assign ex="freemarker.template.utility.Execute"?new()>${ex("open -a Calculator.app")}

随着继续跟进,不用看type,因为不影响。直接看sql

这里走入的是第二个sql的,因为paramArray是null

我们在f.a打断点,继续跟进,是在这里实现rce的

这里的var0 = b(var0, var1);返回的不变,没有改变,来到了var0 = a(var2, var0);

随后在a中,调用了:var1 = FreeMarkerUtils.a(var1, var2);

Freemarker调用点

这边继续来到FreeMarkerUtils.a

在这里执行了命令:(new Template("template", new StringReader(var0), var2)).process(var1, var3);

跟踪process

随后继续跟踪process,从getRootTreeNode进入

来到了进入this.doAutoImportsAndIncludes(this);

继续跟进env.getMainTemplate();

初始化模板 & 命令执行

这里的功能主要是针对自动导入和包含功能的调用

该环境对象具有许多属性和方法,用于处理模板的渲染和执行。这些属性和方法包括配置(configuration)、根数据模型(rootDataModel)、指令堆栈(instructionStack)、异常处理器(templateExceptionHandler)等。

在给定的代码中,我看到了一个模板字符串的定义 "<#assign ex = "freemarker.template.utility.Execute"?new()>${ex("open -a Calculator.app")}"。这里使用了FreeMarker模板语法来定义一个变量 ex,并使用其调用了系统命令 open -a Calculator.app。

随后进入,继续追踪,这里我们看到了调用了this.visit。而visit主要是:对该元素进行访问处理。

在这里的element,就是创建new一个模板。(后续visit也是会反复调用自己,从反射调用类到获取命令)

这里可以看到,TemplateElement类型的变量里,valueExp为:freemarker.template.utility.Execute"?new()

"freemarker.template.utility.Execute"?new() 是FreeMarker模板语法中的一种使用方式,用于执行系统命令。通过这种方式,攻击者可以在受影响的应用程序上执行操作系统命令,并可能导致潜在的安全问题。

而且继续跟踪的,可以看到el的内容成为了${ex("open -a Calculator.app")}

一方面是创建了一个可以执行命令的模板,另一方面是把将要执行的命令拆出来,继续调用自己一遍

这里的变量内容

在调用自己之后,会回到这个函数accept方法里

随后这里调用eval,和刚才传进来的

具体在这里执行命令:

constantValue = {SimpleScalar@19070} "freemarker.template.utility.Execute"
 value = "freemarker.template.utility.Execute"

继续跟踪,来到了eval里的this._eval(env),在_eval里调用了ConstructorFunction,这里也就是反射调用了

freemarker.template.utility.Execute

反射后,创建新的对象

获取命令传入最终执行

那如何获得执行的具体命令是什么呢?(之前只是对执行命令类部分的分析)

随着他visit调用自身,最后来到了accept方法中,

不断的跟踪下去,即可发现,最终来到了Runtime.getRuntime().exec(aExecute);

成功执行了命令

最终附上执行命令的总体流程

三.总结

​ 这个漏洞其实并没有什么难得,主要就是跟踪一下,最后是可以发现rce的触发点。同时这里不光有freemarker的rce,还有sql注入点,可以直接未授权执行sql语句。也许可以继而mysql后渗透,通过mysql控制服务器。

这里我随便执行一下,创建了一个用户:

不过在后续的版本中,官方也是给这里增加了权限设置,之前这里都是未授权访问的。


文章来源: https://xz.aliyun.com/t/13224
如有侵权请联系:admin#unsafe.sh