Gh Actions - Context Script Injections

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks

Zrozumienie ryzyka

GitHub Actions renderuje wyrażenia ${{ … }} zanim krok się wykona. Wartość po renderowaniu jest wklejana do programu kroku (dla kroków z run:, skrypt shell). Jeśli interpolujesz niezaufane dane bezpośrednio w run:, atakujący kontroluje część programu shell i może wykonać dowolne polecenia.

Dokumentacja: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions and contexts/functions: https://docs.github.com/en/actions/learn-github-actions/contexts

Kluczowe punkty:

  • Renderowanie odbywa się przed wykonaniem. Skrypt z run: jest wygenerowany z wszystkimi rozwiązanymi wyrażeniami, a następnie wykonany przez shell.
  • Wiele contexts zawiera pola kontrolowane przez użytkownika w zależności od zdarzenia wyzwalającego (issues, PRs, comments, discussions, forks, stars, etc.). Zobacz untrusted input reference: https://securitylab.github.com/resources/github-actions-untrusted-input/
  • Cytowanie w shellu wewnątrz run: nie jest niezawodną obroną, ponieważ wstrzyknięcie ma miejsce na etapie renderowania szablonu. Atakujący mogą wyłamać się z cytatów lub wstrzyknąć operatory za pomocą spreparowanego inputu.

Wrażliwy wzorzec → RCE na runnerze

Wrażliwy workflow (wyzwalany, gdy ktoś otwiera nowe issue):

name: New Issue Created
on:
issues:
types: [opened]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: New issue
run: |
echo "New issue ${{ github.event.issue.title }} created"
- name: Add "new" label to issue
uses: actions-ecosystem/action-add-labels@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
labels: new

Jeśli atakujący otworzy issue zatytułowane $(id), wyrenderowany krok staje się:

echo "New issue $(id) created"

Substytucja polecenia uruchamia id na runnerze. Przykładowe wyjście:

New issue uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),100(users),999(systemd-journal) created

Dlaczego cytowanie nie wystarczy:

  • Wyrażenia są najpierw renderowane, a następnie uruchamiany jest otrzymany skrypt. Jeśli niezaufana wartość zawiera $(…), ;, "/' lub znaki nowej linii, może zmienić strukturę programu pomimo twojego cytowania.

Bezpieczny wzorzec (shell variables via env)

Poprawne zabezpieczenie: skopiuj niezaufane dane wejściowe do zmiennej środowiskowej, a następnie użyj natywnego rozwinięcia shella ($VAR) w skrypcie run. Nie osadzaj ponownie za pomocą ${{ … }} wewnątrz polecenia.

# safe
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: New issue
env:
TITLE: ${{ github.event.issue.title }}
run: |
echo "New issue $TITLE created"

Uwagi:

  • Unikaj używania ${{ env.TITLE }} inside run:. To ponownie wprowadza renderowanie szablonów do polecenia i powoduje to samo ryzyko wstrzyknięcia.
  • Prefer passing untrusted inputs via env: mapping and reference them with $VAR in run:.

Powierzchnie wyzwalane przez użytkowników (traktuj jako niezaufane)

Accounts with only read permission on public repositories can still trigger many events. Any field in contexts derived from these events must be considered attacker-controlled unless proven otherwise. Przykłady:

  • issues, issue_comment
  • discussion, discussion_comment (organizacje mogą ograniczać dyskusje)
  • pull_request, pull_request_review, pull_request_review_comment
  • pull_request_target (niebezpieczne przy niewłaściwym użyciu — uruchamia się w kontekście base repo)
  • fork (każdy może sforkować publiczne repozytoria)
  • watch (gwiazdkowanie repozytorium)
  • Indirectly via workflow_run/workflow_call chains

Które konkretne pola są kontrolowane przez atakującego zależy od zdarzenia. Zapoznaj się z przewodnikiem GitHub Security Lab po niezaufanych wejściach: https://securitylab.github.com/resources/github-actions-untrusted-input/

Praktyczne wskazówki

  • Minimalizuj użycie wyrażeń wewnątrz run:. Preferuj mapowanie env: i odniesienia przez $VAR.
  • Jeśli musisz przekształcić dane wejściowe, rób to w shellu używając bezpiecznych narzędzi (printf %q, jq -r itp.), zaczynając nadal od zmiennej shellowej.
  • Zachowaj szczególną ostrożność przy interpolowaniu branch names, PR titles, usernames, labels, discussion titles oraz PR head refs do skryptów, opcji wiersza poleceń lub ścieżek plików.
  • Dla reusable workflows i composite actions stosuj ten sam wzorzec: mapuj do env, a następnie odwołuj się przez $VAR.

Referencje

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks