Skip to content
KitploitKITPLOIT
ИнструментыБлог
Log in
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-64640 — Воспроизведение для CVE-2026-64640 — Apache Polaris Iceberg REST register/register-view выдаёт учётные данные хранилища и читает выбранное атакующим расположение метаданных до проверки allowedLocations (перекрёстное чтение между арендаторами через confused-deputy). Затронуты версии ≤ 1.6.0, исправлено в 1.7.0. | Kitploit
Инструменты/GitHubGitHub/oscerd/cve-2026-64640
РазведкаАнализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийЭксфильтрация данныхТестирование на ПроникновениеБезопасность облачных средБезопасность API
GitHuboscerd/cve-2026-64640

CVE-2026-64640

Репозиторий
151 месяц назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →

Описание

Воспроизведение для CVE-2026-64640 — Apache Polaris Iceberg REST register/register-view выдаёт учётные данные хранилища и читает выбранное атакующим расположение метаданных до проверки allowedLocations (перекрёстное чтение между арендаторами через confused-deputy). Затронуты версии ≤ 1.6.0, исправлено в 1.7.0.

Поделиться

CVE-2026-64640 — Apache Polaris: выдача учетных данных до проверки местоположения в register

Самодостаточный воспроизводитель одной командой для CVE-2026-64640: конечные точки register в Iceberg REST в Apache Polaris выпускают учетные данные облачного хранилища для пути, указанного вызывающей стороной, и читают этот путь на стороне сервера до проверки его по allowedLocations каталога.

Участник (principal), единственное право которого — создание таблиц в собственном каталоге, может заставить Polaris использовать учетные данные хранилища каталога для чтения объектов, которых каталогу никогда не разрешалось касаться: префикс другого арендатора, другой bucket, всё, что доступно участнику хранилища.

CVECVE-2026-64640
Компонентpolaris-runtime-service — IcebergCatalog / LocalIcebergCatalog: registerTable, registerView
Конечные точкиPOST /api/catalog/v1/{prefix}/namespaces/{namespace}/register
POST /api/catalog/v1/{prefix}/namespaces/{namespace}/register-view (1.6.0+)
CWECWE-441 (confused deputy), CWE-639 (обход авторизации через контролируемый пользователем ключ), CWE-918 (SSRF)
КритичностьВысокая — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N (8.1)
Затронуто≤ 1.6.0 (проверено на 1.3.0-incubating, 1.4.0, 1.4.1, 1.5.0, 1.6.0)
Исправлено в1.7.0 — в 1.6.0 исправлен только путь таблицы, и ошибка появилась на новом пути представления
Требуемые привилегииодин аутентифицированный участник с TABLE_CREATE / CATALOG_MANAGE_CONTENT на любом каталоге — без админа

1.6.0 — это не исправление. Он закрывает register (непреднамеренно, в рамках feature-запроса) и поставляет новый конечный точку register-view с той же ошибкой порядка. Воспроизводитель доказывает обе части. Обновитесь до 1.7.0.

Запуск

Требования: Docker с плагином Compose v2, curl, python3, bash. Больше ничего — окружение разворачивается из опубликованных образов и удаляется после.

./exploit.sh                 # default: apache/polaris:1.4.1  -> reproduces via register
./exploit.sh --tag 1.6.0     # partially fixed               -> reproduces via register-view
./exploit.sh --tag 1.7.0     # comprehensively fixed         -> refuses cleanly on both
./scripts/version-matrix.sh  # every release, side by side

Код выхода 0 означает, что уязвимость воспроизведена, 1 — не воспроизведена, 2 — окружение не удалось запустить. Каждый запрос и ответ сохраняются в evidence/<timestamp>-polaris-<tag>/.

