Microsoft Cloud Access Tokens - Control the Token, Control the Cloud

Microsoft Cloud Access Tokens

Control the Token, Control the Cloud

Marius Elmiger
by Marius Elmiger
on May 23, 2024
time to read: 21 minutes

Keypoints

Why it is important to protect Microsoft cloud access tokens

  • Access tokens are used for authentication
  • They're generated and issued by the Microsoft Identity Platform
  • Access Tokens are security tokens encoded in the JSON Web Tokens (JWTs) format
  • They can be extracted from multiple sources
  • Access tokens especially from privileged users should be protected
  • The current access token protection options are limited

As more and more companies use cloud services for their daily operations, it is important to understand the potential risks of access token theft. While some on-premises systems can provide multiple layers of token protection, incidents of credential theft still happen. In the cloud, the risk is higher, as access tokens often lack proper protection and can be extracted in multiple ways. Once obtained, attackers quickly access corporate data from remote, which makes breaches more likely to have a large impact

While access tokens serve a similar purpose across different cloud platforms, solutions, or Web sites, there may be differences in their implementation and specific functionality. This article focuses primarily on how to extract access tokens issued by the Microsoft Cloud. It concludes with some ways to make access token theft more difficult.

What is a Microsoft Cloud Access Token?

An access token is a security token issued by an authorization server as part of an OAuth 2.0 flow. It contains information about the user and the resource for which the token is intended. This information can be used to access Web APIs and other protected resources. Resources validate access tokens to grant access to a client application.

The Microsoft Identity Platform implements security tokens as JSON Web Tokens (JWTs) that contain claims. Because JWTs are used as security tokens, this form of authentication is sometimes referred to as JWT authentication. A claim provides assertions about one entity, such as a client application or resource owner, to another entity, such as a resource server. A claim may also be referred to as a JWT claim or a JSON Web token claim. Additionally, cryptographic signing ensures the integrity and authenticity of the token. The token is digitally signed using a private key, and the recipient can verify its authenticity using the corresponding public key.

The default Microsoft Cloud JWT token is base64url-encoded, so it can be decoded. Decoding is preferably done offline to avoid any risk of compromise. For example, by downloading and reviewing the code from jwt.ms or jwt.io and using the HTML/JavaScript offline. Or by using a PowerShell script like the one from Vasil Michev or the Python solution roadtx from DirkJan. Once the JWT is decoded, it may look like the following truncated access token example:

{
  "typ": "JWT",
  "nonce": "OwJxBtbDQCPbBNDAfLGfXVExE0pF8sLb36nC_MWvpDQ",
  "alg": "RS256"
}.{
  "aud": "https://graph.microsoft.com",
  "iss": "https://sts.windows.net/d2a16643-x/",
  "iat": 1715765602,
  "nbf": 1715765602,
  "exp": 1715770910,
  "amr": [
    "pwd",
    "mfa"
  ],
  "app_displayname": "My Profile",
  "appid": "8c59ead7-d703-4a27-9e55-c96a0054c8d2",
  "appidacr": "0",
  "ipaddr": "141.195.x.x",
  "name": "Rabban",
  "oid": "4c422389-x-x-x-x",
  "scp": "AuditLog.Read.All BitlockerKey.Read.All CrossTenantInformation.ReadBasic.All CrossTenantUserProfileSharing.ReadWrite.All Device.EnableDisableAccount.All Device.Read.All email Group.Read.All Group.ReadWrite.All GroupMember.Read.All MailboxSettings.ReadWrite openid Organization.Read.All Policy.Read.All profile RoleManagement.ReadWrite.Directory User.Invite.All User.Read.All User.ReadBasic.All User.ReadWrite",
  "signin_state": [
    "kmsi"
  ],
  "tid": "d2a16643-x-x-x-x",
  "upn": "rabban@x.onmicrosoft.com",
  "xms_cc": [
    "cp1"
  ],
}.[Signature]

In the above example, the token contains several claims. The most important ones are listed below to identify for example the owner, the audience, the scope, the xms_cc, and the expiration date.

