Phase 1 Checklist

0 / 8 completed
Authorised Testing Only. All techniques in this guide must be performed only against tenants you have explicit written authorisation to test. Reconnaissance activities, even passive ones, should be documented in your rules of engagement. Some user enumeration techniques may trigger Azure AD sign-in logs or Smart Lockout.

🔍 Tenant Discovery

1 Domain Enumeration

The first objective is to discover every domain associated with the target's Microsoft 365 tenant. Organisations often register multiple domains (primary, regional, vanity, subsidiary) under a single Entra ID tenant. Each domain is a potential attack surface.

AADInternals dig / nslookup crt.sh whois Amass

AADInternals — Enumerate Tenant Domains

This queries the Microsoft autodiscover and federation endpoints to return all domains registered under the tenant associated with the given domain. No authentication is required.

PowerShell
# Install AADInternals if not already present
Install-Module AADInternals -Scope CurrentUser
Import-Module AADInternals

# Enumerate all domains registered in the target tenant
Get-AADIntTenantDomains -Domain "targetcompany.com"

# Example output:
# targetcompany.com
# targetcompany.onmicrosoft.com
# targetcompany.mail.onmicrosoft.com
# subsidiary-brand.com
# targetcompany.co.uk

DNS-Based Domain Validation

Verify Microsoft 365 usage by checking for well-known DNS records that Microsoft requires for domain verification and service routing.

Bash
# Check for Microsoft domain verification TXT record
dig TXT targetcompany.com +short
# Look for: "MS=ms12345678" or "v=spf1 include:spf.protection.outlook.com"

# Check for the msoid CNAME (Microsoft Online ID)
dig CNAME msoid.targetcompany.com +short
# Resolves to: clientconfig.microsoftonline-p.net

# Check Autodiscover CNAME (Exchange Online)
dig CNAME autodiscover.targetcompany.com +short
# Resolves to: autodiscover.outlook.com

# Check for DMARC policy
dig TXT _dmarc.targetcompany.com +short
# Reveals mail handling policies and reporting addresses

Certificate Transparency Logs

Query certificate transparency (CT) logs to discover subdomains and related domains that may share the same tenant. Certificates issued for Microsoft-hosted services can reveal additional domain names.

Bash
# Query crt.sh for certificate transparency logs
curl -s "https://crt.sh/?q=%25.targetcompany.com&output=json" | \
  jq -r '.[].name_value' | sort -u

# Use Amass for comprehensive subdomain enumeration
amass enum -passive -d targetcompany.com -o subdomains.txt

# Search for related domains via WHOIS registrant data
whois targetcompany.com | grep -i "registrant"
💡
Tip: The .onmicrosoft.com domain is always present and cannot be removed. It is often the initial tenant domain and may follow a predictable naming convention such as companyname.onmicrosoft.com. Discovering this domain confirms Microsoft 365 usage and provides a reliable identifier for the tenant.
🛡
Defender Note: Domain enumeration via Get-AADIntTenantDomains uses public Microsoft endpoints and does not generate sign-in logs. Consider whether your organisation's subsidiary and vanity domains need to be associated with the primary tenant, or whether they should be isolated. Unused domains that remain verified in your tenant increase your attack surface.
2 Tenant ID Discovery

Every Entra ID (Azure AD) tenant has a globally unique identifier (GUID). Knowing the tenant ID allows you to query specific Microsoft APIs, target the correct authorization endpoints, and distinguish between tenants when an organisation has multiple.

OpenID Configuration AADInternals curl

OpenID Configuration Endpoint

Microsoft publishes an OpenID Connect discovery document for every tenant. This document is publicly accessible and contains the tenant ID embedded in the issuer and authorization endpoint URLs.

Bash
# Retrieve the OpenID configuration for the target domain
curl -s "https://login.microsoftonline.com/targetcompany.com/.well-known/openid-configuration" | \
  jq '.authorization_endpoint'

# Example output:
# "https://login.microsoftonline.com/a1b2c3d4-e5f6-7890-abcd-ef1234567890/oauth2/v2.0/authorize"
# The GUID in the URL is the tenant ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890

# Extract just the tenant ID
curl -s "https://login.microsoftonline.com/targetcompany.com/.well-known/openid-configuration" | \
  jq -r '.token_endpoint' | grep -oP '[a-f0-9-]{36}'

