I vårt forrige innlegg, Vi så hvordan man oppdager og beskytter mot direkte forgiftning Pipeline Utførelse (D-PPE). Vi så også hvordan man oppdager denne sårbarheten ved hjelp av Xygeni-skanner, samt noen beskyttelsesmekanismer.
Forgiftet Pipeline Utførelse (PPE) produseres når angriperen kan endre pipeline logikk på en av to måter:
- Ved å endre CI-konfigurasjonsfilen (den pipeline) -> Direkte personlig verneutstyr (D-PPE)
- Ved å endre filer referert av pipeline (for eksempel: skript referert fra innsiden av pipeline konfigurasjonsfil) -> Indirekte personlig verneutstyr (I-PPE)

I dette innlegget skal vi dykke dypt ned i indirekte personlig verneutstyr. Men før det, og som et supplement til mitt forrige innlegg, la oss først se hvordan GitHub håndterer utførelsen av pipelines og hva er beskyttelsesmekanismene mot D-PPE.
Hvordan beskytter GitHub utførelsen av pipelinekommer det fra PR-er?
Hvordan fungerer GitHub når det gjelder utførelse av modifiserte pipelines?
Modifisert pipelines kan komme fra Pushes eller Pull Requests (PR). Som en viktig god praksis anbefales det sterkt å unngå direkte «push» til en beskyttet gren og bruke Pull Requests som en mekanisme for å fremtvinge en viss gjennomgang før aksept av bidragsyter kode.
Pull Requests kan komme fra to forskjellige kilder:
- PR-er som kommer fra gafler
- PR-er som kommer fra grener
PR-er fra gafler kan komme enten fra offentlig or privat depoter.
Siden vi har å gjøre med personlig verneutstyr (forgiftet) Pipeline Utførelse), er ikke hovedpoenget vårt «aksept» av en PR, men utførelsen av en modifisert pipeline under PRs aksept-/godkjenningsprosess. Kjernen i et PPE-angrep er en utilsiktet utførelse av en «ondsinnet» modifisert pipeline.
Med noen få ord, forgiftet Pipeline Henrettelse (PPE) produseres når angriperen kan endre pipeline logikk.
Det er to varianter:
- Direkte personlig verneutstyr (D-PPE): I et D-PPE-scenario, angriperen endrer CI-konfigurasjonsfilen i et repository de har tilgang til, enten ved å pushe endringen direkte til en ubeskyttet ekstern gren på repoet, eller ved å sende inn en PR med endringen fra en gren eller en fork. Siden CI pipeline Utførelsen er definert av kommandoene i den modifiserte CI-konfigurasjonsfilen. Angriperens ondsinnede kommandoer kjøres til slutt i byggenoden når byggeprosessen er fullført. pipeline utløses.
- Indirekte personlig verneutstyr (I-PVU): I visse tilfeller er muligheten for D-PPE ikke tilgjengelig for en motpart med tilgang til en SCM depotet (f.eks. hvis pipeline er konfigurert til å hente CI-konfigurasjonsfilen fra en separat, beskyttet gren i samme repository). I et slikt scenario, i stedet for å forgifte pipeline i seg selv injiserer en angriper skadelig kode i filer referert til av pipeline (for eksempel: skript referert fra innsiden av pipeline konfigurasjonsfil)
I begge tilfeller, GitHub vil kjøre den modifiserte pipeline uten behov for forutgående gjennomgang eller godkjenning.
PR-er fra gafler og videre offentlig repos
GitHub tillater konfigurering av oppførselen under behandling PR-er som kommer fra forks i offentlige reposer.
Når en PR kommer fra en fork, fremtvinger GitHub alltid et visst nivå av «godkjenning» før den utføres. pipeline knyttet til PR-enDette godkjenningsnivået veksler mellom svak og streng godkjenning.
At Organisasjonsnivå (Organisasjon>>Innstillinger>>Handlinger>>Generelt), kan du velge mellom flere alternativer for «godkjenning»:

Den strengeste er den siste («Krev godkjenning fra alle eksterne samarbeidspartnere”) fordi GitHub alltid vil kreve godkjenning når PR-en kommer fra forks fra eksterne samarbeidspartnere.
Men selv i dette strenge tilfellet finnes det forskjeller mellom samarbeidspartnere med lese- og skrivetillatelser.
- Når PR-en kommer fra en lese brukeren, den utførelse av pipeline er STOPPET inntil det foreligger en godkjenning av endringene. Hvis godkjenningen er ok, så vil den endrede pipeline er utført.
- Når PR-en kommer fra en skrive brukeren, den godkjenning er ikke nødvendig, og den endrede pipeline blir alltid utført!!

Som en konklusjon er PR-er som kommer fra forks på offentlige repositorier svakt beskyttet mot PPE. Det er noe beskyttelse mot eksterne (lesende) brukere, men ingenting relatert til interne (skrivende) brukere.
Hva med PR-er som kommer fra forks fra private reposer?
PR-er fra gafler og videre privat repos
I dette scenariet tilbyr GitHub noen nyttige konfigurasjonsinnstillinger.

