mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-28 22:51:09 -07:00
Translated ['', 'src/pentesting-cloud/azure-security/az-basic-informatio
This commit is contained in:
+160
-87
@@ -1,34 +1,34 @@
|
||||
# Az - Tokens & Public Applications
|
||||
# Az - Tokens y Aplicaciones Públicas
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Información básica
|
||||
## Información Básica
|
||||
|
||||
Entra ID es la plataforma de identidad y gestión de acceso (IAM) basada en la nube de Microsoft, que sirve como el sistema fundamental de autenticación y autorización para servicios como Microsoft 365 y Azure Resource Manager. Azure AD implementa el framework de autorización OAuth 2.0 y el protocolo de autenticación OpenID Connect (OIDC) para gestionar el acceso a recursos.
|
||||
Entra ID es la plataforma de gestión de identidad y acceso (IAM) en la nube de Microsoft, que sirve como el sistema fundamental de autenticación y autorización para servicios como Microsoft 365 y Azure Resource Manager. Azure AD implementa el marco de autorización OAuth 2.0 y el protocolo de autenticación OpenID Connect (OIDC) para gestionar el acceso a recursos.
|
||||
|
||||
### OAuth
|
||||
|
||||
**Participantes clave en OAuth 2.0:**
|
||||
|
||||
1. **Resource Server (RS):** Protege los recursos propiedad del resource owner.
|
||||
2. **Resource Owner (RO):** Típicamente un usuario final que posee los recursos protegidos.
|
||||
3. **Client Application (CA):** Una aplicación que busca acceso a recursos en nombre del resource owner.
|
||||
4. **Authorization Server (AS):** Emite access tokens a las client applications después de autenticarlas y autorizarlas.
|
||||
2. **Resource Owner (RO):** Normalmente un usuario final que posee los recursos protegidos.
|
||||
3. **Client Application (CA):** Una aplicación que busca acceder a recursos en nombre del resource owner.
|
||||
4. **Authorization Server (AS):** Emite access tokens a las aplicaciones cliente tras autenticarlas y autorizarlas.
|
||||
|
||||
**Scopes y consentimiento:**
|
||||
**Scopes y Consentimiento:**
|
||||
|
||||
- **Scopes:** Permisos granulares definidos en el resource server que especifican niveles de acceso.
|
||||
- **Consent:** El proceso por el cual un resource owner concede a una client application permiso para acceder a recursos con scopes específicos.
|
||||
- **Scopes:** Permisos granulares definidos en el resource server que especifican los niveles de acceso.
|
||||
- **Consent:** El proceso por el cual un resource owner otorga a una aplicación cliente permiso para acceder a recursos con scopes específicos.
|
||||
|
||||
**Integración con Microsoft 365:**
|
||||
|
||||
- Microsoft 365 utiliza Azure AD para IAM y está compuesto por múltiples aplicaciones OAuth "first-party".
|
||||
- Microsoft 365 utiliza Azure AD para IAM y está compuesto por múltiples aplicaciones "de primera parte" (first-party) de OAuth.
|
||||
- Estas aplicaciones están profundamente integradas y a menudo tienen relaciones de servicio interdependientes.
|
||||
- Para simplificar la experiencia del usuario y mantener la funcionalidad, Microsoft concede "implied consent" o "pre-consent" a estas aplicaciones first-party.
|
||||
- **Implied Consent:** Ciertas aplicaciones son automáticamente **concedidas acceso a scopes específicos sin la aprobación explícita del usuario o del administrador**.
|
||||
- Estos scopes pre-consentidos suelen estar ocultos tanto a usuarios como a administradores, lo que los hace menos visibles en las interfaces de gestión estándar.
|
||||
- Para simplificar la experiencia del usuario y mantener la funcionalidad, Microsoft concede "consentimiento implícito" o "pre-consentimiento" a estas aplicaciones de primera parte.
|
||||
- **Consentimiento implícito:** Ciertas aplicaciones reciben automáticamente **acceso a scopes específicos sin la aprobación explícita del usuario o del administrador**.
|
||||
- Estos scopes pre-consentidos suelen estar ocultos tanto para usuarios como para administradores, por lo que son menos visibles en las interfaces de administración estándar.
|
||||
|
||||
**Tipos de Client Application:**
|
||||
**Tipos de Aplicaciones Cliente:**
|
||||
|
||||
1. **Confidential Clients:**
|
||||
- Poseen sus propias credenciales (p. ej., contraseñas o certificados).
|
||||
@@ -36,63 +36,136 @@ Entra ID es la plataforma de identidad y gestión de acceso (IAM) basada en la n
|
||||
2. **Public Clients:**
|
||||
- No tienen credenciales únicas.
|
||||
- No pueden autenticarse de forma segura ante el authorization server.
|
||||
- **Implicación de seguridad:** Un atacante puede suplantar una public client application al solicitar tokens, ya que no existe un mecanismo para que el authorization server verifique la legitimidad de la aplicación.
|
||||
- **Implicación de seguridad:** Un atacante puede suplantar una aplicación cliente pública al solicitar tokens, ya que no existe un mecanismo para que el authorization server verifique la legitimidad de la aplicación.
|
||||
|
||||
### ROPC / Password Grant
|
||||
|
||||
El flujo OAuth2 **Resource Owner Password Credentials** (**ROPC**) utiliza un `POST` directo a `https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token` con `grant_type=password`, un **username**, **password**, un **client_id**, y el **scope** solicitado. En Entra ID esto es principalmente interesante para **public clients** porque el atacante puede reutilizar client IDs first-party de Microsoft o cualquier otro public client permitido sin necesitar un secret.
|
||||
```bash
|
||||
curl -X POST "https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "client_id=f05ff7c9-f75a-4acd-a3b5-f4b6a870245d" \
|
||||
--data-urlencode "client_info=1" \
|
||||
--data-urlencode "grant_type=password" \
|
||||
--data-urlencode "username=user@corp.com" \
|
||||
--data-urlencode "password=Password123!" \
|
||||
--data-urlencode "scope=https://graph.microsoft.com/.default"
|
||||
```
|
||||
Si las credenciales son válidas y el flujo está permitido, Entra puede devolver **access tokens** y a veces **refresh tokens** que son inmediatamente utilizables contra Microsoft Graph o el recurso objetivo.
|
||||
|
||||
### Clases de bypass del registro de inicio de sesión de Entra ID
|
||||
|
||||
Algunos bugs históricos de Entra ID permitían la **password validation** o incluso la **full token issuance** sin generar la entrada esperada del **Entra ID sign-in log**. Estos casos fueron corregidos, pero las técnicas siguen siendo útiles para entender cómo las pipelines de auth pueden fallar de maneras que dejan el **downstream token use visible** mientras la **upstream sign-in telemetry is absent**.
|
||||
|
||||
#### 1. Endpoint de tenant extranjero para validación sigilosa de password
|
||||
|
||||
Si la solicitud se envía al token endpoint de un **tenant GUID** distinto, Entra puede todavía validar si la password enviada es correcta para el username suministrado antes de que el flujo falle porque el usuario no existe en ese tenant extranjero. Históricamente esto permitió:
|
||||
|
||||
- **Password spraying / credential validation** sin un sign-in log correspondiente en el tenant víctima
|
||||
- Una diferencia en la respuesta que revela si el paso de la password tuvo éxito
|
||||
- No token issuance, pero menos telemetría que en un logon fallido normal
|
||||
|
||||
#### 2. Forzar un fallo posterior a la password
|
||||
|
||||
Si un parámetro usado **después** de la credential validation es inválido, como un `client_id` inválido, la transacción completa puede fallar aunque la password ya fuera correcta. Históricamente esto producía una vista de login **failed** mientras se ocultaba que la conjetura de la password había tenido éxito.
|
||||
|
||||
El patrón para recordar es:
|
||||
|
||||
- **Password check succeeds**
|
||||
- Un paso de validación posterior falla
|
||||
- El log representa el estado final de la transacción pero no el paso exitoso de password-validation
|
||||
|
||||
#### 3. Provocar fallo de logging con valores válidos pero sobredimensionados
|
||||
|
||||
La clase más peligrosa es cuando la solicitud permanece sintácticamente válida, la autenticación tiene éxito, **tokens are returned**, pero algún **logged field** es lo suficientemente grande como para romper la pipeline de logging. Ejemplos reportados incluyeron:
|
||||
|
||||
- Repetir scopes válidos miles de veces, como `openid openid openid ...`
|
||||
- Suministrar un header **User-Agent** excesivamente largo pero aún aceptado
|
||||
|
||||
Esto sugiere una clase general de problemas donde:
|
||||
|
||||
1. Entra valida credenciales y la sintaxis de la solicitud
|
||||
2. El token se emite con éxito
|
||||
3. El logging intenta persistir un campo raw controlado por el usuario
|
||||
4. La escritura del logging falla por longitud o por supuestos del esquema
|
||||
5. El usuario obtiene un token válido sin un sign-in record correspondiente
|
||||
|
||||
Example of the repeated-scope pattern:
|
||||
```bash
|
||||
curl -X POST "https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "client_id=f05ff7c9-f75a-4acd-a3b5-f4b6a870245d" \
|
||||
--data-urlencode "client_info=1" \
|
||||
--data-urlencode "grant_type=password" \
|
||||
--data-urlencode "username=user@corp.com" \
|
||||
--data-urlencode "password=Password123!" \
|
||||
--data-urlencode "scope=$(for num in {1..10000}; do echo -n 'openid '; done)"
|
||||
```
|
||||
#### Hunting / defensive note
|
||||
|
||||
No asumas que cada uso válido de un token tendrá un evento de inicio de sesión de Entra correspondiente. Al investigar actividad sospechosa de Graph, correlaciona:
|
||||
|
||||
- **Registros de inicio de sesión no interactivo**
|
||||
- **Registros de actividad de Graph**
|
||||
- **Dirección IP**, **ID de usuario/objeto**, **identificadores de sesión/correlación**, y **ventanas temporales**
|
||||
|
||||
Un método práctico de validación es encuadrar un supuesto éxito invisible entre dos inicios de sesión fallidos normales y luego verificar si la secuencia esperada `Failed -> Successful -> Failed` está perdiendo el evento intermedio después del retraso de ingestión. Si existe actividad posterior en Graph pero no el registro de inicio de sesión, considéralo como una potencial **brecha en el registro de inicio de sesión** o una condición de **token replay**.
|
||||
|
||||
## Authentication Tokens
|
||||
|
||||
Hay **tres tipos de tokens** usados en OIDC:
|
||||
|
||||
- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** El client presenta este token al resource server para **acceder a recursos**. Solo puede usarse para una combinación específica de usuario, client y resource y **no puede ser revocado** hasta su expiración – por defecto 1 hora.
|
||||
- **ID Tokens**: El client recibe este **token del authorization server**. Contiene información básica sobre el usuario. Está **vinculado a una combinación específica de usuario y client**.
|
||||
- **Refresh Tokens**: Proporcionados al client junto con el access token. Se usan para **obtener nuevos access e ID tokens**. Están vinculados a una combinación específica de usuario y client y pueden ser revocados. La expiración por defecto es **90 días** para refresh tokens inactivos y **sin expiración para tokens activos** (a partir de un refresh token es posible obtener nuevos refresh tokens).
|
||||
- Un refresh token debería estar ligado a un **`aud`**, a algunos **scopes**, y a un **tenant** y solo debería poder generar access tokens para ese aud, scopes (y no más) y tenant. Sin embargo, esto no ocurre con los tokens de **FOCI applications**.
|
||||
- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** El cliente presenta este token al servidor de recursos para **acceder a recursos**. Solo puede usarse para una combinación específica de usuario, cliente y recurso y **no puede ser revocado** hasta su expiración — es decir, 1 hora por defecto.
|
||||
- **ID Tokens**: El cliente recibe este **token del servidor de autorización**. Contiene información básica sobre el usuario. Está **vinculado a una combinación específica de usuario y cliente**.
|
||||
- **Refresh Tokens**: Se proporcionan al cliente junto con el access token. Usados para **obtener nuevos access e ID tokens**. Están vinculados a una combinación específica de usuario y cliente y pueden ser revocados. La expiración por defecto es **90 días** para refresh tokens inactivos y **sin expiración para tokens activos** (a partir de un refresh token es posible obtener nuevos refresh tokens).
|
||||
- Un refresh token debería estar ligado a un **`aud`**, a algunos **scopes**, y a un **tenant** y solo debería poder generar access tokens para ese aud, scopes (y no más) y tenant. Sin embargo, este no es el caso con los **FOCI applications tokens**.
|
||||
- Un refresh token está encriptado y solo Microsoft puede desencriptarlo.
|
||||
- Obtener un nuevo refresh token no revoca el refresh token anterior.
|
||||
|
||||
> [!WARNING]
|
||||
> La información para **conditional access** está **almacenada** dentro del **JWT**. Por tanto, si solicitas el **token desde una IP permitida**, esa **IP** quedará **almacenada** en el token y luego podrás usar ese token desde una **IP no permitida para acceder a los recursos**.
|
||||
> La información para **conditional access** está **almacenada** dentro del **JWT**. Entonces, si solicitas el **token desde una IP permitida**, esa **IP** quedará **almacenada** en el token y luego puedes usar ese token desde una **IP no permitida para acceder a los recursos**.
|
||||
|
||||
### Access Tokens "aud"
|
||||
|
||||
El campo indicado en el campo "aud" es el **resource server** (la aplicación) utilizado para realizar el login.
|
||||
El campo indicado en el campo "aud" es el **resource server** (la aplicación) usado para realizar el inicio de sesión.
|
||||
|
||||
El comando `az account get-access-token --resource-type [...]` soporta los siguientes tipos y cada uno de ellos añadirá un "aud" específico en el access token resultante:
|
||||
|
||||
> [!CAUTION]
|
||||
> Ten en cuenta que los siguientes son solo las APIs soportadas por `az account get-access-token` pero existen más.
|
||||
> Ten en cuenta que los siguientes son solo las APIs soportadas por `az account get-access-token` pero hay más.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>ejemplos de aud</summary>
|
||||
<summary>Ejemplos de aud</summary>
|
||||
|
||||
- **aad-graph (Azure Active Directory Graph API)**: Usado para acceder a la legacy Azure AD Graph API (deprecated), que permite a las aplicaciones leer y escribir datos del directorio en Azure Active Directory (Azure AD).
|
||||
- **aad-graph (Azure Active Directory Graph API)**: Usado para acceder a la API legacy Azure AD Graph (deprecated), que permite a las aplicaciones leer y escribir datos del directorio en Azure Active Directory (Azure AD).
|
||||
- `https://graph.windows.net/`
|
||||
|
||||
* **arm (Azure Resource Manager)**: Usado para gestionar recursos de Azure a través de la Azure Resource Manager API. Esto incluye operaciones como crear, actualizar y eliminar recursos como máquinas virtuales, cuentas de almacenamiento y más.
|
||||
* **arm (Azure Resource Manager)**: Usado para gestionar recursos de Azure a través de la API Azure Resource Manager. Esto incluye operaciones como crear, actualizar y eliminar recursos como máquinas virtuales, cuentas de almacenamiento y más.
|
||||
- `https://management.core.windows.net/ or https://management.azure.com/`
|
||||
|
||||
- **batch (Azure Batch Services)**: Usado para acceder a Azure Batch, un servicio que permite ejecutar aplicaciones de computación en paralelo y de alto rendimiento a gran escala en la nube.
|
||||
- **batch (Azure Batch Services)**: Usado para acceder a Azure Batch, un servicio que permite ejecutar aplicaciones de computación paralela y de alto rendimiento a gran escala en la nube.
|
||||
- `https://batch.core.windows.net/`
|
||||
|
||||
* **data-lake (Azure Data Lake Storage)**: Usado para interactuar con Azure Data Lake Storage Gen1, que es un servicio escalable de almacenamiento y analítica de datos.
|
||||
* **data-lake (Azure Data Lake Storage)**: Usado para interactuar con Azure Data Lake Storage Gen1, que es un servicio escalable de almacenamiento y análisis de datos.
|
||||
- `https://datalake.azure.net/`
|
||||
|
||||
- **media (Azure Media Services)**: Usado para acceder a Azure Media Services, que proporciona servicios en la nube para procesamiento y entrega de contenido de video y audio.
|
||||
- **media (Azure Media Services)**: Usado para acceder a Azure Media Services, que proporciona servicios en la nube para procesamiento y entrega de medios para contenido de video y audio.
|
||||
- `https://rest.media.azure.net`
|
||||
|
||||
* **ms-graph (Microsoft Graph API)**: Usado para acceder a Microsoft Graph API, el endpoint unificado para datos de servicios de Microsoft 365. Permite acceder a datos e insights de servicios como Azure AD, Office 365, Enterprise Mobility y servicios de seguridad.
|
||||
* **ms-graph (Microsoft Graph API)**: Usado para acceder a Microsoft Graph API, el endpoint unificado para los datos de Microsoft 365. Permite acceder a datos e insights de servicios como Azure AD, Office 365, Enterprise Mobility y servicios de seguridad.
|
||||
- `https://graph.microsoft.com`
|
||||
|
||||
- **oss-rdbms (Azure Open Source Relational Databases)**: Usado para acceder a los servicios de bases de datos de Azure para motores relacionales open-source como MySQL, PostgreSQL y MariaDB.
|
||||
- **oss-rdbms (Azure Open Source Relational Databases)**: Usado para acceder a los servicios de base de datos de Azure para motores relacionales open-source como MySQL, PostgreSQL y MariaDB.
|
||||
- `https://ossrdbms-aad.database.windows.net`
|
||||
|
||||
</details>
|
||||
|
||||
### Access Tokens Scopes "scp"
|
||||
|
||||
El scope de un access token se almacena dentro de la clave scp dentro del JWT del access token. Estos scopes definen a qué tiene acceso el access token.
|
||||
El scope de un access token se almacena dentro de la clave scp en el JWT del access token. Estos scopes definen a qué tiene acceso el access token.
|
||||
|
||||
Si un JWT está autorizado para contactar una API específica pero **no tiene el scope** para realizar la acción solicitada, **no podrá realizar la acción** con ese JWT.
|
||||
Si un JWT tiene permitido contactar una API específica pero **no tiene el scope** para realizar la acción solicitada, **no podrá realizar la acción** con ese JWT.
|
||||
|
||||
### Get refresh & access token example
|
||||
```python
|
||||
@@ -144,32 +217,31 @@ scopes=["https://graph.microsoft.com/.default"],
|
||||
)
|
||||
pprint(new_azure_cli_bearer_tokens_for_graph_api)
|
||||
```
|
||||
### Otros campos del access token
|
||||
### Otros campos del token de acceso
|
||||
|
||||
- **appid**: ID de la aplicación usada para generar el token
|
||||
- **appidacr**: El Application Authentication Context Class Reference indica cómo se autenticó el client; para un public client el valor es 0, y si se usa un client secret el valor es 1
|
||||
- **acr**: El claim Authentication Context Class Reference es "0" cuando la autenticación del usuario final no cumplió los requisitos de ISO/IEC 29115.
|
||||
- **amr**: El Authentication method indica cómo se autenticó el token. Un valor de “pwd” indica que se usó una password.
|
||||
- **appid**: ID de la aplicación usado para generar el token
|
||||
- **appidacr**: El Application Authentication Context Class Reference indica cómo se autenticó el cliente; para un cliente público el valor es 0 y si se usa un secreto de cliente el valor es 1
|
||||
- **acr**: La claim Authentication Context Class Reference vale "0" cuando la autenticación del usuario final no cumplió los requisitos de ISO/IEC 29115.
|
||||
- **amr**: El método de autenticación indica cómo se autenticó; un valor "pwd" indica que se usó una contraseña.
|
||||
- **groups**: Indica los grupos de los que el principal es miembro.
|
||||
- **iss**: El issuer identifica el security token service (STS) que generó el token. e.g. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (el uuid es el tenant ID)
|
||||
- **oid**: El object ID del principal
|
||||
- **tid**: Tenant ID
|
||||
- **iat, nbf, exp**: Issued at (cuando fue emitido), Not before (no puede usarse antes de este tiempo, usualmente mismo valor que iat), Expiration time (tiempo de expiración).
|
||||
- **iss**: El iss identifica el security token service (STS) que generó el token. e.g. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (el uuid es el tenant ID)
|
||||
- **oid**: ID de objeto del principal
|
||||
- **tid**: ID del tenant
|
||||
- **iat, nbf, exp**: Issued at (cuando fue emitido), Not before (no puede usarse antes de este tiempo, normalmente mismo valor que iat), Tiempo de expiración.
|
||||
|
||||
## Escalada de privilegios con tokens FOCI
|
||||
|
||||
## FOCI Tokens Privilege Escalation
|
||||
Anteriormente se mencionó que los refresh tokens deberían estar ligados a los **scopes** con los que fueron generados, a la **application** y al **tenant** a los que fueron emitidos. Si cualquiera de estos límites se rompe, es posible escalar privilegios, ya que se podrá generar access tokens para otros recursos y tenants a los que el usuario tiene acceso y con más scopes de los previstos originalmente.
|
||||
|
||||
Anteriormente se mencionó que los refresh tokens deberían estar ligados a los **scopes** con los que se generaron, a la **application** y al **tenant** al que se generaron. Si cualquiera de estos límites se rompe, es posible escalar privilegios ya que se podría generar access tokens para otros recursos y tenants a los que el usuario tenga acceso y con más scopes de los originalmente previstos.
|
||||
Además, esto es posible con todos los refresh tokens en la [Microsoft identity platform] (Microsoft Entra accounts, Microsoft personal accounts, and social accounts like Facebook and Google) porque, como mencionan los [**docs**]: "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."
|
||||
|
||||
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."
|
||||
También tenga en cuenta que las aplicaciones FOCI son aplicaciones públicas, por lo que **no se necesita secreto** para autenticarse ante el servidor.
|
||||
|
||||
Además, tenga en cuenta que las aplicaciones FOCI son public applications, por lo que **no se necesita client secret** para autenticarse en el servidor.
|
||||
|
||||
Los clientes FOCI conocidos reportados en la [**investigación original**](https://github.com/secureworks/family-of-client-ids-research/tree/main) se pueden [**encontrar aquí**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv).
|
||||
Los clientes FOCI conocidos reportados en la [**original research**] se pueden [**found here**].
|
||||
|
||||
### Obtener un scope diferente
|
||||
|
||||
Siguiendo con el ejemplo de código anterior, en este código se solicita un nuevo token para un scope diferente:
|
||||
Continuando con el código de ejemplo anterior, en este código se solicita un nuevo token para un scope diferente:
|
||||
```python
|
||||
# Code from https://github.com/secureworks/family-of-client-ids-research
|
||||
azure_cli_bearer_tokens_for_outlook_api = (
|
||||
@@ -186,7 +258,7 @@ scopes=[
|
||||
)
|
||||
pprint(azure_cli_bearer_tokens_for_outlook_api)
|
||||
```
|
||||
### Obtener client y scopes diferentes
|
||||
### Obtener un cliente y scopes diferentes
|
||||
```python
|
||||
# Code from https://github.com/secureworks/family-of-client-ids-research
|
||||
microsoft_office_client = msal.PublicClientApplication("d3590ed6-52b3-4102-aeff-aad2292ab01c")
|
||||
@@ -204,45 +276,45 @@ pprint(microsoft_office_bearer_tokens_for_graph_api)
|
||||
```
|
||||
## NAA / BroCI (Nested App Authentication / Broker Client Injection)
|
||||
|
||||
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.
|
||||
A BroCI refresh token es un patrón de intercambio de tokens brokered donde un refresh token existente se usa con parámetros adicionales del broker para solicitar tokens como otra first-party app de confianza.
|
||||
|
||||
These refresh tokens must be minted in that broker context (a regular refresh token usually cannot be used as a BroCI refresh token).
|
||||
Estos refresh tokens deben ser emitidos en ese contexto brokered (un refresh token normal habitualmente no puede usarse como refresh token BroCI).
|
||||
|
||||
### Objetivo y propósito
|
||||
### Goal and purpose
|
||||
|
||||
El objetivo de BroCI es reutilizar una sesión de usuario válida de una cadena de apps con capacidad de broker y solicitar tokens para otra pareja app/recurso de confianza. Por lo tanto, permite "escalar privilegios" desde el token original.
|
||||
El objetivo de BroCI es reutilizar una sesión de usuario válida desde una cadena de apps con capacidad de broker y solicitar tokens para otra pareja app/recurso de confianza. Por lo tanto, permite "escalar privilegios" desde el token original.
|
||||
|
||||
Desde una perspectiva ofensiva, esto importa porque:
|
||||
|
||||
- Puede desbloquear rutas de aplicaciones first-party con consentimiento previo que no son accesibles con intercambios de refresh estándar.
|
||||
- Puede desbloquear rutas de apps first-party pre-consentidas que no son accesibles con intercambios de refresh estándar.
|
||||
- Puede devolver access tokens para APIs de alto valor (por ejemplo, Microsoft Graph) bajo identidades de app con permisos delegados amplios.
|
||||
- Amplía las oportunidades de post-authentication token pivoting más allá del clásico FOCI client switching.
|
||||
- Amplía las oportunidades de pivot de tokens post-autenticación más allá del clásico cambio de cliente FOCI.
|
||||
|
||||
What changes in a NAA/BroCI refresh token is not the visible token format, but the **issuance context** and broker-related metadata that Microsoft validates during brokered refresh operations.
|
||||
Lo que cambia en un NAA/BroCI refresh token no es el formato visible del token, sino el contexto de emisión y los metadatos relacionados con el broker que Microsoft valida durante las operaciones de refresh brokered.
|
||||
|
||||
NAA/BroCI token exchanges are **not** the same as a regular OAuth refresh exchange.
|
||||
Los intercambios de token NAA/BroCI **no** son lo mismo que un intercambio OAuth refresh regular.
|
||||
|
||||
- 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.
|
||||
- Un refresh token regular (por ejemplo obtenido vía device code flow) suele ser válido para operaciones estándar `grant_type=refresh_token`.
|
||||
- Una petición BroCI incluye contexto adicional del broker (`brk_client_id`, broker `redirect_uri`, y `origin`).
|
||||
- Microsoft valida si el refresh token presentado fue emitido en un contexto brokered que coincida.
|
||||
- Por ello, muchos refresh tokens "normales" fallan en peticiones BroCI con errores como `AADSTS900054` ("Specified Broker Client ID does not match ID in provided grant").
|
||||
- Generalmente no puedes "convertir" un refresh token normal en uno válido para BroCI por código.
|
||||
- Necesitas un refresh token ya emitido por un flujo brokered compatible.
|
||||
|
||||
Check the web **<https://entrascopes.com/>** to find BroCI configured apps an the trust relationships they have.
|
||||
|
||||
|
||||
### Modelo mental
|
||||
### Mental model
|
||||
|
||||
Think of BroCI as:
|
||||
Piensa en BroCI como:
|
||||
|
||||
`user session -> brokered refresh token issuance -> brokered refresh call (brk_client_id + redirect_uri + origin) -> access token for target trusted app/resource`
|
||||
|
||||
If any part of that broker chain does not match, the exchange fails.
|
||||
Si cualquier parte de esa cadena broker no coincide, el intercambio falla.
|
||||
|
||||
### Dónde encontrar un refresh token válido para BroCI
|
||||
### Where to find a BroCI-valid refresh token
|
||||
|
||||
One practical way is browser portal traffic collection:
|
||||
Una forma práctica es la colección de tráfico del portal en el navegador:
|
||||
|
||||
1. Sign in to `https://entra.microsoft.com` (or Azure portal).
|
||||
2. Open DevTools -> Network.
|
||||
@@ -252,13 +324,13 @@ One practical way is browser portal traffic collection:
|
||||
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).
|
||||
|
||||
### Errores comunes
|
||||
### 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.
|
||||
|
||||
<details>
|
||||
<summary>Python BroCI refresh helper (broci_auth.py)</summary>
|
||||
<summary>Ayudante de refresh BroCI en Python (broci_auth.py)</summary>
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
@@ -533,30 +605,31 @@ raise SystemExit(main())
|
||||
|
||||
## Dónde encontrar tokens
|
||||
|
||||
Desde la perspectiva de un atacante es muy interesante saber dónde es posible encontrar access y refresh tokens cuando, por ejemplo, el PC de la víctima está comprometido:
|
||||
Desde la perspectiva de un atacante, es muy interesante saber dónde es posible encontrar access and refresh tokens cuando, por ejemplo, el PC de una víctima está comprometido:
|
||||
|
||||
- Inside **`<HOME>/.Azure`**
|
||||
- **`azureProfile.json`** contiene info sobre usuarios que iniciaron sesión en el pasado
|
||||
- **`clouds.config contains`** info sobre subscriptions
|
||||
- **`service_principal_entries.json`** contiene application credentials (tenant id, clients and secret). Only in Linux & macOS
|
||||
- **`msal_token_cache.json`** contiene access tokens y refresh tokens. Only in Linux & macOS
|
||||
- **`service_principal_entries.bin`** and msal_token_cache.bin se usan en Windows y están encriptados con DPAPI
|
||||
- **`msal_http_cache.bin`** es un cache de HTTP request
|
||||
- Load it: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)`
|
||||
- **`AzureRmContext.json`** contiene información sobre logins previos usando Az PowerShell (pero sin credentials)
|
||||
- Inside **`C:\Users\<username>\AppData\Local\Microsoft\IdentityCache\*`** hay varios archivos `.bin` con **access tokens**, ID tokens y account information encriptados con el DPAPI del usuario.
|
||||
- Es posible encontrar más **access tokens** en los archivos `.tbres` dentro de **`C:\Users\<username>\AppData\Local\Microsoft\TokenBroken\Cache\`**, que contienen un base64 encriptado con DPAPI con access tokens.
|
||||
- En Linux y macOS puedes obtener **access tokens, refresh tokens and id tokens** desde Az PowerShell (si se usó) ejecutando `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"`
|
||||
- Dentro de **`<HOME>/.Azure`**
|
||||
- **`azureProfile.json`** contiene información sobre usuarios que iniciaron sesión en el pasado
|
||||
- **`clouds.config contains`** contiene información sobre suscripciones
|
||||
- **`service_principal_entries.json`** contiene credenciales de aplicaciones (tenant id, clients and secret). Solo en Linux & macOS
|
||||
- **`msal_token_cache.json`** contiene access tokens y refresh tokens. Solo en Linux & macOS
|
||||
- **`service_principal_entries.bin`** y msal_token_cache.bin se usan en Windows y están cifrados con DPAPI
|
||||
- **`msal_http_cache.bin`** es una cache de peticiones HTTP
|
||||
- Cargarlo: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)`
|
||||
- **`AzureRmContext.json`** contiene información sobre logins previos usando Az PowerShell (pero sin credenciales)
|
||||
- Dentro de **`C:\Users\<username>\AppData\Local\Microsoft\IdentityCache\*`** hay varios archivos `.bin` con **access tokens**, ID tokens e información de cuentas cifrados con el DPAPI del usuario.
|
||||
- Es posible encontrar más **access tokens** en los archivos `.tbres` dentro de **`C:\Users\<username>\AppData\Local\Microsoft\TokenBroken\Cache\`**, que contienen un base64 cifrado con DPAPI con access tokens.
|
||||
- En Linux y macOS puedes obtener **access tokens, refresh tokens and id tokens** de Az PowerShell (si se usó) ejecutando `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"`
|
||||
- En Windows esto solo genera id tokens.
|
||||
- Es posible comprobar si se usó Az PowerShell en Linux y macOS verificando si `$HOME/.local/share/.IdentityService/` existe (aunque los archivos contenidos están vacíos e inútiles)
|
||||
- Si el usuario está **logged inside Azure with the browser**, según este [**post**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) es posible iniciar el flujo de autenticación con un **redirect to localhost**, hacer que el navegador autorice automáticamente el login y recibir el refresh token. Nota que solo hay unas pocas aplicaciones FOCI que permiten redirect to localhost (como az cli o el powershell module), así que esas aplicaciones deben estar permitidas.
|
||||
- Otra opción explicada en el blog es usar la herramienta [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow) que puede usar cualquier aplicación porque **obtendrá el OAuth code para luego obtener un refresh token desde el título de la página final de auth** usando la redirect URI `https://login.microsoftonline.com/common/oauth2/nativeclient`.
|
||||
- Es posible ver si Az PowerShell fue usado en Linux y macOS comprobando si `$HOME/.local/share/.IdentityService/` existe (aunque los archivos contenidos están vacíos e inútiles)
|
||||
- Si el usuario está **logueado en Azure desde el navegador**, según este [**post**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) es posible iniciar el flujo de autenticación con una **redirección a localhost**, hacer que el navegador autorice automáticamente el inicio de sesión y recibir el refresh token. Ten en cuenta que solo hay unas pocas aplicaciones FOCI que permiten redirect a localhost (como az cli o el módulo de powershell), por lo que estas aplicaciones deben estar permitidas.
|
||||
- Otra opción explicada en el blog es usar la herramienta [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow) que puede usar cualquier aplicación porque **obtendrá el código OAuth para luego obtener un refresh token desde el título de la página de autenticación final** usando el redirect URI `https://login.microsoftonline.com/common/oauth2/nativeclient`.
|
||||
|
||||
## References
|
||||
## Referencias
|
||||
|
||||
- [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/)
|
||||
- [https://trustedsec.com/blog/full-disclosure-a-third-and-fourth-azure-sign-in-log-bypass-found](https://trustedsec.com/blog/full-disclosure-a-third-and-fourth-azure-sign-in-log-bypass-found)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user