AADInternals — Get Tenant ID

PowerShell
# Resolve tenant ID from any verified domain
Get-AADIntTenantID -Domain "targetcompany.com"

# Example output:
# a1b2c3d4-e5f6-7890-abcd-ef1234567890

# You can also resolve from the onmicrosoft.com domain
Get-AADIntTenantID -Domain "targetcompany.onmicrosoft.com"

Alternative: Login Error Endpoint

Another approach uses the Azure AD login endpoint, which will redirect and expose the tenant ID in the response even for invalid requests.

Bash
# Use the OAuth2 authorize endpoint with a dummy client_id
curl -s -I "https://login.microsoftonline.com/targetcompany.com/oauth2/v2.0/authorize?client_id=test&response_type=code&redirect_uri=https://localhost" | \
  grep -i "location"

# The redirect URL in the Location header contains the tenant ID

# You can also query the login metadata endpoint
curl -s "https://login.microsoftonline.com/getuserrealm.srf?login=user@targetcompany.com" | jq '.'
# Returns: NameSpaceType (Managed/Federated), DomainName, FederationBrandName, CloudInstanceName
💡
Tip: The getuserrealm.srf endpoint also reveals whether the domain uses Managed authentication (cloud-only passwords in Entra ID) or Federated authentication (ADFS, PingFederate, Okta, etc.). This distinction is critical for planning credential attacks in later phases.
🛡
Defender Note: The OpenID configuration and tenant ID are public by design and cannot be hidden. Focus your defensive effort on ensuring that knowledge of the tenant ID does not provide an advantage — enforce Conditional Access policies, disable legacy authentication protocols, and ensure all exposed endpoints require MFA.
3 Service Enumeration

Determine which Microsoft 365 services are active for the target tenant. Each service exposes distinct attack surfaces. DNS records are the primary indicator because Microsoft requires specific records for each service to function.

dig / nslookup dnsrecon AADInternals

M365 Service DNS Fingerprints

Each M365 service requires specific DNS records. Checking for these records reveals which services are provisioned and actively configured.

Service DNS Record Record Type Expected Value
Exchange Online autodiscover.domain.com CNAME autodiscover.outlook.com
Exchange Online domain.com MX *.mail.protection.outlook.com
SharePoint Online domain.com CNAME *.sharepoint.com
Skype / Teams lyncdiscover.domain.com CNAME webdir.online.lync.com
Skype / Teams _sipfederationtls._tcp.domain.com SRV sipfed.online.lync.com
Skype / Teams sip.domain.com CNAME sipdir.online.lync.com
Intune / MDM enterpriseregistration.domain.com CNAME enterpriseregistration.windows.net
Intune / MDM enterpriseenrollment.domain.com CNAME enterpriseenrollment.manage.microsoft.com
DKIM (Exchange) selector1._domainkey.domain.com CNAME selector1-domain-com._domainkey.*.onmicrosoft.com

Automated DNS Service Check

Bash
#!/bin/bash
# Enumerate M365 services for a target domain
DOMAIN="targetcompany.com"

echo "[*] Checking Exchange Online..."
dig CNAME autodiscover.${DOMAIN} +short
dig MX ${DOMAIN} +short

echo "[*] Checking Teams / Skype for Business..."
dig CNAME lyncdiscover.${DOMAIN} +short
dig SRV _sipfederationtls._tcp.${DOMAIN} +short
dig CNAME sip.${DOMAIN} +short

echo "[*] Checking Intune / MDM Enrollment..."
dig CNAME enterpriseregistration.${DOMAIN} +short
dig CNAME enterpriseenrollment.${DOMAIN} +short

echo "[*] Checking DKIM..."
dig CNAME selector1._domainkey.${DOMAIN} +short
dig CNAME selector2._domainkey.${DOMAIN} +short

echo "[*] Checking SPF Record..."
dig TXT ${DOMAIN} +short | grep "spf"

echo "[*] Checking Microsoft Online ID..."
dig CNAME msoid.${DOMAIN} +short

SharePoint & OneDrive URL Discovery

SharePoint Online tenant URLs follow a predictable format. You can confirm their existence by making unauthenticated HTTP requests.