Как выглядит окружение

  catalog  tenant_a_catalog        allowedLocations = [ s3://bucket123 ]
  actor    low_priv_user           CATALOG_MANAGE_CONTENT on that catalog, nothing else
  target   s3://tenant-b-private   another tenant's bucket:
                                     no allowedLocations entry, no grant, no relation
                                     to the attacker's catalog — but reachable by the
                                     credentials that back it

Последняя строка — самая реалистичная часть. Операторы ограничивают каталог с помощью allowedLocations; нижележащая IAM-роль почти всегда шире одного префикса. allowedLocations — это стена. Эта ошибка обходит её.

Что это доказывает

Тест 0 — стена реальна. Создание таблицы с явным расположением в s3://tenant-b-private отклоняется с 403 ForbiddenException, до чтения чего-либо. Polaris отлично знает, что расположение вне допустимых границ.

Тест 1 — register всё равно читает это. Тот же участник направляет register на s3://tenant-b-private/sales/metadata/00007-tenant-b-sales.metadata.json. Ответ также 403 — но в нём цитируется s3://tenant-b-private/warehouse/CANARY-64640-4f1c9e2a-tenant-b-sales, строка, которая существует только внутри тела этого объекта:

{"error":{"message":"Invalid locations '[s3://tenant-b-private/warehouse/sales/data,
s3://tenant-b-private/warehouse/CANARY-64640-4f1c9e2a-tenant-b-sales]' for identifier
'tenant_a_ns.pwn_canary': s3://tenant-b-private/warehouse/sales/data is not in the list
of allowed locations: [s3://bucket123/tenant_a_ns]","type":"ForbiddenException","code":403}}

В запросе никогда не упоминается warehouse/. Polaris мог получить эти строки только путём выборки и разбора объекта с учётными данными каталога. 403 — это Polaris, фиксирующий нарушение на один шаг после чтения, которое он должен был предотвратить.

Тест 2 — что возвращается. Два отдельных поля, извлечённых из документа-жертвы, возвращаются вызывающей стороне: объявленное расположение таблицы location и свойство write.data.path.

Тест 3 — оракул перечисления хранилища. Тот же вызов отвечает по-разному для каждого состояния цели за пределами allowedLocations:

зонд (все вне allowedLocations)ответ 1.4.1
допустимые метаданные Iceberg, существуют403 ForbiddenException + извлечённые расположения в ответе
ключ отсутствует400 NotFoundException — Location does not exist: …
bucket не существует400 NoSuchBucketException — необработанная ошибка S3 SDK
существует, но не метаданные Iceberg503 RuntimeIOException — Failed to read file: …

Четыре различимых ответа означают четыре факта о хранилище, которые вызывающая сторона не имеет права узнавать. В реальном AWS зонд существования bucket достигает глобального пространства имён bucket'ов S3, используя учётные данные каталога.

На исправленной сборке каждая строка этой таблицы — один и тот же 403 с указанием только запрошенного пути, и ничего изнутри объекта не возвращается — скрипт обнаруживает эту сигнатуру и сообщает NOT VULNERABLE — pre-validation observed.

Тест 4 — та же ошибка на register-view. Polaris 1.6.0 добавил POST .../namespaces/{ns}/register-view, ведущий к registerView, который загружает FileIO и разбирает документ вызывающей стороны без предварительной проверки — именно то, что registerTable только что перестал делать. На 1.6.0 view-канарейка возвращает:

{"error":{"message":"Invalid locations '[s3://tenant-b-private/warehouse/CANARY-64640-VIEW-8d3b7a15-tenant-b]'
for identifier 'tenant_a_ns.pwn_view': … is not in the list of allowed locations:
[s3://bucket123/tenant_a_ns]","type":"ForbiddenException","code":403}}

Таким образом, развёртывание 1.6.0 по-прежнему остаётся уязвимым к тому же примитиву через другую конечную точку. В 1.4.1 и старше эта конечная точка не существует, и скрипт сообщает об этом.

Корневая причина

IcebergCatalog.registerTable (LocalIcebergCatalog начиная с 1.6.0), до исправления — registerView имеет ту же структуру:

String locationDir = metadataFileLocation.substring(0, lastSlashIndex);   // attacker-controlled
...
FileIO fileIO =
    loadFileIOForTableLike(
        identifier,
        Set.of(locationDir),                                              // credentials minted here
        resolvedParent,
        new HashMap<>(tableDefaultProperties),
        Set.of(PolarisStorageActions.READ, PolarisStorageActions.LIST));

InputFile metadataFile = fileIO.newInputFile(metadataFileLocation);       // server-side GET
TableMetadata metadata = TableMetadataParser.read(metadataFile);          // server-side parse
ops.commit(null, metadata);                                               // allowedLocations checked HERE

Цепочка выдачи (loadFileIOForTableLike → StorageAccessConfigProvider.getStorageAccessConfig → *StorageIntegration.getSubscopedCreds) не выполняет собственную проверку allowedLocations, поэтому единственная проверка — на этапе commit — и к этому моменту привилегированное чтение уже произошло, а его результат находится в ответе.

Скачать инструмент