Claim typeNotes
audIdentifies the intended recipient of the token. In id_tokens, the audience is your app’s Application ID, assigned to your app in the Azure portal. Your app should validate this value, and reject the token if the value does not match.
expThe “exp” (expiration time) claim identifies the expiration time on or after which the JWT must not be accepted for processing. It is important to note that a resource may reject the token before this time as well – if for example a change in authentication is required or a token revocation has been detected.
amrIdentifies how the subject of the token was authenticated. Microsoft identities can authenticate in a variety of ways, which may be relevant to your application. The amr claim is an array that can contain multiple items, such as [“mfa”, “rsa”, “pwd”], for an authentication that used both a password and the Authenticator app. See the amr claim section in Azure Active Directory access tokens documentation for values.
appidThe application ID of the client using the token. The application can act as itself or on behalf of a user. The application ID typically represents an application object, but it can also represent a service principal object in Entra ID.
ipaddrThe IP address the user authenticated from.
scpThe set of scopes exposed by your application for which the client application has requested (and received) consent. Your app should verify that these scopes are valid ones exposed by your app, and make authorization decisions based on the value of these scopes. Only included for user tokens.
tidA GUID that represents the Entra ID tenant that the user is from. For work and school accounts, the GUID is the immutable tenant ID of the organization that the user belongs to. For personal accounts, the value is 9188040d-6c67-4c5b-b112-36a304b66dad. The profile scope is required in order to receive this claim.
upnThe username of the user. May be a phone number, email address, or unformatted string. Should only be used for display purposes and providing username hints in reauthentication scenarios.
xms_ccThe xms_cc claim with a value of cp1 in the access token is the authoritative way to identify a client application is capable of handling a claims challenge. Access Tokens with this claim can be protected by Continuous Access Evaluation (CAE)

More details regarding the Microsoft cloud’s token claims are documented under the ID token claims reference.

A Microsoft cloud access token is limited to one resource, is typically valid for one hour, and cannot be revoked. There is also a Continuous Access Evaluation (CAE) access token that is valid for 24 hours and is revokable. Tools such as TokenTacticsV2 or roadtx can be used to do create a CAE access token from a valid refresh token or a cookie. Unfortunately, refresh tokens are not covered in this article, as they are a beast in themselves. If you want to learn more about refresh tokens, check out Dirk-Jan Mollema blogs.

If an access token can be extracted, it can usually be used from any device, from anywhere, for as long as it is valid. It is therefore crucial to protect access tokens especially for privileged users. For more details on how to do this, jump ahead to the Access Token Protection chapter.

I want one

There are many ways to grab a Microsoft Cloud Access Token. Here are some examples that we use during Security Assessments, Pentests or Red Teaming.

From the Browser

The easiest way for a logged-in user to obtain an access token is to open the browser developer tools and browse to Microsoft cloud front-end URLs such as https://myapps.microsoft.com/, https://myaccount.microsoft.com/, https://portal.azure.com/ or https://mysignins.microsoft.com/. Here is a brief overview of access tokens that can be extracted from known API endpoints and whether they can be used for tools such as RoadRecon or AzureHound.