Bash
# Attempt to resolve the SharePoint Online tenant URL
# The tenant name is usually the onmicrosoft.com prefix
curl -s -o /dev/null -w "%{http_code}" "https://targetcompany.sharepoint.com"
# 200/302 = exists, 404 = does not exist

# Check for OneDrive (uses the -my suffix)
curl -s -o /dev/null -w "%{http_code}" "https://targetcompany-my.sharepoint.com"

# Check for common SharePoint site naming patterns
for site in intranet portal hr wiki team; do
  curl -s -o /dev/null -w "$site: %{http_code}\n" \
    "https://targetcompany.sharepoint.com/sites/${site}"
done
💡
Tip: The presence of enterpriseregistration and enterpriseenrollment CNAMEs indicates that Intune MDM is configured, which means device compliance policies are likely in place. This is relevant for later phases when you may need to bypass device-based Conditional Access policies.
🛡
Defender Note: Remove DNS records for services you no longer use. Dangling CNAME records (pointing to deprovisioned Microsoft services) can be exploited for subdomain takeover attacks. Regularly audit your DNS zone for stale records. Consider using dnsrecon against your own domains as part of your security hygiene checks.

👤 User Enumeration

4 Username Harvesting

Before attempting to validate accounts, you need a list of candidate usernames. Microsoft 365 accounts typically follow an email format such as first.last@domain.com or flast@domain.com. OSINT sources provide the raw names; you then generate candidate UPNs (User Principal Names) matching the organisation's email format.

LinkedIn hunter.io linkedin2username theHarvester crosslinked

LinkedIn Employee Scraping

LinkedIn is the most reliable source of employee names. Tools like linkedin2username automate the process of scraping employee names and generating email addresses in common formats.

Bash
# linkedin2username - generate usernames from LinkedIn company page
# Requires valid LinkedIn session cookie
python3 linkedin2username.py -u "your-linkedin-email" -c "Target Company" -d "targetcompany.com"

# Output generates multiple format files:
# first.last@targetcompany.com
# flast@targetcompany.com
# firstl@targetcompany.com
# first_last@targetcompany.com

# CrossLinked - alternative LinkedIn scraper (no API key needed)
python3 crosslinked.py -f '{first}.{last}@targetcompany.com' "Target Company"
python3 crosslinked.py -f '{f}{last}@targetcompany.com' "Target Company"

hunter.io & Email Format Discovery

hunter.io reveals the email format used by an organisation and provides verified email addresses found in public sources.

Bash
# Query hunter.io API for email pattern and known addresses
curl -s "https://api.hunter.io/v2/domain-search?domain=targetcompany.com&api_key=YOUR_API_KEY" | \
  jq '.data.pattern, .data.emails[].value'

# Example pattern result: "{first}.{last}"
# This tells you the email format is first.last@targetcompany.com

theHarvester — Comprehensive OSINT

Bash
# theHarvester - search multiple data sources for emails and subdomains
theHarvester -d targetcompany.com -b all -l 500 -f harvester_results

# Sources include: Google, Bing, Baidu, DNSDumpster,
# CertSpotter, Crtsh, LinkedIn, Twitter, and more

# Also check for emails in public breach databases (legal/ethical consideration)
# dehashed.com, haveibeenpwned.com (domain search)

Company Website & Documents

Author metadata in publicly available documents (PDFs, DOCX, XLSX) often contains internal usernames or full names that can be converted to email addresses.

Bash
# Use exiftool to extract metadata from downloaded documents
exiftool -Author -Creator -Producer -LastModifiedBy *.pdf *.docx *.xlsx

# Use Google dorks to find documents from the target domain
# site:targetcompany.com filetype:pdf
# site:targetcompany.com filetype:docx
# site:targetcompany.com filetype:xlsx

# Metagoofil - automates document metadata extraction
metagoofil -d targetcompany.com -t pdf,docx,xlsx -l 100 -o metadata_output
Caution: LinkedIn scraping may violate LinkedIn's terms of service. Ensure your rules of engagement and legal authorisation cover OSINT activities. Consider whether passive approaches (manually browsing LinkedIn) are more appropriate than automated scraping tools for your engagement.
🛡
Defender Note: Educate employees about LinkedIn privacy settings. Strip metadata from documents before public publication using tools such as mat2 or built-in Office metadata removal. Consider monitoring for bulk scraping activity against your corporate LinkedIn page. Be aware that your email format is essentially public knowledge.
5 User Validation

