Notes on Microsoft 365 and Entra Active Directory
This post is intended to be a collection of resources, techniques and knowledge around security in Microsoft 365 and Microsoft Entra ID (formely Azure Active Directory). The post heavily relies on public resources.
The following topics are discussed:
- Identify Microsoft 365 subscription and tenantID
- Identify domains registered on a tenant
- Enumerate user accounts on Microsoft 365
- Notes on Active Directory Federation Services auditing
- Deliver emails to Office 365 bypassing third-party mail filtering
- Microsoft Exchange Online legacy protocols MFA check
- Entra ID attacks
- Service Principals in Microsoft Entra ID
- Microsoft Entra ID Overlooked Loopholes
- Conditional Access Policies
- Azure Arc
- References
Identify Microsoft 365 subscription and tenantID
One of the first questions that comes in mind when approaching simulated attacks, is if the targret organization has a Microsoft 365 subscription. To answer this question public APIs can be leveraged. Each tenant on Microsoft 365 has a unique identifier, namely GUID (Globally Unique IDentifier). This ID is publicly available. To get this information programatically, a GET request can be made to the following URI:
https://login.microsoftonline.com/<FQDN>/.well-known/openid-configuration
Fans of linux’s curl can do:
curl https://login.microsoftonline.com/<FQDN>/.well-known/openid-configuration
The response to the request, will have a structure similar to the listed below:
{
"token_endpoint": "https://login.microsoftonline.com/<GUID>/oauth2/token",
"token_endpoint_auth_methods_supported": [
"client_secret_post",
"private_key_jwt",
"client_secret_basic"
],
"jwks_uri": "https://login.microsoftonline.com/common/discovery/keys",
"response_modes_supported": [
"query",
"fragment",
"form_post"
],
"subject_types_supported": [
"pairwise"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"response_types_supported": [
"code",
"id_token",
"code id_token",
"token id_token",
"token"
],
"scopes_supported": [
"openid"
],
"issuer": "https://sts.windows.net/<GUID>/",
"microsoft_multi_refresh_token": true,
"authorization_endpoint": "https://login.microsoftonline.com/<GUID>/oauth2/authorize",
"device_authorization_endpoint": "https://login.microsoftonline.com/<GUID>/oauth2/devicecode",
"http_logout_supported": true,
"frontchannel_logout_supported": true,
"end_session_endpoint": "https://login.microsoftonline.com/<GUID>/oauth2/logout",
"claims_supported": [
"sub",
"iss",
"cloud_instance_name",
"cloud_instance_host_name",
"cloud_graph_host_name",
"msgraph_host",
"aud",
"exp",
"iat",
"auth_time",
"acr",
"amr",
"nonce",
"email",
"given_name",
"family_name",
"nickname"
],
"check_session_iframe": "https://login.microsoftonline.com/<GUID>/oauth2/checksession",
"userinfo_endpoint": "https://login.microsoftonline.com/<GUID>/openid/userinfo",
"kerberos_endpoint": "https://login.microsoftonline.com/<GUID>/kerberos",
"tenant_region_scope": "WW",
"cloud_instance_name": "microsoftonline.com",
"cloud_graph_host_name": "graph.windows.net",
"msgraph_host": "graph.microsoft.com",
"rbac_url": "https://pas.windows.net"
}
The PowerShell cmdlet Get-AADIntTenantID from AADInternals [1] will parse the output and print the GUID of the tenant, effectively providing the tenantID. If this cmdlet prints a GUID it can be safely concluded that the company behind the provided FQDN, has a Microsoft 365 subscription.
Identify domains registered on a tenant
A request to the URL listed below returns the domains registered from the tenant of the given domain. This information was pulled from [1].
For Threat Intelligence purposes, that means that if an attacker uses a Microsoft tenant to host phishing infrastructure (for example register phising domains), the following URL reveals additional domains. This information may become useful to attribute activity to a specific threat actor (threat actor that uses a single tenant to conduct phishing against multiple targets).
For teams that emulate attacker activities (attack simulation, red team) caution must be exercised to not use the same tenant for registering phishing domains used in different attacks or for different stages of an engagement. This will increase the operational security (OPSEC) of the engagement and contribute to the stealthiness.
https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc
Fans of Linux’s curl (body.txt contains the SOAP request):
curl -i -H “Content-Type:text/xml; charset=utf-8” -H ‘SOAPAction:”http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation”’ -H “User-Agent:AutodiscoverClient” -d @./body.txt “https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc”
Complete request (replace <DOMAIN> with the desired domain):
POST /autodiscover/autodiscover.svc HTTP/1.1
Host: autodiscover-s.outlook.com
Accept: */*
Content-Type:text/xml; charset=utf-8
SOAPAction: "http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation"
User-Agent: AutodiscoverClient
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:exm="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:ext="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<a:Action soap:mustUnderstand="1">http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation</a:Action>
<a:To soap:mustUnderstand="1">https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc</a:To>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
</soap:Header>
<soap:Body>
<GetFederationInformationRequestMessage xmlns="http://schemas.microsoft.com/exchange/2010/Autodiscover">
<Request>
<Domain><DOMAIN></Domain>
</Request>
</GetFederationInformationRequestMessage>
</soap:Body>
</soap:Envelope>
Sample response:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformationResponse</a:Action>
<h:ServerVersionInfo xmlns:h="http://schemas.microsoft.com/exchange/2010/Autodiscover" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<h:MajorVersion>15</h:MajorVersion>
<h:MinorVersion>20</h:MinorVersion>
<h:MajorBuildNumber>5332</h:MajorBuildNumber>
<h:MinorBuildNumber>17</h:MinorBuildNumber>
<h:Version>Exchange2015</h:Version>
</h:ServerVersionInfo>
</s:Header>
<s:Body>
<GetFederationInformationResponseMessage xmlns="http://schemas.microsoft.com/exchange/2010/Autodiscover">
<Response xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ErrorCode>NoError</ErrorCode><ErrorMessage/>
<ApplicationUri>outlook.com</ApplicationUri>
<Domains>
<Domain><DOMAIN1>.onmicrosoft.com</Domain>
<Domain><DOMAIN></Domain>
<Domain><DOMAIN1>.mail.onmicrosoft.com</Domain>
</Domains>
<TokenIssuers>
<TokenIssuer>
<Endpoint>https://login.microsoftonline.com/extSTS.srf</Endpoint>
<Uri>urn:federation:MicrosoftOnline</Uri>
</TokenIssuer>
</TokenIssuers>
</Response>
</GetFederationInformationResponseMessage>
</s:Body>
</s:Envelope>
Enumerate user accounts on Microsoft 365
It is possible to enumerate user accounts on Microsoft O365 [1], [3] by calling the API located at:
https://login.microsoftonline.com/common/GetCredentialType
The enumeration allows an attacker to identify valid users accounts in preparation for phishing.
The API enforces throttling and therefore if a large number of requests is to be made, a tool such as Fireprox [4] could allow attackers avoid this defense.
Sample request with curl:
curl -H “Content-Type: application/json; charset=UTF-8” -d ‘{“flowToken”:””,”isCookieBannerShown”:”false”,”isRemoteNGCSupported”:”false”,”originalRequest”:””,”isOtherIdpSupported”:”true”,”checkPhones”:”true”,”username”:”<USER_ACCOUNT>@<DOMAIN>”,”isFidoSupported”:”false”}’ “https://login.microsoftonline.com/common/GetCredentialType”
Sample request:
POST /common/GetCredentialType HTTP/1.1
Host: login.microsoftonline.com
Accept: */*
Content-Type: application/json; charset=UTF-8
Content-Length: 400
{
"flowToken":"",
"isCookieBannerShown":"false",
"isRemoteNGCSupported":"false",
"originalRequest":"",
"isOtherIdpSupported":"true",
"checkPhones":"true",
"username":"<USER_ACCOUNT>@<DOMAIN>",
"isFidoSupported":"false"
}
Body of sample Response if account exists (IfExistsResult equals 0):
{
"Username": "name.lastname@imaginary-fake-domain.com",
"Display": "name.lastname@imaginary-fake-domain.com",
"IfExistsResult": 0,
"IsUnmanaged": false,
"ThrottleStatus": 1,
"Credentials": {
"PrefCredential": 1,
"HasPassword": true,
"RemoteNgcParams": null,
"FidoParams": null,
"SasParams": null,
"CertAuthParams": null,
"GoogleParams": null,
"FacebookParams": null
},
"EstsProperties": {
"UserTenantBranding": [
{
"Locale": 0,
"BannerLogo": "https://aadcdn.msauthimages.net/<REDACTED>",
"Illustration": "https://aadcdn.msauthimages.net/<REDACTED>",
"KeepMeSignedInDisabled": false,
"UseTransparentLightBox": false
}
],
"DomainType": 3
},
"IsSignupDisallowed": true,
"apiCanary": "<REDACTED>"
}
Notes on Active Directory Federation Services auditing
To identify the FQDN of a ADFS server (the server may be internet-facing or sitting behind a proxy):
curl -s https://login.microsoftonline.com/common/userrealm/<USERNAME>@<DOMAIN>?api-version=2.0 | jq ‘.AuthURL’
Shodan and Censys provide a broader list of ADFS servers exposed (directly or through a proxy) to the internet.
To list the available ADFS endpoints use the federation metadata endpoint [5]:
curl https://<ADFS FQDN>/adfs/services/trust/mex
If either or both endpoints /adfs/services/trust/2005/windowstransport and /adfs/services/trust/13/windowstransport are available, they leak the internal hostname of the ADFS server (not the hostname of the proxy), including the Active Directory domain name. These endpoints support NTLM-based authentication for on-premises users and Microsoft recommends they should be intranet facing only [6]. Exposing these endpoints to the internet could allow attackers bypass account lockout protections.
After identifying the ADFS server and the endpoint it exposes, to identify the internal hostname and domain name acquiring information from NTLM tools such as Shodan (a form of passive scan - a third party does the scanning) or nmap (a form of active scan - the one who scans hits the scanned infrastructure) give the answer.
To retrieve disclosed NTLM information with nmap, the script http-ntlm-info is the way to go. For example:
nmap -sS -p 443 –script http-ntlm-info –script-args http-ntlm-info.root=/adfs/services/trust/2005/windowstransport <ADFS_server>
Or, in case the endpoint used above is not available:
nmap -sS -p 443 –script http-ntlm-info –script-args http-ntlm-info.root=/adfs/services/trust/13/windowstransport <ADFS_server>
Another interesting endpoint in terms of enumeration is /adfs/ls/idpinitiatedsignon.aspx. If enabled, this endpoint lists all the relying parties and provides an additional form for authentication. The list of relying parties may be utilised for spear phishing (targeted attacks) as in inspire lures related to relying parties.
Hybrid Environments
In hybrid environments authentication for valid accounts may not redirect to the ADFS server. If that’s the case, the following request returns null.
curl -s https://login.microsoftonline.com/common/userrealm/<USERNAME>@<DOMAIN>?api-version=2.0 | jq ‘.AuthURL’
To retrieve the ADFS FQDN repeat the request with an invalid email address.
Deliver emails to Office 365 bypassing third-party mail filtering
This section provides a methodology on how to bypass third-party mail filtering (if this is possible) to deliver an email to the Office 365 of tenant, leveraging publicly available information.
Organizations that migrate their email infrastructure to Office 365 often add an additional security layer by sending first the emails to a third-party mail filtering service (such as Proofpoint). However, due to misconfigurations it may still be possible to send an email directly to the tenant effectively bypassing the third-party filtering.
First things first. To identify what email fitlering service is used, first look at the MX record of a domain. Assuming Proofpoint services are used to filter incoming emails for the imaginary domain imaginary-prd-domain.com, the MX DNS record for imaginary-prd-domain.com should like:
;; ANSWER SECTION:
imaginary-prd-domain.com. 1800 IN MX 10 <SUBDOMAIN1>.pphosted.com.
imaginary-prd-domain.com. 1800 IN MX 10 <SUBDOMAIN2>.pphosted.com.
Next step is to identify if the imaginary domain is linked to Microsoft cloud infrastructure. For this, the cmdlet Get-AADIntTenantID [1] provides the answer.
Get-AADIntTenantID -Domain imaginary-prd-domain.com
After confirming that the domain is linked to a tenant, next is to identify all the domains that are registered from that tenant. If the MX record for the domain formatted as .onmicrosoft.com points to the domain formatted as *.mail.protection.outlook.com that indicates that Office 365 is used for emails. The list of registered domains under the tenant, is:
Get-AADIntTenantDomains -Domain imaginary-prd-domain.com
Run through the list of domains the above cmdlet returns and look for .onmicrosoft.com. Assuming this is imaginary-prd-domain.onmicrosoft.com, the next step is to check the MX record for that domain:
dig mx imaginary-prd-domain.onmicrosoft.com
If the result includes the domain mail.protection.outlook.com that means Office 365 is used for email delivery. Therefore, if the mail filtering is not configured properly, it may be possible to send emails directly to <DOMAIN>.mail.protection.outlook.com.
The next step in the process is to identify the address to send the email. To find this information, traverse the MX record of the <DOMAIN>.mail.onmicrosoft.com domain. This is in the form:
<DOMAIN>.mail.protection.outlook.com
The IP address the domain listed above resolves to is the destination address.
The information posted in this section was acquired from [2].
Microsoft Exchange Online legacy protocols MFA check
When the user agent BAV2ROPC is send along with an authentication request to Microsoft Exchange Online, the ROPC OAuth [9] flow is initiated. If invalid_grant
is returned, this is indicative that MFA is enabled.
Attackers have used this technique to identify if MFA is enabled [8] and avoid other services that may be sitting behind MFA. For an attacker with valid credential this could lead to Business Email Compromise (BEC).
The request to check this:
POST {tenant}/oauth2/v2.0/token
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
User-Agent: BAV2ROPC
client_id=6731de76-14a6-49ae-97bc-6eba6914391e&scope=user.read%20openid%20profile%20offline_access&username=MyUsername@imaginaryclientname.com&password=SuperS3cret&grant_type=password
Entra ID attacks
This section is a short summary of two detailed posts published on dirkjanm.io
, specifically [10], [11].
An attacker can use device code phishing to acquire an access (comes with a refresh token) for the client ID (application):
- 29d9ed98-a469-4536-ade2-f981bc1d605e (Microsoft Authentication Broker)
Attack path #1 - Device Registration
With the refresh token acquired by phishing for client ID 29d9ed98-a469-4536-ade2-f981bc1d605e
and resource urn:ms-drs:enterpriseregistration.windows.net
an attacker could then register (and not join) a new device on the Entra tenant.
The result of the registration process creates a certificate (pem format) and a private key.
Using the same refresh token acquired by device registration phishing and the newly created certificate and private key, an attacker can request a Primary Refresh Token (PRT). The PRT can be used in a browser to request access tokens for applications and services for which the Entra ID acts as the identity provider (applications registered on the tenant). This PRT acts like a TGT on an on-premises Active Directory environment. Effectively, it offers persistence and lateral movement opporunities to attackers.
The process is the same as when a user provides their credentials on a Entra-joined or a hybrid-joined device. In this authentication flow after the initial login occurs, the user opens their browser and can then browse to cloud resources such as myapps.microsoft.com
. From there, they can browse to Microsoft and third-party cloud applications that are registered on the organization’s tenant. If Conditional Access Policies (CAPs) do not enforce certain controls (like MFA, compliant device, IP restrictions), the user is allowed to authenticate and access these apps. This is the reason why this attack path can be impactful.
Defenses
A strong mix of Conditional Access Policies (CAP) can provide sufficient protection against identity attacks. More specifically by:
- Blocking or, if that’s not a feasible option, monitoring closely instead device code authentication flows. Microsoft provides relevant guidance in [21].
- Requiring MFA authentication for device registration. Microsoft provides relevant guidance in [22]. To allow users to register a device themselves, Temporary Access Pass (TAP) can be used to get past the MFA requirement [23].
- Configuring frequent reauthentication, especially for sensitive applications such as administrative portals and applications that host sensitive data.
- Requiring a compliant device to access sensitive applications. This will block access to protected applications from non-compliant devices.
Service Principals in Microsoft Entra ID
Service Principals can be unnecessarily privileged and lead to a tenant compromise. Documented examples of exploitation paths for Service principals can be found in [15] (which could also be considered an evolution of [14]).
To authenticate using a service principal:
az login --service-principal --username <clientID> --password <client_secret> --tenant <tenantID>
List all subscriptions for the logged in account:
az account list --all
List all Azure Arc connected devices [14]:
az connectedmachine list –resource-group <RG_name>
Microsoft Entra ID Overlooked Loopholes
This section discusses configuration gaps in Microsoft Entra ID configurations that could allow attackers to compromise the security of environments that rely on it for identity and access management.
The section is divided in the following sub-sections:
- Conditional Access Policy Bypass via Group Membership Changes
- MFA Not Enforced On Additional Authenticator App Registration
Conditional Access Policy Bypass via Group Membership Changes
Issue: Bypass of Conditional Access Policy enforcement by group membership change
Let’s assume that an organization enforces Conditional Access Policies (CAPs). CAPs - by design - can only be changed by users that have the Conditional Access Administrator role. The organization additionally excludes specific user groups from certain CAPs. This condition effectively creates a loophole, in which users with the Groups Administrator role (or similarly privileged accounts) can add users to groups that are excluded from CAPs (such as multi-factor authenticator, compliant device requirement, location restrictions).
To mitigate this gap:
- Avoid group exclusions in CAPs unless absolutely necessary.
- Monitor group changes to sensitive groups, especially those used in CAP exclusions.
- Perform regular access reviews to verify if exclusions and membership to CAP-excluded groups is justified.
- Use Privileged Identity Management (PIM) to manage membership in sensitive CAP-excluded groups.
MFA Not Enforced On Additional Authenticator App Registration
Issue: Security Info Registration is only protected by a valid session - no fresh MFA claim is required
Although MFA is absolutely a strong protection against identity attacks, certain configuration gaps in the security info registration process, could open the door to actions that undermine that protection. More specifically, if an attacker has managed to access Security Info through mysignins.microsoft.com
, they could then add an additional - attacker-controlled - authenticator app. Access to mysignins.microsoft.com
could be achieved if an attacker possesses the Primary Refresh Token (PRT) of an account, for example after connecting to a host using RDP. This PRT serves as a JWT for SSO applications [19]. Effectively, with a valid session token and the MFA requirement met, an attacker could then meet Conditional Access Policies (CAPs) and further access sensitive resources. Clearly, the impact can be greater if the attacker also possess account credentials.
To mitigate this gap:
- Require MFA for user action Register security information [16]. Configure Temporary Access Pass (TAP) to allow users to register MFA [17].
- Monitor audit logs for updates on user authentication methods and inform relevant admins, security teams and the affected users.
- Configure additional CAPs, such as compliant device and IP restrictions to protect administrative portals (Azure Portal, Microsoft Administration Center, Microsoft Entra Admin Center) and applications that store sensitive data.
Conditional Access Policies
- Conditional Access Policies can be applied on Service Principals (also known as Workload Identities). Official documentation located at: Conditional Access for workload identities
- Guide for reauthentication enforcement on Privileged Identity Management (PIM) via CAP at: Step-by-Step Guide: How to setup conditional access reauthentication policy for PIM?
- Conditional Access Policy for blocking device code and authentication transfer at: Block authentication flows with Conditional Access policy
Azure Arc
Links that cover various aspects of Azure Arc:
- Identifying and abusing Azure Arc for hybrid escalation and persistence
- LOLCLOUD - Azure Arc - C2aaS
- Azure Arc – Part 1 – Escalation from On-Premises to Cloud
- Azure Arc – Part 2 – Escalation from Cloud to On-Premises
- Azure Arc – Part 3 – General Security Considerations
- busing Azure Arc: From Service Principal Exposed to Reverse Shell
- Abusing Azure Arc for lateral movement
- Extracting Managed Identity Certificates from the Azure Arc Service
- Abusing Azure Hybrid Workers for Privilege Escalation – Part 1
References
[1] https://o365blog.com/
[2] https://practical365.com/how-to-ensure-your-third-party-filtering-gateway-is-secure/
[3] https://warroom.rsmus.com/enumerating-emails-via-office-com/
[4] https://github.com/ustayready/fireprox
[5] https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-endpoints
[6] https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/deployment/best-practices-securing-ad-fs#disable-ws-trust-windows-endpoints-on-the-proxy-ie-from-extranet
[7] https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-initiatedsignon
[8] https://www.microsoft.com/security/blog/2021/06/14/behind-the-scenes-of-business-email-compromise-using-cross-domain-threat-data-to-disrupt-a-large-bec-infrastructure/
[9] https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
[10] https://dirkjanm.io/phishing-for-microsoft-entra-primary-refresh-tokens/
[11] https://github.com/dirkjanm/ROADtools
[12] https://www.microsoft.com/en-us/security/blog/2025/02/13/storm-2372-conducts-device-code-phishing-campaign/
[13] https://learn.microsoft.com/en-us/entra/identity/conditional-access/policy-all-users-device-compliance
[14] https://medium.com/@r3n_hat/abusing-azure-arc-for-lateral-movement-39a1b56cbf2b
[15] https://xybytes.com/azure/Abusing-Azure-Arc/
[16] https://learn.microsoft.com/en-us/entra/identity/conditional-access/policy-all-users-security-info-registration
[17] https://learn.microsoft.com/en-us/entra/identity/authentication/howto-authentication-temporary-access-pass
[18] https://techcommunity.microsoft.com/blog/itopstalkblog/step-by-step-guide-how-to-setup-conditional-access-reauthentication-policy-for-p/4421881
[19] https://medium.com/understanding-and-attacking-hybrid-environments/part-5-primary-refresh-token-prt-rdp-cloudap-lsass-deep-dive-3b64b8392e7d
[20] https://syfuhs.net/how-azure-ad-windows-sign-in-works
[21] https://learn.microsoft.com/en-us/entra/identity/conditional-access/policy-block-authentication-flows
[22] https://learn.microsoft.com/en-us/entra/identity/conditional-access/policy-all-users-device-registration
[23] https://learn.microsoft.com/en-us/entra/identity/authentication/howto-authentication-temporary-access-pass
tags:#Microsoft 365 and Microsoft Entra ID