envenenado-pipeline-execução-II

A Deep Veja maisto CI/CD Pipelines Vulnerabilidades (II): Envenenamento Indireto Pipeline Execução (I-PPE)

Em nossa postagem anterior, vimos como detectar e proteger contra envenenamento direto Pipeline Execução (D-PPE). Também vimos como detectar essa vulnerabilidade usando Scanner Xygeni, bem como alguns mecanismos de proteção. 

 Envenenado Pipeline Execução (EPP) é produzido quando o invasor pode modificar o pipeline lógica de duas maneiras:

  • Modificando o arquivo de configuração do CI (o pipeline) -> EPI direto (D-PPE)
  • Ao modificar os arquivos referenciados pelo pipeline (por exemplo: scripts referenciados dentro do pipeline arquivo de configuração) -> EPI indireto (EPI-I)
pp2

Neste post, vamos nos aprofundar no Veja maisto Indirect PPE. Mas, antes disso, e como complemento ao meu post anterior, vamos ver primeiro como o GitHub gerencia a execução de pipelinese e quais são os mecanismos de proteção contra D-PPE.

Como o GitHub protege a execução de pipelineestá vindo de relações públicas?

Como funciona o GitHub em relação à execução de modificados pipelines?

Modificado pipelines podem vir de Pushes ou Pull Requests (RP). Como uma prática recomendada importante, é altamente recomendável evitar qualquer “push” direto para um branch protegido e usar Pull Requests como um mecanismo para impor alguma revisão antes de aceitar qualquer código contribuído. 

Pull Requests pode chegar de duas fontes diferentes:

  • PRs vindos de forks
  • PRs vindos de ramos

RP de forks pode vir de público or investidores privados repositórios.

Como estamos tratando de EPI (Envenenado Pipeline Execução), nosso ponto principal não é a “aceitação” de um PR, mas a execução de um projeto modificado pipeline durante o processo de aceitação/aprovação do PR. No centro de um ataque PPE, há uma execução não intencional de um ataque modificado “malicioso”. pipeline. 

Em poucas palavras, envenenado Pipeline A execução (EPI) é produzida quando o invasor pode modificar o pipeline lógica.

Há dois variantes:

  • EPI direto (D-EPI): Em um cenário D-PPE, o invasor modifica o arquivo de configuração do CI em um repositório ao qual eles têm acesso, seja enviando a alteração diretamente para uma ramificação remota desprotegida no repositório ou enviando um PR com a alteração de uma ramificação ou bifurcação. Desde o CI pipeline a execução for definida pelos comandos no arquivo de configuração do CI modificado, os comandos maliciosos do invasor serão executados no nó de compilação assim que a compilação pipeline é acionado.
  • EPI indireto (I-EPI): Em certos casos, a possibilidade de D-PPE não está disponível para um adversário com acesso a um SCM repositório (por exemplo, se o pipeline está configurado para extrair o arquivo de configuração do CI de uma ramificação separada e protegida no mesmo repositório). Nesse cenário, em vez de envenenar o pipeline em si, um invasor injeta código malicioso em arquivos referenciados pelo pipeline (por exemplo: scripts referenciados dentro do pipeline arquivo de configuração)

Em ambos os casos, GitHub executará o modificado pipeline sem necessidade de revisão ou aprovação prévia.

PRs de garfos em diante público repos

GitHub permite configurar o comportamento durante o processamento PRs provenientes de bifurcações em repositórios públicos.

Quando um PR vem de uma bifurcação, o GitHub sempre força algum nível de “aprovação” antes de executar o pipeline associado ao PR. Este nível de aprovação varia de uma aprovação fraca a uma aprovação estrita.

At Nível organizacional (Org>>Configurações>>Ações>>Geral), você pode decidir entre várias opções de “aprovação”:

ppe3

O mais rigoroso é o último (“Exigir aprovação de todos os colaboradores externos”) porque o GitHub sempre exigirá aprovação quando o PR vier de forks de colaboradores externos. 

Mas mesmo neste caso estrito, existem diferenças entre colaboradores com permissões de leitura e gravação.

  • Quando o PR vem de um ler usuário, o execução do pipeline está parado até que haja aprovação das alterações. Se a aprovação estiver correta, então o modificado pipeline É executado. 
  • Quando o PR vem de um escrever usuário, o aprovação não é necessária e o modificado pipeline é sempre executado !! 
pp4

Concluindo, os PRs provenientes de bifurcações em repositórios públicos são levemente protegidos contra EPI. Há alguma proteção contra usuários externos (leitura), mas nada relacionado a usuários internos (gravação).

Sobre o quê PRs provenientes de forks de repositórios privados?

PRs de garfos em diante investidores privados repos

Nesse cenário, o GitHub fornece algumas definições de configuração úteis.

ppe9

As configurações acima podem ser definidas em Org ou em Repo nível.

Ao nenhuma opção está marcada, o GitHub irá pedir aprovação e não executará o modificado pipeline. Esta é a configuração mais segura!!

O processo de configuração mais insegura é quando "Executar fluxos de trabalho a partir do fork pull request" está checado. Neste caso, o mesmo para usuários de leitura e gravação, o Github executará automaticamente o modificado pipeline!! E esta situação pode ser ainda pior E se "Enviar tokens de gravação para fluxos de trabalho do fork pull requestseEnviar segredos e variáveis ​​para fluxos de trabalho do fork pull requests” são verificados. Não faça isso a menos que seja claramente justificado!!