After harvesting candidate usernames, you need to validate which ones actually exist in the target Entra ID tenant. Microsoft exposes several endpoints that allow username enumeration without requiring a password attempt, making this a stealthy reconnaissance technique.

GetCredentialType API o365creeper AADInternals TeamFiltration

GetCredentialType API

The GetCredentialType endpoint is the primary method for unauthenticated user enumeration. It is the same endpoint that the Microsoft login page calls to determine how to authenticate a user. It returns different response codes depending on whether a username exists.

Bash
# GetCredentialType API - validate a single username
curl -s -X POST \
  "https://login.microsoftonline.com/common/GetCredentialType" \
  -H "Content-Type: application/json" \
  -d '{"Username":"user@targetcompany.com"}' | jq '.'

# Key response fields:
# IfExistsResult: 0 = user EXISTS, 1 = user does NOT exist
# IfExistsResult: 5 = exists but in different tenant, 6 = exists (catch-all)
# ThrottleStatus: 1 = you are being throttled (slow down)

Bulk Enumeration with o365creeper

Bash
# o365creeper - bulk email validation against Office 365
python3 o365creeper.py -f userlist.txt -o valid_users.txt

# userlist.txt contains one email per line:
# john.smith@targetcompany.com
# jane.doe@targetcompany.com
# admin@targetcompany.com
# it.helpdesk@targetcompany.com

# valid_users.txt will contain only confirmed accounts

AADInternals — User Enumeration

AADInternals provides a dedicated function that uses multiple Microsoft endpoints (GetCredentialType, autodiscover, and others) to validate users.

PowerShell
# Enumerate a single user
Invoke-AADIntUserEnumerationAsOutsider -UserName "user@targetcompany.com"

# Bulk enumerate from a file
Get-Content ".\userlist.txt" | Invoke-AADIntUserEnumerationAsOutsider | Format-Table

# Example output:
# UserName                        Exists
# --------                        ------
# john.smith@targetcompany.com    True
# fake.user@targetcompany.com     False
# admin@targetcompany.com         True
# jane.doe@targetcompany.com      True

# The function checks multiple methods:
# - GetCredentialType (login.microsoftonline.com)
# - Autodiscover (outlook.office365.com)
# - Azure AD Graph (desktopsso endpoint)

TeamFiltration — Teams Enumeration

TeamFiltration can validate users via the Microsoft Teams user search API. This method can sometimes bypass protections applied to the GetCredentialType endpoint.

Bash
# TeamFiltration - enumerate users via Teams API
# Requires a valid Teams token (from any tenant)
TeamFiltration --enum --userlist userlist.txt --token teams_token.txt

# This uses the Teams people search API to check if users exist
# It can also pull profile pictures and presence information
Throttling: Microsoft applies rate limiting to the GetCredentialType endpoint. If ThrottleStatus returns 1 in the response, your requests are being throttled and all results will appear as "user does not exist" regardless of reality. Slow down your enumeration rate to approximately 1 request per second, use rotating source IPs, or switch to an alternative enumeration method.
🛡
Defender Note: Microsoft does not log GetCredentialType requests in Azure AD sign-in logs by default, making this difficult to detect. However, defenders can: (1) Monitor for anomalous patterns at the network/WAF level if using a reverse proxy. (2) Enable Azure AD Identity Protection which may flag enumeration patterns. (3) Consider configuring a tenant-wide policy to disable user existence disclosure where possible. (4) Use Smart Lockout to throttle enumeration attempts automatically.
6 Identifying Authentication Methods

The GetCredentialType response contains far more than just user existence. It reveals the authentication methods configured for each user, including whether MFA is required, what type of MFA is configured, and whether the account uses federation. This intelligence is invaluable for planning credential attacks.

GetCredentialType API AADInternals MFASweep

Parsing GetCredentialType Responses

Bash
# Full GetCredentialType request with detailed fields
curl -s -X POST \
  "https://login.microsoftonline.com/common/GetCredentialType" \
  -H "Content-Type: application/json" \
  -d '{
    "Username": "user@targetcompany.com",
    "isOtherIdpSupported": true,
    "checkPhones": true,
    "isRemoteNGCSupported": true,
    "isCookieBannerShown": false,
    "isFidoSupported": true,
    "originalRequest": "",
    "flowToken": ""
  }' | jq '.'