URL Recipient (aud) Scopes RoadRecon AzureHound
https://mysignins.microsoft.comhttps://graph.microsoft.comemail openid profile AuditLog.Read.All CrossTenantInformation.ReadBasic.All Directory.Read.All Policy.Read.All User.Read UserAuthenticationMethod.ReadWrite UserAuthenticationMethod.ReadWrite.All .defaultNoYes
(Entra ID only)
https://mysignins.microsoft.com0000000c-0000-0000-c000-000000000000tenants.read .defaultNoNo
https://portal.azure.comhttps://graph.windows.netrestricted_user_impersonation .defaultYesNo
https://portal.azure.comhttps://management.core.windows.netrestricted_user_impersonation .defaultNoNo
https://entra.microsoft.comhttps://graph.windows.netrestricted_user_impersonation .defaultYesNo
https://entra.microsoft.comhttps://management.core.windows.netrestricted_user_impersonation .defaultNoNo
https://myaccount.microsoft.com/https://graph.microsoft.comemail openid profile AuditLog.Read.All BitlockerKey.Read.All CrossTenantInformation.ReadBasic.All CrossTenantUserProfileSharing.ReadWrite.All Device.EnableDisableAccount.All Device.Read.All Group.Read.All Group.ReadWrite.All GroupMember.Read.All MailboxSettings.ReadWrite Organization.Read.All Policy.Read.All RoleManagement.ReadWrite.Directory User.Invite.All User.Read.All User.ReadBasic.All User.ReadWriteNoYes
(Entra ID only)
https://myaccount.microsoft.comhttps://graph.microsoft.comemail openid profile AuditLog.Read.All BitlockerKey.Read.All CrossTenantInformation.ReadBasic.All CrossTenantUserProfileSharing.ReadWrite.All Device.EnableDisableAccount.All Device.Read.All Group.Read.All Group.ReadWrite.All GroupMember.Read.All MailboxSettings.ReadWrite Organization.Read.All Policy.Read.All RoleManagement.ReadWrite.Directory User.Invite.All User.Read.All User.ReadBasic.All User.ReadWrite .defaultNoYes
(Entra ID only)
https://myaccount.microsoft.comhttps://graph.microsoft.comopenid profile AuditLog.Read.All BitlockerKey.Read.All CrossTenantInformation.ReadBasic.All CrossTenantUserProfileSharing.ReadWrite.All Device.EnableDisableAccount.All Device.Read.All Group.Read.All Group.ReadWrite.All GroupMember.Read.All MailboxSettings.ReadWrite Organization.Read.All Policy.Read.All RoleManagement.ReadWrite.Directory User.Invite.All User.Read.All User.ReadBasic.All User.ReadWriteNoYes
(Entra ID only)
https://myaccount.microsoft.comhttps://graph.windows.netrestricted_user_impersonation .defaultYesNo
https://cosmos.azure.comhttps://management.azure.comuser_impersonation .defaultNoYes
(ARM only)
https://portal.office.comhttps://graph.microsoft.comemail openid profile Calendars.Read Contacts.Read Family.Read Files.ReadWrite.All InformationProtectionPolicy.Read Notes.Create People.Read Presence.Read.All Sites.Read.All Tasks.ReadWrite User.Read User.ReadBasic.All .defaultNoYes
(Entra ID only)
https://portal.office.comhttps://x.sharepoint.comFiles.ReadWrite.All Sites.FullControl.All User.Read.All .defaultNoNo
https://portal.office.comhttps://outlook.office365.comsearch/SubstrateSearch-Internal.ReadWrite search/.defaultNoNo

Access token from the browser

Another way to grab an access token is to steal web session cookies. The cookie is then exchanged for an access token. Stealing cookies from a browser is very well described by Justin Bui in his article Hands in the Cookie Jar: Dumping Cookies with Chromium’s Remote Debugger Port. After that, roadtx by Dirkjan can be used, e.g. with the command roadtx interactiveauth --estscookie 0.AYIAQ --tokens-stdout -r msgraph -c azps to exchange the cookie for an access token. For example for Azurehound and RoadTools use for -r: msgraph, https://graph.windows.net or https://management.azure.com. For the -c any Family of Client IDs (FOCI) should work.

To prevent or make it more difficult for an attacker to execute the above methods as a user with low privileges, the developer tools and remote debugging can be disabled for most browsers via group policies.

From files or processes

Access tokens can also be extracted from files. For example Sander Maas discovered early on that Outlook for Windows (Yes only the new one) is storing refresh and as well access token under %localappdata%\Microsoft\Olk\EBWebView\Default\Session Storage\00000x.log. Older versions of the Azure CLI and other cmdlets stored access tokens in plain text at %USERPROFILE%\.azure. Still a good folder to check, because who updates PowerShell modules?

Access token in files

Access tokens can also be found in processes such as Outlook, Word, Teams, PowerShell, etc. The easiest way to do this is to dump the process via Task Manager and search for access tokens in the dump with sysinternals strings.exe and findstr /i eyJ0eX. Tokens issued for https://graph.microsoft.com can usualy be found and are usable for AzureHound.

Further reading or tools to automate the search and extraction of access tokens from processes:

From APIs

A simple way to get an access token is via the OAuth 2.0 Device Authorization Grant Flow. Further details how that works can be found in the article Hidden dangers of phishing attacks. Nowadays this flow can be blocked by Conditional Access policies.

There are other OAuth 2.0 grant flows from which an access token can be obtained. Such as the password credentials grant flow or others that are well documented under Microsoft identity platform app types and authentication flows. These flows can be used if the credentials are known or abused, for example by deploying a phishing application. A good read is Nyxgeek’s Creating a Malicious Entra ID OAuth2 Application.

From Cmdlets

There are several Azure or Entra ID-related cmdlets. Some of the cmdlets allow you to view/get the access token when a session has been cached or after a successful login.

TypeModule Command RoadRecon AzureHound
PowerShellAz.AccountsGet-AzAccessToken Yes Yes
Azure CLIazaz account get-access-token —resource=https://graph.microsoft.com —query accessToken -o tsv Yes Yes