E se "Exigir aprovação para bifurcação pull request fluxos de trabalho”está marcado, a situação acima é um pouco melhorada: o GitHub solicitará aprovação e não executará o modificado pipeline para o usuário de leitura, mas ainda o executará para um usuário de gravação.

ppe6

Forks vistos, e quanto PRs vindos de filiais?

RP de ramos

Para proteger este cenário você deve confiar em Regras de proteção de filiais

No nível do repositório, você pode criar regras de proteção de ramificação para qualquer ramificação. Estas regras acrescentam alguns restrições à modificação de ramificações protegidas.

Embora você configure uma regra para “Exigir um pull request antes de fundireExigir aprovações" o modificado pipeline será executado automaticamente após a criação do PR.A “aprovação” só se aplicará à ação de mesclagem.

ppe7

E quanto ao envenenamento indireto Pipeline Execução

Como vimos acima, o D-PPE pode ser mitigado usando pull_request_target, Mas não se aplica ao EPI.

Se você usar pull_request_target, o checkout padrão será o código base. Mas se você quiser validar algumas verificações no código contribuído (código PR), você precisa verificar explicitamente o código PR. Portanto, se o código PR modificou qualquer script de shell invocado pelo pipeline, a “base” (segura) pipeline irá invocar o shell script “modificado” → EPI indireto!!

A solução para isso é um pouco mais complicada (não existe uma solução mágica como pull_request_target). 

Nossa pipeline agora é seguro para D-PPE porque estamos usando pull_request_target. Mas ainda é vulnerável ao I-PPE. 

Em nosso exemplo de teste, precisamos basicamente verificar o código PR para fazer a construção, mas os testes são executados no artefato gerado pela construção. 

Então .. por que não verifica ambas as bases de código? 

  • Confira o código PR porque é o código contribuído que queremos construir e testar
  • Confira o código base para executar a versão original do pipeline e os scripts de construção/testes 

Isto pode ser feito por verificando essas bases de código em pastas diferentes: o código base pode ser retirado para a pasta raiz e o PR para uma pasta diferente. Nesse caso, executaríamos o build e o script de teste da pasta raiz em relação ao código colocado na nova pasta.

Esta é uma solução fácil, claro!! Mas, para efeitos de aprendizagem, gostaria de introduzir uma variante bastante interessante (…) 

GitHub fluxo de trabalho_executar evento desencadeador

Além de pull_request_target, o GitHub fornece outro evento de gatilho: fluxo de trabalho_executar. Este evento permite execução de um pipeline condicionado a outro pipelineexecução

fluxo de trabalho_executar e pull_request_target os gatilhos são semelhantes em um aspecto: ambos serão executados em modo privilegiado e, apesar das modificações de PR, a base pipeline será executado !! 

Vamos ver nosso atual 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
        [...]

A seção de construção é segura para D-PPE, mas a seção de teste ainda é vulnerável ao I-PPE.

O processo de pipeline em si é seguro para D-PPE devido ao pull_request_target acionar. Mas a etapa de teste ainda é vulnerável ao I-PPE devido à invocação de um script de shell externo.

Evitando EPI 

O objetivo do acima pipeline é construir e testar o código contribuído, sendo seguro para o EPI. 

Então .. Por que não dividir o pipeline em dois ? Um para construção e outro para teste..

  • O 1st pipeline (Construir IC) gostaria verifique o código PR (para construí-lo), faça a construção e gere um artefato.
  • O 2nd pipeline (Testar IC) gostaria verifique o código base (para evitar modificação do shell script) e execute os scripts originais no artefato. 
  • Para sincronizar o IC de teste pipeline para executar DEPOIS do Build CI pipeline, usaremos o fluxo de trabalho_executar desencadear. 
ppe8

Desta maneira:

  • pipeline Construir IC is segura para ambos D-EPI (devido a pull_request_target) e I-EPI (porque não executa mais o shell script).
  • pipeline Testar IC É também segura para ambos D-EPI (devido a fluxo de trabalho_executar) e I-EPI (porque verifica o código base para obter o script de shell original) 

Vamos ver o código de ambos pipelineestá de acordo com essas modificações…

1st pipeline (Construir 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

2nd pipeline (Teste IC):

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
        [...]

Uau… boa solução!! Mas….. Estamos seguros? Receio que não 😭

Na verdade, introduzimos uma nova vulnerabilidade!! Qual deles? Esse será o assunto do nosso próximo post 🙂… Fique ligado!! 

PS: Desculpe, não consigo ficar quieto 🤐 ..Você já ouviu falar sobre Envenenamento por artefato ? 😂

Envenenamento por Artefatos e Injeção de Código

A Deep Veja maisto CI/CD Pipelines Vulnerabilidades (III)​

Proteção contra envenenamento por artefatos por meio de atestados de software

A Deep Veja maisto CI/CD Pipelines Vulnerabilidades (IV)​

Envenenado Pipeline Execução (EPI)

A Deep Veja maisto CI/CD Pipelines Vulnerabilidades (I)​
sca-tools-software-composição-análise-ferramentas
Priorize, corrija e proteja seus riscos de software
você recebe uma avaliação gratuita de 7 dias da nossa licença Business Edition e pode aproveitar alguns dos recursos avançados da plataforma SecurityScorecard.
Não é necessário cartão de crédito

Proteja seu desenvolvimento e entrega de software

com o Suíte de Produtos da Xygeni