# Az - Tokens & Public Applications

{{#include ../../../banners/hacktricks-training.md}}

## Basic Information

Entra ID est la plateforme de gestion des identités et des accès (IAM) basée sur le cloud de Microsoft, servant de système d'authentification et d'autorisation fondamental pour des services comme Microsoft 365 et Azure Resource Manager. Azure AD implémente le cadre d'autorisation OAuth 2.0 et le protocole d'authentification OpenID Connect (OIDC) pour gérer l'accès aux ressources.

### OAuth

**Participants clés dans OAuth 2.0 :**

1. **Serveur de ressources (RS) :** Protège les ressources appartenant au propriétaire des ressources.
2. **Propriétaire des ressources (RO) :** Typiquement un utilisateur final qui possède les ressources protégées.
3. **Application cliente (CA) :** Une application cherchant à accéder aux ressources au nom du propriétaire des ressources.
4. **Serveur d'autorisation (AS) :** Délivre des jetons d'accès aux applications clientes après les avoir authentifiées et autorisées.

**Scopes et consentement :**

- **Scopes :** Permissions granulaires définies sur le serveur de ressources qui spécifient les niveaux d'accès.
- **Consentement :** Le processus par lequel un propriétaire de ressources accorde à une application cliente la permission d'accéder aux ressources avec des scopes spécifiques.

**Intégration Microsoft 365 :**

- Microsoft 365 utilise Azure AD pour l'IAM et est composé de plusieurs applications OAuth "de première partie".
- Ces applications sont profondément intégrées et ont souvent des relations de service interdépendantes.
- Pour simplifier l'expérience utilisateur et maintenir la fonctionnalité, Microsoft accorde un "consentement implicite" ou un "pré-consentement" à ces applications de première partie.
- **Consentement implicite :** Certaines applications se voient automatiquement **accorder l'accès à des scopes spécifiques sans approbation explicite de l'utilisateur ou de l'administrateur**.
- Ces scopes pré-consentis sont généralement cachés à la fois des utilisateurs et des administrateurs, les rendant moins visibles dans les interfaces de gestion standard.

**Types d'applications clientes :**

1. **Clients confidentiels :**
- Possèdent leurs propres identifiants (par exemple, mots de passe ou certificats).
- Peuvent **s'authentifier de manière sécurisée** auprès du serveur d'autorisation.
2. **Clients publics :**
- N'ont pas d'identifiants uniques.
- Ne peuvent pas s'authentifier de manière sécurisée auprès du serveur d'autorisation.
- **Implication de sécurité :** Un attaquant peut usurper une application cliente publique lors de la demande de jetons, car il n'existe aucun mécanisme pour que le serveur d'autorisation vérifie la légitimité de l'application.

## Authentication Tokens

Il existe **trois types de jetons** utilisés dans OIDC :

- [**Jetons d'accès**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** Le client présente ce jeton au serveur de ressources pour **accéder aux ressources**. Il ne peut être utilisé que pour une combinaison spécifique d'utilisateur, de client et de ressource et **ne peut pas être révoqué** jusqu'à son expiration - c'est-à-dire 1 heure par défaut.
- **Jetons d'identité** : Le client reçoit ce **jeton du serveur d'autorisation**. Il contient des informations de base sur l'utilisateur. Il est **lié à une combinaison spécifique d'utilisateur et de client**.
- **Jetons de rafraîchissement** : Fournis au client avec le jeton d'accès. Utilisés pour **obtenir de nouveaux jetons d'accès et d'identité**. Il est lié à une combinaison spécifique d'utilisateur et de client et peut être révoqué. L'expiration par défaut est de **90 jours** pour les jetons de rafraîchissement inactifs et **pas d'expiration pour les jetons actifs** (il est possible d'obtenir de nouveaux jetons de rafraîchissement à partir d'un jeton de rafraîchissement).
- Un jeton de rafraîchissement doit être lié à un **`aud`**, à certains **scopes**, et à un **tenant** et il ne devrait pouvoir générer des jetons d'accès que pour cet aud, ces scopes (et pas plus) et ce tenant. Cependant, ce n'est pas le cas avec les **jetons d'applications FOCI**.
- Un jeton de rafraîchissement est crypté et seul Microsoft peut le déchiffrer.
- Obtenir un nouveau jeton de rafraîchissement ne révoque pas le jeton de rafraîchissement précédent.

> [!WARNING]
> Les informations pour **l'accès conditionnel** sont **stockées** à l'intérieur du **JWT**. Donc, si vous demandez le **jeton depuis une adresse IP autorisée**, cette **IP** sera **stockée** dans le jeton et vous pourrez ensuite utiliser ce jeton depuis une **IP non autorisée pour accéder aux ressources**.

### Access Tokens "aud"

Le champ indiqué dans le champ "aud" est le **serveur de ressources** (l'application) utilisé pour effectuer la connexion.

La commande `az account get-access-token --resource-type [...]` prend en charge les types suivants et chacun d'eux ajoutera un "aud" spécifique dans le jeton d'accès résultant :

> [!CAUTION]
> Notez que les éléments suivants ne sont que les API prises en charge par `az account get-access-token`, mais il y en a d'autres.

<details>

<summary>exemples d'aud</summary>

- **aad-graph (Azure Active Directory Graph API)** : Utilisé pour accéder à l'API Azure AD Graph héritée (dépréciée), qui permet aux applications de lire et d'écrire des données d'annuaire dans Azure Active Directory (Azure AD).
- `https://graph.windows.net/`

* **arm (Azure Resource Manager)** : Utilisé pour gérer les ressources Azure via l'API Azure Resource Manager. Cela inclut des opérations telles que la création, la mise à jour et la suppression de ressources telles que des machines virtuelles, des comptes de stockage, et plus encore.
- `https://management.core.windows.net/ ou https://management.azure.com/`

- **batch (Azure Batch Services)** : Utilisé pour accéder à Azure Batch, un service qui permet d'exécuter efficacement des applications de calcul parallèle à grande échelle et de haute performance dans le cloud.
- `https://batch.core.windows.net/`

* **data-lake (Azure Data Lake Storage)** : Utilisé pour interagir avec Azure Data Lake Storage Gen1, qui est un service de stockage et d'analyse de données évolutif.
- `https://datalake.azure.net/`

- **media (Azure Media Services)** : Utilisé pour accéder à Azure Media Services, qui fournissent des services de traitement et de livraison de médias basés sur le cloud pour le contenu vidéo et audio.
- `https://rest.media.azure.net`

* **ms-graph (Microsoft Graph API)** : Utilisé pour accéder à l'API Microsoft Graph, le point de terminaison unifié pour les données des services Microsoft 365. Il permet d'accéder aux données et aux informations des services tels qu'Azure AD, Office 365, Enterprise Mobility et les services de sécurité.
- `https://graph.microsoft.com`

- **oss-rdbms (Azure Open Source Relational Databases)** : Utilisé pour accéder aux services de base de données Azure pour des moteurs de bases de données relationnelles open-source comme MySQL, PostgreSQL et MariaDB.
- `https://ossrdbms-aad.database.windows.net`

</details>

### Access Tokens Scopes "scp"

Le scope d'un jeton d'accès est stocké à l'intérieur de la clé scp dans le JWT du jeton d'accès. Ces scopes définissent à quoi le jeton d'accès a accès.

Si un JWT est autorisé à contacter une API spécifique mais **n'a pas le scope** pour effectuer l'action demandée, il **ne pourra pas effectuer l'action** avec ce JWT.

### Get refresh & access token example
```python
# Code example from https://github.com/secureworks/family-of-client-ids-research
import msal
import requests
import jwt
from pprint import pprint
from typing import Any, Dict, List


# LOGIN VIA CODE FLOW AUTHENTICATION
azure_cli_client = msal.PublicClientApplication(
"04b07795-8ddb-461a-bbee-02f9e1bf7b46" # ID for Azure CLI client
)
device_flow = azure_cli_client.initiate_device_flow(
scopes=["https://graph.microsoft.com/.default"]
)
print(device_flow["message"])

# Perform device code flow authentication

azure_cli_bearer_tokens_for_graph_api = azure_cli_client.acquire_token_by_device_flow(
device_flow
)
pprint(azure_cli_bearer_tokens_for_graph_api)


# DECODE JWT
def decode_jwt(base64_blob: str) -> Dict[str, Any]:
"""Decodes base64 encoded JWT blob"""
return jwt.decode(
base64_blob, options={"verify_signature": False, "verify_aud": False}
)
decoded_access_token = decode_jwt(
azure_cli_bearer_tokens_for_graph_api.get("access_token")
)
pprint(decoded_access_token)


# GET NEW ACCESS TOKEN AND REFRESH TOKEN
new_azure_cli_bearer_tokens_for_graph_api = (
# Same client as original authorization
azure_cli_client.acquire_token_by_refresh_token(
azure_cli_bearer_tokens_for_graph_api.get("refresh_token"),
# Same scopes as original authorization
scopes=["https://graph.microsoft.com/.default"],
)
)
pprint(new_azure_cli_bearer_tokens_for_graph_api)
```
### Autres champs de jeton d'accès

- **appid** : ID de l'application utilisé pour générer le jeton
- **appidacr** : La référence de classe de contexte d'authentification de l'application indique comment le client a été authentifié, pour un client public la valeur est 0, et si un secret client est utilisé la valeur est 1
- **acr** : La revendication de référence de classe de contexte d'authentification est "0" lorsque l'authentification de l'utilisateur final ne répond pas aux exigences de l'ISO/IEC 29115.
- **amr** : La méthode d'authentification indique comment le jeton a été authentifié. Une valeur de “pwd” indique qu'un mot de passe a été utilisé.
- **groups** : Indique les groupes dont le principal est membre.
- **iss** : Les problèmes identifient le service de jeton de sécurité (STS) qui a généré le jeton. e.g. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (l'uuid est l'ID du locataire)
- **oid** : L'ID de l'objet du principal
- **tid** : ID du locataire
- **iat, nbf, exp** : Émis à (quand il a été émis), Pas avant (ne peut pas être utilisé avant ce moment, généralement la même valeur que iat), Temps d'expiration.

## Escalade de privilèges des jetons FOCI

Il a été mentionné précédemment que les jetons d'actualisation devraient être liés aux **portées** avec lesquelles ils ont été générés, à l'**application** et au **locataire** auxquels ils ont été générés. Si l'une de ces limites est franchie, il est possible d'escalader les privilèges car il sera possible de générer des jetons d'accès pour d'autres ressources et locataires auxquels l'utilisateur a accès et avec plus de portées que ce qui était initialement prévu.

De plus, **cela est possible avec tous les jetons d'actualisation** dans la [Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/) (comptes Microsoft Entra, comptes personnels Microsoft et comptes sociaux comme Facebook et Google) car comme le mentionnent les [**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens) : "Les jetons d'actualisation sont liés à une combinaison d'utilisateur et de client, mais **ne sont pas liés à une ressource ou à un locataire**. Un client peut utiliser un jeton d'actualisation pour acquérir des jetons d'accès **à travers n'importe quelle combinaison de ressource et de locataire** où il a la permission de le faire. Les jetons d'actualisation sont cryptés et seule la Microsoft identity platform peut les lire."

De plus, notez que les applications FOCI sont des applications publiques, donc **aucun secret n'est nécessaire** pour s'authentifier auprès du serveur.

Ensuite, les clients FOCI connus rapportés dans la [**recherche originale**](https://github.com/secureworks/family-of-client-ids-research/tree/main) peuvent être [**trouvés ici**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv).

### Obtenir une portée différente

En suivant l'exemple de code précédent, dans ce code, un nouveau jeton est demandé pour une portée différente :
```python
# Code from https://github.com/secureworks/family-of-client-ids-research
azure_cli_bearer_tokens_for_outlook_api = (
# Same client as original authorization
azure_cli_client.acquire_token_by_refresh_token(
new_azure_cli_bearer_tokens_for_graph_api.get(
"refresh_token"
),
# But different scopes than original authorization
scopes=[
"https://outlook.office.com/.default"
],
)
)
pprint(azure_cli_bearer_tokens_for_outlook_api)
```
### Obtenir différents clients et portées
```python
# Code from https://github.com/secureworks/family-of-client-ids-research
microsoft_office_client = msal.PublicClientApplication("d3590ed6-52b3-4102-aeff-aad2292ab01c")
microsoft_office_bearer_tokens_for_graph_api = (
# This is a different client application than we used in the previous examples
microsoft_office_client.acquire_token_by_refresh_token(
# But we can use the refresh token issued to our original client application
azure_cli_bearer_tokens_for_outlook_api.get("refresh_token"),
# And request different scopes too
scopes=["https://graph.microsoft.com/.default"],
)
)
# How is this possible?
pprint(microsoft_office_bearer_tokens_for_graph_api)
```
## Références

- [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)

{{#include ../../../banners/hacktricks-training.md}}
