avvelenato-pipeline-esecuzione-II

Un tuffo profondo CI/CD Pipelines Vulnerabilità (II): Avvelenamento indiretto Pipeline Esecuzione (I-PPE)

Nel nostro post precedente, abbiamo visto come individuare e proteggersi dall'avvelenamento diretto Pipeline Esecuzione (D-PPE). Abbiamo anche visto come rilevare tale vulnerabilità utilizzando Scanner Xygeni, nonché alcuni meccanismi di protezione. 

 Avvelenato Pipeline Esecuzione (DPI) viene prodotto quando l'utente malintenzionato può modificare il file pipeline logica in due modi:

  • Modificando il file di configurazione CI (the pipeline) -> DPI diretti (D-PPE)
  • Modificando i file a cui fa riferimento il file pipeline (ad esempio: script a cui si fa riferimento all'interno del file pipeline file di configurazione) -> DPI indiretti (I-PPE)
pp2

In questo post approfondiremo i DPI indiretti. Ma prima di ciò, e come complemento al mio post precedente, vediamo prima come GitHub gestisce l'esecuzione di pipelines e quali sono i meccanismi di protezione contro i D-PPE.

In che modo GitHub protegge l'esecuzione di pipelineviene dai PR?

Come funziona GitHub per quanto riguarda l'esecuzione di modification pipelines?

Modificata pipelines può provenire da Spinte o Pull Requests (PR). Come buona pratica, si consiglia vivamente di evitare qualsiasi "push" diretto a un ramo protetto e di utilizzare Pull Requests come meccanismo per imporre una revisione prima di accettare qualsiasi codice contribuito. 

Pull Requests può provenire da due fonti diverse:

  • PR provenienti da forchette
  • PR provenienti da rami

PR da forchette può provenire da entrambi la percezione or tour privati repository.

Poiché si tratta di DPI (Poisoned Pipeline Esecuzione), il nostro punto principale non è “l'accettazione” di un PR ma l'esecuzione di una modifica pipeline durante il processo di accettazione/approvazione del PR. Al centro di un attacco PPE c’è l’esecuzione involontaria di una modifica “dannosa”. pipeline. 

In poche parole, Avvelenato Pipeline L'esecuzione (DPI) viene prodotta quando l'attaccante può modificare il file pipeline logica.

Ci sono due varianti:

  • DPI diretti (D-PPE): In uno scenario D-PPE, l'aggressore modifica il file di configurazione CI in un repository a cui hanno accesso, inviando la modifica direttamente a un ramo remoto non protetto sul repository o inviando un PR con la modifica da un ramo o un fork. Dal momento che il CI pipeline l'esecuzione è definita dai comandi nel file di configurazione CI modificato, i comandi dannosi dell'aggressore vengono infine eseguiti nel nodo di build una volta completata la build pipeline E 'attivato.
  • DPI indiretti (I-PPE): In alcuni casi, la possibilità di D-PPE non è disponibile per un avversario con accesso a un SCM repository (ad esempio se il pipeline è configurato per estrarre il file di configurazione CI da un ramo separato e protetto nello stesso repository). In uno scenario del genere, invece di avvelenare il pipeline stesso, un utente malintenzionato inserisce codice dannoso nei file a cui fa riferimento il file pipeline (ad esempio: script a cui si fa riferimento all'interno del file pipeline file di configurazione)

In entrambi i casi, GitHub eseguirà il file modificato pipeline senza necessità di revisione o approvazione preventiva.

PR dalle fork in poi la percezione pronti contro termine

GitHub consente di configurare il comportamento durante l'elaborazione PR provenienti da fork nei repository pubblici.

Quando un PR proviene da un fork, GitHub impone sempre un certo livello di "approvazione" prima di eseguire il pipeline associato al PR. Questo livello di approvazione passa da un’approvazione debole a un’approvazione rigorosa.

At Livello di organizzazione (Org>>Impostazioni>>Azioni>>Generale), puoi decidere tra diverse opzioni di "approvazione":

ppe3

Il più severo è l’ultimo (“Richiedere l'approvazione di tutti i collaboratori esterni”) perché GitHub richiederà sempre l'approvazione quando il PR proviene da fork di collaboratori esterni. 

Ma anche in questo caso rigoroso, ci sono differenze tra collaboratori con permessi di lettura e scrittura.

  • Quando il PR viene da a read utente, il esecuzione del pipeline è FERMATO fino all'approvazione delle modifiche. Se l'approvazione è ok, allora la modifica pipeline viene eseguito. 
  • Quando il PR viene da a scrivere utente, il l'approvazione non è necessaria e la modificata pipeline viene sempre eseguito!! 
pp4

In conclusione, i PR provenienti da fork su repository pubblici sono leggermente protetti dai PPE. Esiste una certa protezione contro gli utenti esterni (di lettura), ma nulla relativo agli utenti interni (di scrittura).

Che dire PR provenienti da fork di repository privati?

PR dalle fork in poi tour privati pronti contro termine

In questo scenario, GitHub fornisce alcune utili impostazioni di configurazione.

ppe9

Le impostazioni di cui sopra possono essere configurate su Org o repo livello.

Quando nessuna opzione è selezionata, GitHub lo farà chiedere l'approvazione and non eseguirà la modifica pipeline. Questa è la configurazione più sicura!!

Migliori configurazione non sicura è quando "Esegui flussi di lavoro da fork pull request" è selezionato. In questo caso, lo stesso sia per gli utenti di lettura che di scrittura, Github eseguirà automaticamente la modifica pipeline!! E questa situazione può essere uniforme peggio Se "Invia token di scrittura ai flussi di lavoro dal fork pull requests" e "Invia segreti e variabili ai flussi di lavoro da fork pull requests" sono controllati. Non farlo se non chiaramente giustificato!!

Se "Richiedere l'approvazione per la forcella pull request flussi di lavoro" è selezionato, la situazione di cui sopra è in qualche modo migliorata: GitHub chiederà l'approvazione e non eseguirà la modifica pipeline per l'utente di lettura, ma lo eseguirà comunque per un utente di scrittura.

ppe6

Forchette viste, che ne dici? PR provenienti dalle filiali?

PR da rami

Per proteggere questo scenario devi fare affidamento Norme di tutela delle filiali

A livello di repository, puoi creare regole di protezione del ramo per qualsiasi ramo. Queste regole ne aggiungono alcuni vincoli alla modifica dei rami protetti.

Anche se configuri una regola su "Richiedi un pull request prima di fondersi" e "Richiedere approvazioni", il modificato pipeline verrà eseguito automaticamente al momento della creazione della PR.L'“approvazione” si applicherà solo all'azione di fusione.

ppe7

Che dire dell'avvelenamento indiretto? Pipeline

Come abbiamo visto sopra, i D-PPE possono essere mitigati utilizzando pull_request_target, Ma non si applica agli I-PPE.

Se utilizzi pull_request_target, il checkout predefinito sarà il codice base. Ma se vuoi convalidare alcuni controlli sul codice contribuito (codice PR) devi verificare esplicitamente il codice PR. Pertanto, se il codice PR ha modificato qualsiasi script di shell richiamato dal file pipeline, la “base” (sicura) pipeline invocherà lo script di shell “modificato” → PPE indiretto!!

La soluzione a questo è un po' più complicata (non esiste una bacchetta magica come pull_request_target). 

pipeline ora è sicuro per D-PPE perché stiamo utilizzando pull_request_target. Ma è ancora vulnerabile all’I-PPE. 

Nel nostro esempio di test, dobbiamo controllare il codice PR fondamentalmente per realizzare la build, ma i test vengono eseguiti sull'artefatto generato dalla build. 

Quindi .. perché non controllare entrambe le codebase? 

  • Acquista il codice PR perché è il codice contribuito ciò che vogliamo costruire e testare
  • Codice Checkout Base per eseguire la versione originale di pipeline e gli script di build/test 

Questo potrebbe essere fatto da controllando quelle basi di codice in cartelle diverse: il codice di base potrebbe essere estratto nella cartella principale e il PR in una cartella diversa. In questo caso eseguiremmo la build e lo script di test dalla cartella principale rispetto al codice inserito nella nuova cartella.

Questa è una soluzione semplice, ovviamente!! Ma, a scopo didattico, vorrei introdurre una variante piuttosto interessante (…) 

GitHub flusso di lavoro_esegui evento scatenante

Oltre a pull_request_target, GitHub fornisce un altro evento trigger: flusso di lavoro_esegui. Questo evento lo consente esecuzione di a pipeline condizionato ad un altro pipelinel'esecuzione

flusso di lavoro_esegui and pull_request_target i trigger sono simili sotto un aspetto: entrambi verranno eseguiti in modalità privilegiata e, nonostante le modifiche PR, la base pipeline verrà giustiziato!! 

Vediamo la nostra attuale 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
        [...]

La sezione di costruzione è sicura per il D-PPE, ma la sezione di test è ancora vulnerabile all'I-PPE.

Migliori pipeline di per sé è sicuro per i D-PPE a causa del pull_request_target grilletto. Ma la fase di test è ancora vulnerabile all'I-PPE a causa del richiamo di uno script di shell esterno.

Evitare gli I-PPE 

Lo scopo di cui sopra pipeline è costruire e testare il codice contribuito, essendo sicuro per PPE. 

Quindi .. Perché non dividere il pipeline in due? Uno per costruire e un altro per testare..

  • il 1st pipeline (Costruisci CI) voluto controlla il codice PR (per costruirlo), crea la build e genera un artefatto.
  • L'2nd pipeline (Prova CI) voluto controlla il codice Base (per evitare la modifica dello script di shell) ed eseguire gli script originali sull'artefatto. 
  • Per sincronizzare il test CI pipeline da eseguire DOPO la build CI pipeline, useremo il flusso di lavoro_esegui grilletto. 
ppe8

In questo modo:

  • pipeline Costruisci CI is sicura A entrambi D-PPE (a causa di pull_request_target) e I-PPE (perché non esegue più lo script di shell).
  • pipeline Prova CI è altresì sicura A entrambi D-PPE (a causa di flusso di lavoro_esegui) e I-PPE (perché controlla il codice di base per ottenere lo script di shell originale) 

Vediamo il codice di entrambi pipelines secondo queste modifiche...

1st pipeline (Costruisci 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 (Test 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
        [...]

Wow... bella soluzione!! Ma….. Siamo al sicuro? Temo di no 😭

Infatti, abbiamo introdotto una nuova vulnerabilità!! Quale? Questo sarà l'argomento del nostro prossimo post 🙂 … Restate sintonizzati!! 

PS: Scusa, non riesco a stare zitto 🤐 ..ne hai sentito parlare Avvelenamento da artefatto ? 😂

Avvelenamento di artefatti e iniezione di codice

Un tuffo profondo CI/CD Pipelines Vulnerabilità (III)​

Protezione contro l'avvelenamento degli artefatti tramite attestazioni software

Un tuffo profondo CI/CD Pipelines Vulnerabilità (IV)​

Avvelenato Pipeline Esecuzione (DPI)

Un tuffo profondo CI/CD Pipelines Vulnerabilità (I)​
sca-tools-software-strumenti-di-analisi-della-composizione
Dai priorità, risolvi e proteggi i rischi del tuo software
Prova gratuita 7-day
Nessuna carta di credito richiesta

Proteggi lo sviluppo e la consegna del tuo software

con la suite di prodotti Xygeni