Response Field Analysis

Key fields in the GetCredentialType response and what they reveal about the target account:

Field Value Meaning
IfExistsResult 0 Account exists in tenant
IfExistsResult 1 Account does not exist
IfExistsResult 5 Account exists in a different tenant
IfExistsResult 6 Account exists (domain-level match)
ThrottleStatus 1 Requests are being throttled
Credentials.PrefCredential 1 Password-based authentication
Credentials.PrefCredential 4 FIDO2 / Windows Hello preferred
Credentials.HasPassword true/false Whether account has a password set
EstsProperties.DesktopSsoEnabled true Seamless SSO is configured (indicates on-prem AD)
FederationRedirectUrl URL present Account uses federated authentication (ADFS, etc.)

Automated Auth Method Enumeration

Python
# Simple Python script to check auth methods for a list of users
import requests, json, sys, time

url = "https://login.microsoftonline.com/common/GetCredentialType"

with open(sys.argv[1]) as f:
    users = [line.strip() for line in f if line.strip()]

for user in users:
    body = {
        "Username": user,
        "isOtherIdpSupported": True,
        "checkPhones": True,
        "isRemoteNGCSupported": True,
        "isFidoSupported": True
    }
    resp = requests.post(url, json=body).json()

    exists = resp.get("IfExistsResult", -1)
    has_pw = resp.get("Credentials", {}).get("HasPassword", "N/A")
    fed_url = resp.get("Credentials", {}).get("FederationRedirectUrl")
    pref = resp.get("Credentials", {}).get("PrefCredential", -1)
    sso = resp.get("EstsProperties", {}).get("DesktopSsoEnabled")
    throttle = resp.get("ThrottleStatus", 0)

    status = "EXISTS" if exists == 0 else "NOT_FOUND"
    fed = "FEDERATED" if fed_url else "MANAGED"

    print(f"{user} | {status} | {fed} | HasPW:{has_pw} | PrefCred:{pref} | SSO:{sso}")

    if throttle == 1:
        print("[!] THROTTLED - sleeping 30s")
        time.sleep(30)
    else:
        time.sleep(1)  # Rate limit to avoid throttling

MFASweep — MFA Configuration Check

Once you have valid credentials (in later phases), MFASweep can test which MFA methods are configured and whether any authentication endpoints lack MFA enforcement.

PowerShell
# MFASweep - test MFA enforcement across various Microsoft endpoints
# Run this once you have valid credentials (post Phase 3)
Import-Module MFASweep.ps1
Invoke-MFASweep -Username "user@targetcompany.com" -Password "Password123"

# MFASweep tests these endpoints for MFA enforcement:
# - Microsoft Graph API
# - Azure Service Management API
# - Microsoft 365 Exchange Web Services
# - Microsoft 365 Web Portal
# - Microsoft 365 Active Sync
# - ADFS (if federated)
💡
Tip: Accounts that show HasPassword: false are likely passwordless accounts using FIDO2 keys or Windows Hello. These are harder to attack via traditional credential spraying. Prioritise accounts with HasPassword: true and PrefCredential: 1 (password-based) for Phase 3 attacks. Accounts showing a FederationRedirectUrl authenticate through an external IdP, so credential attacks should target that federation endpoint instead.
🛡
Defender Note: The GetCredentialType response leaks substantial information about your authentication configuration. While this cannot be fully prevented, you can reduce risk by: (1) Enabling Conditional Access policies that enforce MFA on all cloud apps, not just selected ones. (2) Moving toward passwordless authentication (FIDO2, Windows Hello) to make sprayed credentials useless. (3) Deploying Azure AD Identity Protection to detect and respond to suspicious sign-in patterns. (4) Using break-glass accounts with non-standard UPN formats that are unlikely to be guessed.

🖧 Infrastructure Mapping

7 Azure / M365 IP Range Discovery

Identifying the IP ranges and infrastructure associated with the target's Azure and Microsoft 365 deployment helps map their external footprint. SPF records reveal mail infrastructure, MX records show mail routing, and Azure IP ranges can indicate deployed resources.

dig / nslookup curl Microsoft Endpoints Shodan

SPF Record Analysis

SPF (Sender Policy Framework) records list the IP addresses and services authorised to send email for a domain. This reveals the target's mail infrastructure and any third-party email services they use.

