Knowing the application secret of an Azure AD registered application allows for an interactive sign-in using the client credentials grant. The application ID corresponds to the user name and the application secret corresponds to the password, which is why the secret is also called the application password. If the registered application is a multi-tenant application, such a sign-in is possible in every tenant where consent was given for the application. The access token received from the sign-in can then be used in Microsoft Graph API calls made possible through application permissions.
For example, there is an application registered named jmprieur-dotnet-web-daemon-v2 with
- tenant where application is registered: 8b3c36dd-942d-4ea7-a4dd-df9ef430cf5a
- application ID: 5fdb1e39-be38-4cb1-8523-9d97365ed7de
- application secret: li.t14-00uhd9Ji~5a2a647D_h68F6sx11
- tenant where consent is given for application: 9cbada80-ca8c-43b1-8fb2-492cf58bccc9
The application has two delegated permissions and one application permission set up.
Microsoft recommends using an authentication library (like MSAL) for Azure AD authentication scenarios. Ignoring that, a simple HTTP POST request also gets an access token.
$postParams = @{
client_id='5fdb1e39-be38-4cb1-8523-9d97365ed7de';
client_secret='li.t14-00uhd9Ji~5a2a647D_h68F6sx11';
scope='https://graph.microsoft.com/.default';
grant_type='client_credentials'}
$accessToken = ((Invoke-WebRequest -Uri https://login.microsoftonline.com/9cbada80-ca8c-43b1-8fb2-492cf58bccc9/oauth2/v2.0/token -Method POST -Body $postParams).Content | ConvertFrom-Json).access_token
Note that the ‘scope’ parameter is required. Specifying ‘.default’ returns an access token that contains all application permissions. In the example it looks like this:
It can be seen that the access token contains the one application permission, but none of the delegation permissions. Consequently, in this example, the access token cannot be used to read a user’s mail, but it can be used to read all properties of all Azure AD accounts.
The manager of user ryan@resource-tenant.com can be found with the following REST call:
Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/users/ryan@resource-tenant.com/manager' -Headers @{'Authorization' = "Bearer " + $accessToken} -Method Get
This blog post is a small add-on to Jan Geisbauer‘s Privilege escalation in Azure AD article.