CVE-2024-23328 DataEase jdbc反序列化漏洞分析

DataEase是一款开源的数据可视化分析工具。DataEase数据源中存在一个反序列化漏洞,可以被利用来执行任意代码。漏洞代码位于`core/core-backend/src/main/java/io/dataease/datasource/type/Mysql.java`文件中。可以绕过mysql jdbc攻击的黑名单,攻击者可以进一步利用该漏洞进行反序列化执行或读取任意文件。该漏洞已在1.18.15和2.3.0版本中修复。

漏洞概述:

DataEase是一款开源的数据可视化分析工具。DataEase数据源中存在一个反序列化漏洞,可以被利用来执行任意代码。漏洞代码位于core/core-backend/src/main/java/io/dataease/datasource/type/Mysql.java文件中。可以绕过mysql jdbc攻击的黑名单,攻击者可以进一步利用该漏洞进行反序列化执行或读取任意文件。该漏洞已在1.18.15和2.3.0版本中修复。

调试环境搭建

去官网或github下载安装包和源代码,然后再linux部署,这里下载的是1.18.14版本的

下载完成后解压,然后编辑/detaease-vxxx/dataease/docker-compose.yml,添加调试端口5005

image-20240326114008102

然后运行/detaease-vxxx/install.sh等待docker部署完成

docker部署后是有两个容器,进入detaease的容器编辑文件/deployments/run-java.sh ,添加调试参数

debug_options()中添加:

echo "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"

image-20240326114520110

修改完成后使用docker restart xx重启该容器即可

除了使用GitHub上的源码调试,还可以用docker里面运行的jar /opt/apps/backend-1.18.14.jar

漏洞分析

补丁分析

首先查看一下漏洞补丁

image-20240326120015431

在补丁中可以看到,修补的方式是添加了一个判断条件, getExtraParams() 返回的内容通过URL解码后是否存在于非法参数列表中,即黑名单

说实话,我并没有找到core/core-backend/src/main/java/io/dataease/datasource/type/Mysql.java这个文件

只找到了src/main/java/io/dataease/dto/datasource/MysqlConfiguration.java

image-20240326145839057

参数黑名单如下:

private List illegalParameters = Arrays.asList("autoDeserialize", "queryInterceptors", "statementInterceptors", "detectCustomCollations", "allowloadlocalinfile", "allowUrlInLocalInfile", "allowLoadLocalInfileInPath");  

public List getIllegalParameters(){  
        List newIllegalParameters = new ArrayList<>();  
        newIllegalParameters.addAll(illegalParameters);  
        newIllegalParameters.addAll(Arrays.asList("allowloadlocalinfile", "allowUrlInLocalInfile", "allowLoadLocalInfileInPath"));  
        return newIllegalParameters;  
    }

补丁就加了个URL编码解码,说明漏洞利用点在于URL编码绕过了黑名单

漏洞验证

根据漏洞所在代码的功能找到对应功能点进行测试

这个是jdbc url的构造,说明这个是用来连接数据库的,在添加数据源的地方可以找到连接数据库的功能

image-20240326151716540

image-20240326151841423

这个额外的JDBC连接字符串可控,如果不存在黑名单,就大概率存在反序列化漏洞

验证漏洞很简单,将autoDeserialize=true编码然后填写到JDBC连接字符串中(等号不编码),autoDeserialize存在于黑名单中:

%61%75%74%6f%44%65%73%65%72%69%61%6c%69%7a%65=%74%72%75%65

点击校验,发现能够正常的得到连接响应,说明绕过了黑名单。

image-20240326155216351

这个漏洞我没有利用成功,可能是这个版本还太新了,这个版本利用的jdbc版本是8.0.28的,似乎没有反序列化漏洞

image-20240326155854650

经过一波摸索,发现这个可以自己上传驱动,漏洞实锤了

image-20240326163607911

直接使用工具就能够利用,读取文件需要添加allowLoadLocalInfile=true ,该工具没给出

%61%6c%6c%6f%77%4c%6f%61%64%4c%6f%63%61%6c%49%6e%66%69%6c%65=%74%72%75%65

读取/etc/passwd成功

image-20240326222203194

疑问解释

为什么jdbc连接时正常解析url编码?

这个需要调试跟踪一下

在构造完jdbc url后在io.dataease.provider.datasource.JdbcProvider.java进行连接,跟进connet方法

image-20240326162154614

来到com.mysql.cj.jdbc.NonRegisteringDriver

image-20240326173635715

首先来到accept(url) 判断这个url是否被允许请求

image-20240326173756963

继续跟进

image-20240326173831509

isConnectionStringSupported方法中通过正则匹配出jdbc:mysql:

image-20240326174036065

跟进decodeSkippingPlusSign

image-20240326174108561

这里会将+替换成%2B然后进行URLdecode

返回到isConnectionStringSupported

image-20240326174759809

跟进isSupported

image-20240326174955819

这个枚举了Scheme,看jdbc:mysql:是否存在。

返回到connect

image-20240326175355748

跟进getConnectionUrlInstance

image-20240326175520805

这个buildConnectionStringCacheKey方法把账号密码添加到了url中

image-20240326175557785

往下,根据返回的connStringCacheKey尝试从缓存中获取connectionUrl 没有缓存就通过parseConnectionString获取ConnectionUrlParser对象

image-20240326180035844

跟进parseConnectionString,此时的参数是connString ,即还没有加上账号密码的那个

image-20240326180505412

继续跟进ConnectionUrlParser()

image-20240326180634516

将connString赋值给this.baseConnectionString ,然后调用this.parseConnectionString() ,跟进

image-20240326181048646

这里对数据库名进行了解码,并且通过正则表达式将URL参数赋值部分取出保存在this.query

返回到getConnectionUrlInstance

刚刚解析得到的connStrParser传入到了getConnectionUrlInstance中进行处理

image-20240326214424293

跟进getConnectionUrlInstance

image-20240326215413683

因为info里面只有password和user,没有dnsSrv这个key,所有这里走的是else这个分支

(parsedProperties = parser.getProperties()).containsKey(dnsSrvPropKey.getKeyName() ,这个代码是从url参数进行查找dnsSrv,这里可能会对参数进行url解码

跟进这个getProperties()

image-20240326215948104

因为this.parsedProperties为null ,进入到this.parseQuerySection()中,继续跟进

image-20240326220250150

这里的this.query是上面正则表达式解析出来的URL参数 ,因为不为null 进入到了processKeyValuePattern中,PROPERTIES_PTRN的内容如下:

image-20240326220514764

跟进processKeyValuePattern

image-20240326220650132

这里根据正则表达式匹配出key和value ,并且通过decode()函数解码

image-20240326220853125

这个decode就是进行URLdecode的地方

image-20240326220950422

END

  • 发表于 2024-04-02 10:00:00
  • 阅读 ( 15763 )
  • 分类:漏洞分析

0 条评论

请先 登录 后评论
Stree
Stree

果农

8 篇文章

站长统计