Bash
# Retrieve and analyze the SPF record
dig TXT targetcompany.com +short | grep "spf"

# Example output:
# "v=spf1 include:spf.protection.outlook.com include:_spf.google.com ip4:203.0.113.0/24 -all"

# This tells us:
# - Exchange Online is used (spf.protection.outlook.com)
# - Google Workspace may also be in use (_spf.google.com)
# - 203.0.113.0/24 is an on-prem or third-party mail server

# Recursively resolve all SPF includes to get full IP list
dig TXT spf.protection.outlook.com +short
dig TXT spfa.protection.outlook.com +short
dig TXT spfb.protection.outlook.com +short

# Check MX records for mail routing
dig MX targetcompany.com +short
# Example: 10 targetcompany-com.mail.protection.outlook.com.
# Points to Exchange Online Protection (EOP)

Azure IP Range Identification

If the target has Azure resources, you can identify their IP ranges by querying the published Azure IP ranges and cross-referencing with information gathered from DNS, headers, and other sources.

Bash
# Download Microsoft's published IP ranges for Azure/M365
# The URL changes weekly; get the latest from the download page
curl -s "https://www.microsoft.com/en-us/download/details.aspx?id=56519"

# Alternatively, use the service tag discovery API
curl -s "https://download.microsoft.com/download/7/1/D/71D86715-5596-4529-9B13-DA13A5DE5B63/ServiceTags_Public_20250106.json" | \
  jq '.values[] | select(.name == "AzureCloud") | .properties.addressPrefixes[:10]'

# Search Shodan for the target's Azure-hosted assets
shodan search "ssl.cert.subject.cn:targetcompany.com"
shodan search "org:\"Target Company\" cloud:azure"

# Check if the target has Azure Front Door, App Gateway, etc.
dig A targetcompany.com +short
# If it resolves to Azure IP ranges, they have Azure-hosted web resources

# Check for Azure Blob Storage
curl -s -o /dev/null -w "%{http_code}" "https://targetcompany.blob.core.windows.net"

Exchange Online IP & Header Analysis

Bash
# If you can send an email to the target and receive a bounce or auto-reply,
# examine the email headers for routing information

# Headers to look for:
# X-MS-Exchange-Organization-AuthSource: reveals internal Exchange server names
# X-OriginatorOrg: targetcompany.com (confirms the tenant domain)
# X-MS-Exchange-CrossTenant-Id: a1b2c3d4-... (reveals tenant GUID)
# Received: from ... by ... with Microsoft SMTP Server
# X-Microsoft-Antispam: reveals EOP/Defender configuration

# Resolve the Exchange Online Protection (EOP) endpoint
dig A targetcompany-com.mail.protection.outlook.com +short
💡
Tip: If the SPF record includes IP ranges outside of Microsoft (e.g., on-premise mail servers), these could be targets for separate infrastructure testing. Third-party includes such as mailchimp.com, sendgrid.net, or salesforce.com reveal which SaaS platforms the target uses, providing additional attack surface.
🛡
Defender Note: Ensure your SPF record uses -all (hard fail) rather than ~all (soft fail) to prevent email spoofing. Implement DMARC with a p=reject policy and DKIM signing. Audit your SPF record regularly to remove deprecated IP ranges and third-party includes that are no longer in use. Consider using Azure Private Link and Private Endpoints to reduce the number of publicly exposed Azure resources.
8 Open Federation & Guest Access

Azure AD B2B collaboration allows organisations to invite external users as guests. If the target tenant has permissive federation or guest access settings, attackers can leverage this to gain an initial foothold, enumerate internal resources, or pivot from a compromised partner tenant.

AADInternals Microsoft Graph curl TeamFiltration

Checking Federation Configuration

Determine whether the target tenant uses federated authentication (ADFS, Okta, PingFederate, etc.) and identify the federation endpoint. This is important because federated environments may have different security controls than cloud-managed environments.

Bash
# Check the user realm to determine federation status
curl -s "https://login.microsoftonline.com/getuserrealm.srf?login=user@targetcompany.com" | jq '.'

# Example output for a FEDERATED domain:
# {
#   "NameSpaceType": "Federated",
#   "DomainName": "targetcompany.com",
#   "FederationBrandName": "Target Company",
#   "AuthURL": "https://adfs.targetcompany.com/adfs/ls/?..."
#   "CloudInstanceName": "microsoftonline.com"
# }

