В нашей предыдущей публикации мы увидели, как обнаружить и защититься от прямого отравления Pipeline Исполнение (Д-СИЗ). Мы также увидели, как обнаружить эту уязвимость с помощью Ксигени-сканер, а также некоторые механизмы защиты.
Отравленные Pipeline Исполнение (средства индивидуальной защиты) создается, когда злоумышленник может изменить pipeline логику одним из двух способов:
- Изменив файл конфигурации CI (файл pipeline) -> Прямые СИЗ (Д-СИЗ)
- Изменяя файлы, на которые ссылается pipeline (например: сценарии, на которые ссылаются изнутри pipeline файл конфигурации) -> Косвенные СИЗ (I-PPE)
В этом посте мы подробно углубимся в косвенные СИЗ. Но перед этим и в дополнение к моему предыдущему посту давайте сначала посмотрим, как GitHub управляет выполнением pipelines и каковы механизмы защиты от D-PPE.
Как GitHub защищает выполнение pipelineэто исходит от пиарщиков?
Как GitHub работает с выполнением измененных pipelines?
Модифицированный pipelines может происходить от Pushes или Pull Requests (ПР). В качестве основной передовой практики настоятельно рекомендуется избегать любого прямого «push» в защищенную ветку и использовать Pull Requests как механизм, обеспечивающий проведение некоторой проверки перед принятием любого предоставленного кода.
Pull Requests могут поступать из двух разных источников:
- PR, исходящие от вилки
- PR, исходящие от ветви
PR от вилки может прийти либо из что такое варган? or частная Хранилища.
Поскольку мы имеем дело со СИЗ (отравленными Pipeline Исполнение), наша главная задача – не «принятие» ПР, а исполнение модифицированного pipeline в процессе принятия/утверждения ОР. В основе атаки PPE лежит непреднамеренное выполнение «вредоносной» модифицированной программы. pipeline.
В двух словах: Отравленный Pipeline Исполнение (PPE) производится, когда злоумышленник может изменить pipeline логика.
Есть два варианты:
- Прямые СИЗ (Д-СИЗ): В сценарии D-PPE злоумышленник изменяет файл конфигурации CI в репозитории, к которому у них есть доступ, либо отправив изменение непосредственно в незащищенную удаленную ветку репозитория, либо отправив PR с изменением из ветки или форка. Поскольку КИ pipeline выполнение определяется командами в измененном файле конфигурации CI, вредоносные команды злоумышленника в конечном итоге запускаются на узле сборки после завершения сборки. pipeline срабатывает.
- Косвенные СИЗ (I-СИЗ): В некоторых случаях возможность D-PPE недоступна противнику, имеющему доступ к SCM репозиторий (например, если pipeline настроен на получение файла конфигурации CI из отдельной защищенной ветки в том же репозитории). В таком случае, вместо того, чтобы отравлять pipeline сам злоумышленник внедряет вредоносный код в файлы, на которые ссылается pipeline (например: сценарии, на которые ссылаются изнутри pipeline Файл конфигурации)
В обоих случаях, GitHub выполнит измененный pipeline без необходимости предварительного рассмотрения или одобрения.
Пиар от вилок на что такое варган? РЕПО
GitHub позволяет настроить поведение при обработке PR, поступающие из форков в публичных репозиториях.
Когда PR исходит из форка, GitHub всегда требует определенного уровня «одобрения» перед выполнением pipeline связанный с пиаром. Этот уровень одобрения варьируется от слабого до строгого.
At Уровень организации (Организация>>Настройки>>Действия>>Общие), вы можете выбрать один из нескольких вариантов «одобрения»:
Самый строгий — последний («Требовать одобрения от всех внешних соавторов»), потому что GitHub всегда будет требовать одобрения, когда PR исходит от форков от внешних соавторов.
Но даже в этом строгом случае существуют различия между соавторами с разрешениями на чтение и запись.
- Когда пиар исходит от читать пользователь, выполнение pipeline ОСТАНОВЛЕНО до момента одобрения изменений. Если утверждение одобрено, то измененный pipeline выполнен.
- Когда пиар исходит от записывать пользователь, одобрение не требуется, и измененное pipeline всегда выполняется !!
В заключение можно сказать, что PR, поступающие из форков публичных репозиториев, слабо защищены от средств индивидуальной защиты. Существует некоторая защита от внешних пользователей (чтения), но нет ничего, связанного с внутренними пользователями (записью).
Как насчет PR, поступающие от форков из частных репозиториев?
Пиар от вилок на частная РЕПО
В этом сценарии GitHub предоставляет некоторые полезные параметры конфигурации.
Вышеуказанные настройки можно настроить либо на организация или, по крайней Repo уровень.
После появления ни одна опция не отмечена, GitHub будет запросить одобрение и он не выполнит измененное pipeline. Это самая безопасная конфигурация!!
самая небезопасная конфигурация когда Запуск рабочих процессов из форка pull request" проверено. В этом случае, как для пользователей чтения, так и для записи, Github автоматически выполнит измененный файл. pipeline!! И эта ситуация может быть даже хуже если "Отправка токенов записи в рабочие процессы из форка pull requests(Основной ключ) и Отправлять секреты и переменные в рабочие процессы из форка pull requests» проверяются. Не делайте этого без явной причины!!
Если "Требовать одобрения для вилки pull request Рабочие процессы», описанная выше ситуация несколько улучшается: GitHub запросит одобрение и не выполнит измененное pipeline для пользователя чтения, но он все равно выполнит его для пользователя записи.
Форкс видел, а как насчет PR из филиалов?
PR от ветви
Чтобы защитить этот сценарий, вы должны полагаться на Правила защиты филиалов.
На уровне репо вы можете создавать правила защиты веток для любой ветки. Эти правила добавляют некоторые ограничения на изменение защищенных ветвей.
Несмотря на то, что вы настраиваете правило «Требовать pull request перед слиянием(Основной ключ) и Требовать одобрения», модифицированный pipeline будет автоматически выполнено при создании PR.. «Одобрение» будет применяться только к действию по слиянию.
А как насчет косвенного отравления? Pipeline Типы
Как мы видели выше, воздействие D-PPE можно смягчить, используя pull_request_target, Но не распространяется на I-PPE.
Если вы используете pull_request_target, оформлением по умолчанию будет базовый код. Но если вы хотите проверить некоторые проверки предоставленного кода (PR-кода), вам необходимо явно извлечь PR-код. Таким образом, если PR-код изменил какой-либо сценарий оболочки, вызванный pipeline, «база» (безопасная) pipeline вызовет «модифицированный» сценарий оболочки → Косвенный PPE!!
Решение этой проблемы немного сложнее (не существует такого волшебного средства, как pull_request_target).
Наша команда pipeline теперь безопасно для D-PPE, поскольку мы используем pull_request_target. Но он по-прежнему уязвим для I-PPE.
В нашем тестовом примере нам нужно получить PR-код, чтобы выполнить сборку, но тесты выполняются на артефакте, сгенерированном сборкой.
Итак .. почему бы не проверить обе кодовые базы?
- PR-код Checkout, потому что мы хотим создать и протестировать предоставленный код.
- Базовый код Checkout для запуска исходной версии pipeline и сценарии сборки/тестирования
Это может быть сделано проверка этих кодовых баз в разных папках: базовый код может быть извлечен в корневую папку, а PR — в другую папку. В этом случае мы выполнили бы сборку и тестовый скрипт из корневой папки с кодом, помещенным в новую папку.
Конечно, это простое решение! Но в целях обучения я хотел бы представить довольно интересный вариант (…)
GitHub рабочий процесс_запуск триггерное событие
Кроме того pull_request_target, GitHub предоставляет еще одно событие-триггер: рабочий процесс_запуск. Это мероприятие позволяет выполнение pipeline обусловленный другим pipelineисполнение.
рабочий процесс_запуск и pull_request_target Триггеры похожи в одном аспекте: оба будут выполняться в привилегированном режиме и, несмотря на доработки ПР, база pipeline будет казнён!!
Давайте посмотрим на наше нынешнее pipeline:
name: PR TARGET CI
on:
pull_request_target:
branches: [ main ]
env:
MY_SECRET: ${{ secrets.MY_SECRET }}
jobs:
prt_build_test_and_merge:
runs-on: ubuntu-latest
steps:
# checkout PR code
- name: Checkout repository
uses: actions/checkout@v4
with:
# This is to get the PR code instead of the repo code
ref: ${{ github.event.pull_request.head.sha }}
# Simulation of a compilation
- name: Building ...
run: |
mkdir ./bin
touch ./bin/mybin.exe
ls -lR
# Simulation of running tests
- name: Running tests ...
id : run_tests
run: |
echo Running tests..
chmod +x runtests.sh
./runtests.sh
echo Tests executed.
#
# Let’s omit the check conditions at this moment …
#
- name: pr_check_conditions_to_merge
[...]
Раздел сборки безопасен для D-PPE, но раздел тестирования по-прежнему уязвим для I-PPE.
pipeline сам по себе безопасен для D-PPE из-за pull_request_target курок. Но этап тестирования по-прежнему уязвим для I-PPE из-за вызова внешнего сценария оболочки.
Избегание I-PPE
Цель вышеизложенного pipeline заключается в создании и тестировании предоставленного кода, безопасном для средств индивидуальной защиты.
Итак .. Почему бы не разделить pipeline на двоих? Один для сборки, другой для тестирования...
- 1-й pipeline (Построить CI) было бы проверить PR-код (для его создания), выполните сборку и сгенерируйте артефакт.
- 2nd pipeline (Тестовый CI) было бы проверить базовый код (чтобы избежать модификации сценария оболочки) и выполнить исходные сценарии для артефакта.
- Синхронизация тестового ЭК pipeline запускать ПОСЛЕ сборки CI pipelineмы будем использовать рабочий процесс_запуск вызывать.
Этим способом:
- pipeline Построить CI is безопасный как для Д-СИЗ (из-за pull_request_target) и расширение I-СИЗ (потому что он больше не выполняет сценарий оболочки).
- pipeline Тестовый CI Также безопасный как для Д-СИЗ (из-за рабочий процесс_запуск) и расширение I-СИЗ (потому что он проверяет базовый код, чтобы получить исходный сценарий оболочки)
Давайте посмотрим код обоих pipelines согласно этим модификациям…
1 pipeline (Сборка CI):
name: Build CI
on:
pull_request_target:
branches: [ main ]
env:
MY_SECRET: ${{ secrets.MY_SECRET }}
GITHUB_PAT: ${{ secrets.GH_PAT }}
jobs:
prt_build_and_upload:
runs-on: ubuntu-latest
steps:
- name: Checking out PR code
uses: actions/checkout@v4
if: ${{ github.event_name == 'pull_request_target' }}
with:
# This is to get the PR code instead of the repo code
ref: ${{ github.event.pull_request.head.sha }}
- name: Building ...
run: |
mkdir ./bin
touch ./bin/mybin.exe
# Save some PR info for later use by the 2nd pipeline
echo "${{github.event.pull_request.title}}" > ./bin/PR_TITLE.txt
echo "${{github.event.number}}" > ./bin/PR_ID.txt
# Upload the binary as a pipeline artifact
- name: Archive building artifacts
uses: actions/upload-artifact@v3
with:
name: archive-bin
path: |
bin
2 pipeline (Тестовый CI):
ame: Test CI
on:
workflow_run:
workflows: [ 'PR TARGET CI' ]
types: [completed]
env:
MY_SECRET: ${{ secrets.MY_SECRET }}
GITHUB_PAT: ${{ secrets.GH_PAT }}
jobs:
deploy:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
# By default, checks out base code (not PR code)
- name: Checkout repository
uses: actions/checkout@v4
# Download the artifact
- name: 'Download artifact'
uses: actions/github-script@v6
with:
script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name == "archive-bin"
})[0];
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
let fs = require('fs');
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/myartifact.zip`, Buffer.from(download.data));
# Unzip the artifact
- name: 'Unzip artifact'
run: |
unzip -o myartifact.zip
# Runs tests
- name: Running tests ...
id : run_tests
run: |
echo Running tests..
chmod +x runtests.sh
./runtests.sh
echo Tests executed.
#
# Let’s omit the check conditions at this moment …
#
- name: pr_check_conditions_to_merge
[...]
Вау… хорошее решение!! Но….. Мы в безопасности? Боюсь, что нет 😭
Действительно, мы ввели новую уязвимость!! Который из? Это станет темой нашего следующего поста 🙂… Оставайтесь с нами!!
PS: Извините, не могу молчать 🤐 ..Вы слышали о Отравление артефактом ? 😂





