# Az - Tokens & Public Applications

{{#include ../../../banners/hacktricks-training.md}}

## Basic Information

Entra ID è la piattaforma di gestione dell'identità e degli accessi (IAM) basata sul cloud di Microsoft, che funge da sistema fondamentale di autenticazione e autorizzazione per servizi come Microsoft 365 e Azure Resource Manager. Azure AD implementa il framework di autorizzazione OAuth 2.0 e il protocollo di autenticazione OpenID Connect (OIDC) per gestire l'accesso alle risorse.

### OAuth

**Partecipanti Chiave in OAuth 2.0:**

1. **Server delle Risorse (RS):** Protegge le risorse possedute dal proprietario delle risorse.
2. **Proprietario delle Risorse (RO):** Tipicamente un utente finale che possiede le risorse protette.
3. **Applicazione Client (CA):** Un'applicazione che cerca di accedere alle risorse per conto del proprietario delle risorse.
4. **Server di Autorizzazione (AS):** Emissione di token di accesso alle applicazioni client dopo averle autenticate e autorizzate.

**Scopes e Consenso:**

- **Scopes:** Permessi granulari definiti sul server delle risorse che specificano i livelli di accesso.
- **Consenso:** Il processo mediante il quale un proprietario delle risorse concede a un'applicazione client il permesso di accedere alle risorse con specifici scopes.

**Integrazione con Microsoft 365:**

- Microsoft 365 utilizza Azure AD per IAM ed è composto da più applicazioni OAuth "di prima parte".
- Queste applicazioni sono profondamente integrate e spesso hanno relazioni di servizio interdipendenti.
- Per semplificare l'esperienza dell'utente e mantenere la funzionalità, Microsoft concede "consenso implicito" o "pre-consenso" a queste applicazioni di prima parte.
- **Consenso Implicito:** Alcune applicazioni sono automaticamente **concesse accesso a specifici scopes senza approvazione esplicita dell'utente o dell'amministratore**.
- Questi scopes pre-consentiti sono tipicamente nascosti sia agli utenti che agli amministratori, rendendoli meno visibili nelle interfacce di gestione standard.

**Tipi di Applicazioni Client:**

1. **Client Riservati:**
- Possiedono le proprie credenziali (ad es., password o certificati).
- Possono **autenticarsi in modo sicuro** al server di autorizzazione.
2. **Client Pubblici:**
- Non hanno credenziali uniche.
- Non possono autenticarsi in modo sicuro al server di autorizzazione.
- **Implicazione di Sicurezza:** Un attaccante può impersonare un'applicazione client pubblica quando richiede token, poiché non esiste un meccanismo per il server di autorizzazione per verificare la legittimità dell'applicazione.

## Authentication Tokens

Ci sono **tre tipi di token** utilizzati in OIDC:

- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** Il client presenta questo token al server delle risorse per **accedere alle risorse**. Può essere utilizzato solo per una specifica combinazione di utente, client e risorsa e **non può essere revocato** fino alla scadenza - che è di 1 ora per impostazione predefinita.
- **ID Tokens**: Il client riceve questo **token dal server di autorizzazione**. Contiene informazioni di base sull'utente. È **legato a una specifica combinazione di utente e client**.
- **Refresh Tokens**: Forniti al client con il token di accesso. Utilizzati per **ottenere nuovi token di accesso e ID**. È legato a una specifica combinazione di utente e client e può essere revocato. La scadenza predefinita è di **90 giorni** per i refresh token inattivi e **nessuna scadenza per i token attivi** (da un refresh token è possibile ottenere nuovi refresh token).
- Un refresh token dovrebbe essere legato a un **`aud`**, a degli **scopes**, e a un **tenant** e dovrebbe poter generare solo token di accesso per quel aud, scopes (e non di più) e tenant. Tuttavia, questo non è il caso con i **token delle applicazioni FOCI**.
- Un refresh token è crittografato e solo Microsoft può decrittografarlo.
- Ottenere un nuovo refresh token non revoca il refresh token precedente.

> [!WARNING]
> Le informazioni per **l'accesso condizionale** sono **memorizzate** all'interno del **JWT**. Quindi, se richiedi il **token da un indirizzo IP consentito**, quell'**IP** sarà **memorizzato** nel token e poi puoi utilizzare quel token da un **IP non consentito per accedere alle risorse**.

### Access Tokens "aud"

Il campo indicato nel campo "aud" è il **server delle risorse** (l'applicazione) utilizzato per eseguire il login.

Il comando `az account get-access-token --resource-type [...]` supporta i seguenti tipi e ciascuno di essi aggiungerà un "aud" specifico nel token di accesso risultante:

> [!CAUTION]
> Nota che i seguenti sono solo le API supportate da `az account get-access-token` ma ce ne sono di più.

<details>

<summary>aud examples</summary>

- **aad-graph (Azure Active Directory Graph API)**: Utilizzato per accedere all'API Azure AD Graph legacy (deprecata), che consente alle applicazioni di leggere e scrivere dati di directory in Azure Active Directory (Azure AD).
- `https://graph.windows.net/`

* **arm (Azure Resource Manager)**: Utilizzato per gestire le risorse Azure tramite l'API Azure Resource Manager. Questo include operazioni come la creazione, l'aggiornamento e la cancellazione di risorse come macchine virtuali, account di archiviazione e altro.
- `https://management.core.windows.net/ or https://management.azure.com/`

- **batch (Azure Batch Services)**: Utilizzato per accedere ad Azure Batch, un servizio che consente applicazioni di calcolo parallelo e ad alte prestazioni su larga scala in modo efficiente nel cloud.
- `https://batch.core.windows.net/`

* **data-lake (Azure Data Lake Storage)**: Utilizzato per interagire con Azure Data Lake Storage Gen1, che è un servizio di archiviazione e analisi dei dati scalabile.
- `https://datalake.azure.net/`

- **media (Azure Media Services)**: Utilizzato per accedere ad Azure Media Services, che forniscono servizi di elaborazione e distribuzione multimediale basati sul cloud per contenuti video e audio.
- `https://rest.media.azure.net`

* **ms-graph (Microsoft Graph API)**: Utilizzato per accedere all'API Microsoft Graph, l'endpoint unificato per i dati dei servizi Microsoft 365. Consente di accedere a dati e informazioni da servizi come Azure AD, Office 365, Enterprise Mobility e servizi di sicurezza.
- `https://graph.microsoft.com`

- **oss-rdbms (Azure Open Source Relational Databases)**: Utilizzato per accedere ai servizi di database Azure per motori di database relazionali open-source come MySQL, PostgreSQL e MariaDB.
- `https://ossrdbms-aad.database.windows.net`

</details>

### Access Tokens Scopes "scp"

Lo scope di un token di accesso è memorizzato all'interno della chiave scp all'interno del JWT del token di accesso. Questi scopes definiscono a cosa ha accesso il token di accesso.

Se un JWT è autorizzato a contattare un'API specifica ma **non ha lo scope** per eseguire l'azione richiesta, **non sarà in grado di eseguire l'azione** con quel JWT.

### Get refresh & access token example
```python
# Code example from https://github.com/secureworks/family-of-client-ids-research
import msal
import requests
import jwt
from pprint import pprint
from typing import Any, Dict, List


# LOGIN VIA CODE FLOW AUTHENTICATION
azure_cli_client = msal.PublicClientApplication(
"04b07795-8ddb-461a-bbee-02f9e1bf7b46" # ID for Azure CLI client
)
device_flow = azure_cli_client.initiate_device_flow(
scopes=["https://graph.microsoft.com/.default"]
)
print(device_flow["message"])

# Perform device code flow authentication

azure_cli_bearer_tokens_for_graph_api = azure_cli_client.acquire_token_by_device_flow(
device_flow
)
pprint(azure_cli_bearer_tokens_for_graph_api)


# DECODE JWT
def decode_jwt(base64_blob: str) -> Dict[str, Any]:
"""Decodes base64 encoded JWT blob"""
return jwt.decode(
base64_blob, options={"verify_signature": False, "verify_aud": False}
)
decoded_access_token = decode_jwt(
azure_cli_bearer_tokens_for_graph_api.get("access_token")
)
pprint(decoded_access_token)


# GET NEW ACCESS TOKEN AND REFRESH TOKEN
new_azure_cli_bearer_tokens_for_graph_api = (
# Same client as original authorization
azure_cli_client.acquire_token_by_refresh_token(
azure_cli_bearer_tokens_for_graph_api.get("refresh_token"),
# Same scopes as original authorization
scopes=["https://graph.microsoft.com/.default"],
)
)
pprint(new_azure_cli_bearer_tokens_for_graph_api)
```
### Altri campi del token di accesso

- **appid**: ID dell'applicazione utilizzato per generare il token
- **appidacr**: Il riferimento alla classe di contesto di autenticazione dell'applicazione indica come il client è stato autenticato; per un client pubblico il valore è 0, e se viene utilizzato un segreto del client il valore è 1
- **acr**: Il claim del riferimento alla classe di contesto di autenticazione è "0" quando l'autenticazione dell'utente finale non ha soddisfatto i requisiti di ISO/IEC 29115.
- **amr**: Il metodo di autenticazione indica come il token è stato autenticato. Un valore di “pwd” indica che è stata utilizzata una password.
- **groups**: Indica i gruppi di cui il principale è membro.
- **iss**: L'emittente identifica il servizio di token di sicurezza (STS) che ha generato il token. e.g. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (l'uuid è l'ID del tenant)
- **oid**: L'ID dell'oggetto del principale
- **tid**: ID del tenant
- **iat, nbf, exp**: Emesso il (quando è stato emesso), Non prima (non può essere utilizzato prima di questo tempo, di solito lo stesso valore di iat), Tempo di scadenza.

## Escalation dei privilegi dei token FOCI

In precedenza è stato menzionato che i token di aggiornamento dovrebbero essere legati agli **ambiti** con cui sono stati generati, all'**applicazione** e al **tenant** a cui sono stati generati. Se uno di questi confini viene infranto, è possibile aumentare i privilegi poiché sarà possibile generare token di accesso per altre risorse e tenant a cui l'utente ha accesso e con più ambiti di quanto fosse originariamente previsto.

Inoltre, **questo è possibile con tutti i token di aggiornamento** nella [Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/) (account Microsoft Entra, account personali Microsoft e account social come Facebook e Google) perché come menzionano i [**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens): "I token di aggiornamento sono legati a una combinazione di utente e client, ma **non sono legati a una risorsa o tenant**. Un client può utilizzare un token di aggiornamento per acquisire token di accesso **attraverso qualsiasi combinazione di risorsa e tenant** per cui ha il permesso di farlo. I token di aggiornamento sono crittografati e solo la Microsoft identity platform può leggerli."

Inoltre, nota che le applicazioni FOCI sono applicazioni pubbliche, quindi **non è necessario alcun segreto** per autenticarsi al server.

Poi i client FOCI noti riportati nella [**ricerca originale**](https://github.com/secureworks/family-of-client-ids-research/tree/main) possono essere [**trovati qui**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv).

### Ottenere un ambito diverso

Proseguendo con il codice di esempio precedente, in questo codice viene richiesto un nuovo token per un ambito diverso:
```python
# Code from https://github.com/secureworks/family-of-client-ids-research
azure_cli_bearer_tokens_for_outlook_api = (
# Same client as original authorization
azure_cli_client.acquire_token_by_refresh_token(
new_azure_cli_bearer_tokens_for_graph_api.get(
"refresh_token"
),
# But different scopes than original authorization
scopes=[
"https://outlook.office.com/.default"
],
)
)
pprint(azure_cli_bearer_tokens_for_outlook_api)
```
### Ottieni client e scope diversi
```python
# Code from https://github.com/secureworks/family-of-client-ids-research
microsoft_office_client = msal.PublicClientApplication("d3590ed6-52b3-4102-aeff-aad2292ab01c")
microsoft_office_bearer_tokens_for_graph_api = (
# This is a different client application than we used in the previous examples
microsoft_office_client.acquire_token_by_refresh_token(
# But we can use the refresh token issued to our original client application
azure_cli_bearer_tokens_for_outlook_api.get("refresh_token"),
# And request different scopes too
scopes=["https://graph.microsoft.com/.default"],
)
)
# How is this possible?
pprint(microsoft_office_bearer_tokens_for_graph_api)
```
## Dove trovare i token

Dal punto di vista di un attaccante, è molto interessante sapere dove è possibile trovare i token di accesso e di aggiornamento quando, ad esempio, il PC di una vittima è compromesso:

- Dentro **`<HOME>/.Azure`**
- **`azureProfile.json`** contiene informazioni sugli utenti connessi in passato
- **`clouds.config contiene`** informazioni sulle sottoscrizioni
- **`service_principal_entries.json`** contiene le credenziali delle applicazioni (tenant id, client e segreto). Solo in Linux e macOS
- **`msal_token_cache.json`** contiene token di accesso e token di aggiornamento. Solo in Linux e macOS
- **`service_principal_entries.bin`** e **`msal_token_cache.bin`** sono utilizzati in Windows e sono crittografati con DPAPI
- **`msal_http_cache.bin`** è una cache delle richieste HTTP
- Caricalo: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)`
- **`AzureRmContext.json`** contiene informazioni sui login precedenti utilizzando Az PowerShell (ma nessuna credenziale)
- Dentro **`C:\Users\<username>\AppData\Local\Microsoft\IdentityCache\*`** ci sono diversi file `.bin` con **token di accesso**, token ID e informazioni sugli account crittografati con il DPAPI degli utenti.
- È possibile trovare ulteriori **token di accesso** nei file `.tbres` dentro **`C:\Users\<username>\AppData\Local\Microsoft\TokenBroken\Cache\`** che contengono un base64 crittografato con DPAPI con token di accesso.
- In Linux e macOS puoi ottenere **token di accesso, token di aggiornamento e token ID** da Az PowerShell (se utilizzato) eseguendo `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"`
- In Windows questo genera solo token ID.
- È possibile vedere se Az PowerShell è stato utilizzato in Linux e macOS controllando se esiste `$HOME/.local/share/.IdentityService/` (anche se i file contenuti sono vuoti e inutili)
- Se l'utente è **connesso a Azure con il browser**, secondo questo [**post**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) è possibile avviare il flusso di autenticazione con un **reindirizzamento a localhost**, far autorizzare automaticamente il login dal browser e ricevere il token di aggiornamento. Nota che ci sono solo poche applicazioni FOCI che consentono il reindirizzamento a localhost (come az cli o il modulo PowerShell), quindi queste applicazioni devono essere autorizzate.

## Riferimenti

- [https://github.com/secureworks/family-of-client-ids-research](https://github.com/secureworks/family-of-client-ids-research)
- [https://github.com/Huachao/azure-content/blob/master/articles/active-directory/active-directory-token-and-claims.md](https://github.com/Huachao/azure-content/blob/master/articles/active-directory/active-directory-token-and-claims.md)

{{#include ../../../banners/hacktricks-training.md}}