# Example output for a MANAGED (cloud-only) domain:
# {
#   "NameSpaceType": "Managed",
#   "DomainName": "targetcompany.com",
#   "CloudInstanceName": "microsoftonline.com",
#   "FederationBrandName": "Target Company"
# }

ADFS Endpoint Discovery

If the domain is federated, the ADFS server is an additional attack surface. Common ADFS endpoints can be probed to confirm availability and gather configuration details.

Bash
# If AuthURL reveals an ADFS server, probe its endpoints
ADFS="adfs.targetcompany.com"

# ADFS metadata endpoint (public by default)
curl -s "https://${ADFS}/adfs/.well-known/openid-configuration" | jq '.'

# ADFS federation metadata (reveals signing certificates)
curl -s "https://${ADFS}/federationmetadata/2007-06/federationmetadata.xml"

# Common ADFS authentication endpoints
curl -s -o /dev/null -w "%{http_code}" "https://${ADFS}/adfs/ls/idpinitiatedsignon.aspx"
# 200 = ADFS sign-in page is accessible (can be used for password spraying)

# Check for ADFS Extranet Lockout settings
# High lockout thresholds or disabled lockout = easier password spraying

Guest Access & B2B Collaboration Testing

Test whether the target tenant allows external users to be invited as guests. This can be checked by attempting to look up external user properties through the Teams API or by probing the invitation endpoint.

PowerShell
# AADInternals - Check tenant's external collaboration settings
# Get the OpenID configuration which reveals tenant info
Get-AADIntTenantDomains -Domain "targetcompany.com"

# Check if Teams external access is open
# If you have a valid token from ANY M365 tenant, you can test:
Invoke-RestMethod -Uri "https://teams.microsoft.com/api/mt/emea/beta/users/user@targetcompany.com/externalsearchv3" `
  -Headers @{Authorization = "Bearer $token"}

# If external access is allowed, this returns user details
# including display name, presence, and profile picture

Teams External Access Enumeration

Bash
# TeamFiltration can enumerate users via Teams external access
# First, acquire a Teams token from your own tenant
TeamFiltration --enum --userlist userlist.txt

# If external access is enabled on the target tenant, this returns:
# - User display names
# - User presence status (Available, Busy, etc.)
# - User profile photos
# - Whether the user has Teams enabled

# This works because Teams external access allows
# cross-tenant user lookup by default in many tenants

Cross-Tenant Trust Assessment

Bash
# Check if the target has Azure AD cross-tenant access policies
# by testing the cross-tenant synchronization endpoint
curl -s "https://login.microsoftonline.com/targetcompany.com/v2.0/.well-known/openid-configuration" | \
  jq '.tenant_region_scope, .cloud_instance_name'

# Check Azure AD federation metadata for trust relationships
curl -s "https://login.microsoftonline.com/targetcompany.com/federationmetadata/2007-06/federationmetadata.xml"

# The metadata reveals:
# - Token signing certificates
# - Supported claim types
# - Federation endpoints
# - Tenant region and cloud instance
Important: Testing guest access and cross-tenant federation may generate logs in both the target tenant and your own tenant. Ensure your rules of engagement cover cross-tenant testing activities. Do not send guest invitations or attempt to join the target tenant without explicit authorisation.
🛡
Defender Note: Restrict external collaboration in your Azure AD External Identities settings. Key hardening steps: (1) Set "Guest user access restrictions" to the most restrictive option (Guest users have limited access). (2) Under "Collaboration restrictions", allow invitations only to specific domains or block known malicious domains. (3) Disable Teams external access for unmanaged domains. (4) Configure cross-tenant access policies to explicitly define which partner tenants can collaborate. (5) Regularly audit guest accounts using Get-MgUser -Filter "userType eq 'Guest'" and remove stale guests. (6) If you run ADFS, restrict extranet access and enable Extranet Smart Lockout.
📋
Phase 1 Summary: At the end of this phase you should have: a list of all domains in the target tenant, the tenant GUID, a map of active M365 services, a validated list of usernames, intelligence on authentication methods (managed vs. federated, MFA types), and an understanding of the target's external collaboration posture. This information feeds directly into Phase 2 (Initial Access) and Phase 3 (Credential Attacks).