The connect-mggraph cmdlet does not currently have a built-in method to display the access token. However, the process dump method can be used to extract the access token from an active PowerShell process that used the cmdlet connect-mggraph.

From the Microsoft Graph Explorer

If a cached session is open to Microsoft Graph Explorer, an access token can be extracted via the GUI. The access token cannot be used for the azurehound or roadtools tools. However, sometimes the Microsoft Graph Explorer application is allowed for all users and is therefore a good way to do an initial enumeration.

Access token from the Microsoft Graph Explorer

From Intercepting Web Traffic

Tools that can intercept web traffic, such as Proxies, Burp, Fiddler or Zap, can be used to intercept access tokens.

From Azure Cloud Resources

If a user has sufficient access to resources such as Azure Cloud Shell, Azure Cloud Shell images, Azure Automation RunAs accounts, DevOps pipelines, or a virtual machine that uses managed identities, it is often possible to extract the access token.

Access token from Azure Cloud Shell

Further readings:

Access Token Protection

If an access token is stolen, it can be used to access or manipulate data from anywhere on any device, bypassing any conditional access rules. Although Microsoft has or is implementing security features such as CAE or Token Protection to protect against access token theft by ensuring that a token can only be used by its intended device. However, these features do not support all 1st party cloud applications, and Token Protection currently only supports refresh tokens. The only promising feature that could protect against access token theft is Global Secure Access. We have not yet tested this preview feature, so we cannot say whether it will deliver what it promises.

The above methods for extracting access tokens, with the exception of device code authentication, malicious OAuth 2.0 applications, and Azure cloud resources, assume that an attacker is already on the device. However, this requires non-local administrator rights. Protecting the end device and especially the privileged users is therefore crucial. But hey, there is a simple trick for privileged users (e.g. tier-0), almost free, a bit annoying and not very fancy, it is called Privileged Access Workstation. If used, it is the strongest defense against token theft and solves the problem at the beginning namely where the keyboard sits.

In general and for non-privileged users, allowing access only from trusted and hardened endpoints, implementing recommended tenant security recommendations, handling credentials securely, and using phishing-resistant multi-factor authentication (MFA) is a good way to start making access token theft more difficult.

Further reading on protective measures:

Conclusion

As we have explored, there are several ways to obtain access tokens. If an attacker succeeds in obtaining a token, it may be valid for one hour or 24 hours. Enough time to exfiltrate data or install a backdoor for persistence, the latter depending on the user’s privileges.

There is currently no easy way to prevent the unauthorized use of access tokens, other than to make it difficult for an attacker to get close to a user with a privileged access token. This often starts with the old-fashioned but proven way of implementing a secure privileged access strategy. Done correctly, this would make it more difficult for an attacker to succeed. However, it is not uncommon in our security assessments to find privileged or mission-critical users using personal phones or even home computers to access the organization’s tenant. Similar mistakes were made with Active Directory in the past, when everyone was a domain admin and security hardening and token protection did not exist. At least there was the fortress methodology of firewalls protecting the environment from the Internet. But with the cloud, that methodology no longer fully works.

We have a different threat model when working with a cloud environment, the priority is at the endpoint where the user is either allowed or not allowed to access the cloud. Consequently, allowing access only from trusted and hardened endpoints, implementing tenant security recommendations, applying secure practices around privileged access, secure credential handling, using phishing-resistant multi-factor authentication (MFA), and an attackers mindset, to name a few, are the cornerstones of protecting cloud resources and the tokens required to access them.

About the Author

Marius Elmiger

Marius Elmiger is a security professional since the early 2000’s. He worked in various IT roles such as an administrator, engineer, architect, and consultant. His main activities included the implementation of complex IT infrastructure projects, implementation of security hardening concepts, and compromise recoveries. Later he transitioned to the offensive side. As a foundation, in addition to numerous IT certificates, Marius graduated with an MSc in Advanced Security & Digital Forensics at Edinburgh Napier University. (ORCID 0000-0002-2580-5636)

Links

You want to test the security of your firewall?

Our experts will get in contact with you!

×
Foreign Entra Workload Identities

Foreign Entra Workload Identities

Marius Elmiger

Credential Tiering

Credential Tiering

Marius Elmiger

Credential Tiering

Credential Tiering

Marius Elmiger

Hardware-Keylogger

Hardware-Keylogger

Marius Elmiger

You want more?

Further articles available here

You need support in such a project?

Our experts will get in contact with you!

You want more?

Further articles available here