Innstillingene ovenfor kan konfigureres enten på organ eller på repo nivå.
Når ingen alternativer er avkrysset, GitHub vil be om godkjenning og den vil ikke utføre den modifiserte pipelineDette er den sikreste konfigurasjonen!!
Ocuco den usikreste konfigurasjonen Er når "Kjør arbeidsflyter fra fork pull request«er avkryssetI dette tilfellet, det samme for både lese- og skrivebrukere, vil Github automatisk utføre den endrede pipelineOg denne situasjonen kan bli enda mer verre hvis «Send skrivetokener til arbeidsflyter fra fork pull requests"Og"Send hemmeligheter og variabler til arbeidsflyter fra fork pull requests" er avkrysset. Ikke gjør dette med mindre det er klart begrunnet!!
Hvis “Krev godkjenning for gaffel pull request arbeidsflyt" er avkrysset, forbedres situasjonen ovenfor noe: GitHub vil be om godkjenning og ikke utføre den endrede pipeline for lesebrukeren, men den vil fortsatt kjøre den for en skrivebruker.

Gafler sett, hva med PR-er fra filialer?
PR-er fra grener
For å beskytte deg mot dette scenariet må du stole på Regler for filialbeskyttelse.
På repositorinivå kan du opprette regler for grenbeskyttelse for enhver gren. Disse reglene legger til noen begrensninger for modifisering av beskyttede grener.
Selv om du konfigurerer en regel til å «Krev en pull request før sammenslåing"Og"Krev godkjenninger" den modifiserte pipeline vil bli automatisk utført ved opprettelse av PR«Godkjenningen» gjelder kun for sammenslåingen.

Hva med indirekte forgiftning Pipeline Gjennomføring
Som vi så ovenfor, kan D-PPE reduseres ved å bruke pull_request_target, men det gjelder ikke for personlig verneutstyr.
Hvis du bruker pull_request_target, vil standard utsjekking være basiskoden. Men hvis du vil validere noen kontroller på den bidratte koden (PR-kode), må du eksplisitt sjekke ut PR-koden. Derfor, hvis PR-koden har endret et skallskript som kalles av pipeline, «basen» (den trygge) pipeline vil kalle det «modifiserte» skallskriptet → Indirekte PPE!!
Løsningen på dette er litt mer komplisert (det finnes ikke en magisk løsning som pull_request_target).
Våre pipeline er nå trygt for D-PPE fordi vi bruker pull_request_target. Men det er fortsatt sårbart for I-PPE.
I testeksemplet vårt må vi i utgangspunktet sjekke ut PR-koden for å lage byggingen, men testene kjøres på artefakten som genereres av byggingen.
Så .. Hvorfor ikke sjekke ut begge kodebasene?
- PR-kode for kassen, fordi det er den bidragte koden vi ønsker å bygge og teste
- Checkout Base-kode for å kjøre den originale versjonen av pipeline og bygge-/testskriptene
Dette kan gjøres ved å sjekke ut disse kodebasene til forskjellige mapperBasiskoden kan bli sjekket ut til rotmappen, og PR-en til en annen mappe. I dette tilfellet ville vi kjøre byggingen og testskriptet fra rotmappen mot koden som er plassert i den nye mappen.
Dette er selvsagt en enkel løsning!! Men for læringsformål vil jeg gjerne introdusere en ganske interessant variant (…)
GitHub arbeidsflytkjøring utløsende hendelse
Foruten pull_request_target, GitHub tilbyr en annen utløserhendelse: arbeidsflytkjøringDenne hendelsen tillater utførelse av en pipeline betinget til en annen pipelinehenrettelsen.
arbeidsflytkjøring og pull_request_target utløsere er like på ett aspekt: begge vil bli utført i privilegert modus, og til tross for PR-endringene, basen pipeline vil bli henrettet!!
La oss se vår nåværende 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
[...]
Byggeseksjonen er trygg for D-PPE, men testseksjonen er fortsatt sårbar for I-PPE.
Ocuco pipeline i seg selv er trygt å bruke D-PPE på grunn av pull_request_target utløser. Men testtrinnet er fortsatt sårbart for I-PPE på grunn av påkalling av et eksternt skallskript.
Unngå personlig verneutstyr
Formålet med det ovennevnte pipeline er å bygge og teste den bidratte koden, samtidig som det er trygt å bruke personlig verneutstyr.
Så .. Hvorfor ikke splitte opp pipeline i to? En for bygging og en annen for testing..
- Den første pipeline (Bygg CI) ville sjekk PR-koden (for å bygge den), lag byggingen og generer en artefakt.
- Den 2ende pipeline (Test-CI) ville sjekk ut basiskoden (for å unngå modifikasjon av skallskript) og kjør de originale skriptene mot artefaktet.
- For å synkronisere test-CI pipeline å kjøre ETTER Build CI pipeline, vil vi bruke arbeidsflytkjøring avtrekker.

På denne måten:
- pipeline Bygg CI is trygge til begge D-PPE (på grunn av pull_request_target) Og I-PVU (fordi den ikke lenger kjører skallskriptet).
- pipeline Test-CI er også trygge til begge D-PPE (på grunn av arbeidsflytkjøring) Og I-PVU (fordi den sjekker basiskoden for å få det originale skallskriptet)
La oss se koden til begge pipelinei henhold til disse modifikasjonene …
1. pipeline (Bygge 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 (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 ... fin løsning!! Men ... Er vi trygge? Jeg er redd for at ikke 😭
Vi har faktisk introdusert en ny sårbarhet!! Hvilken? Dette blir temaet for vårt neste innlegg 🙂 … Følg med!!
PS: Beklager, jeg klarer ikke å tie stille 🤐 ..Har du hørt om Artefaktforgiftning ? 😂







