If you've done any offensive work against cloud environments, you've probably used tools like onedrive_user_enum, succ, offensive_azure and other tooling to map out your target's infrastructure. These tools all relied on the same underlying technique that Microsoft soft patched a few months ago.

The Old Method: Get-FederationInformation

For those unfamiliar, here's how tenant enumeration worked.

The Exchange PowerShell Get-FederationInformation cmdlet and tools like succ both relied on Microsoft's Autodiscover SOAP endpoint at autodiscover-s.outlook.com/autodiscover/autodiscover.svc.

Tools like succ sent POST requests with XML SOAP envelopes containing a GetFederationInformation request. The response would contain all domains associated with that Office 365 tenant, not just the one you queried. No authentication was required and there was basically 0 rate limiting.

You'd query contoso.com and get back:

  • contoso.com
  • contoso.net
  • mail.contoso.com
  • assets.contoso.org
  • Every other verified domain in the tenant

The response also included the tenant name (the short identifier used in.onmicrosoft.com addresses). This tenant name is crucial because tools like onedrive_user_enum need it to build the SharePoint URL pattern (https://TENANTNAME-my.sharepoint.com/personal/). Without this information, you can't construct valid user enumeration URLs.

Microsoft's Patch

On May 23, 2025, Microsoft published Message Center notice MC1081538 announcing an "Important Update to the Get-FederationInformation Cmdlet in Exchange Online." The actual rollout happened from late June through late August 2025.

The change targeted the backend Autodiscover SOAP service. Previously, querying any single domain would return all federated domains in the DomainNames field. After the patch, the service only returns information about domains explicitly passed as parameters.

Query contoso.com, get back only contoso.com. Query nothing specific, get nothing back.

The patch affected the Autodiscover endpoint itself (autodiscover-s.outlook.com/autodiscover/autodiscover.svc), not just the PowerShell cmdlet wrapper. This meant tools like succ that directly called the SOAP API also stopped working.

The entire technique was neutered. Tools broke. Workflows died.

The Holdout

Except... not everything stopped working. Dr. Nestori Syynimaa's AADInternals exposed a web interface where you could query a domain and get the same information back. We weren’t sure why. At first, the data seemed cached but it was later revealed that an alternate endpoint was in use to collect this information.

People were hammering this app hard to get information which led Dr. Nestori Syynimaa to take the page down altogether.

Dr. Nestori Syynimaa: https://x.com/DrAzureAD/status/1967637883227083244

Alternatively, some researchers have begun creating large datasets as a workaround. They collect tenant IDs for millions of domains and build searchable databases that correlate domains across tenant IDs. An example of this is a project by Micah Van Deusen.

Here, they took roughly 400 million domains and ran the following request to extract the tenant ID for each.

curl -s "https://login.microsoftonline.com/{domain}/v2.0/.well-known/openid-configuration" | jq .token_endpoint

Additionally, they are also grabbing the organization name from the following endpoint.

https://login.microsoftonline.com/getuserrealm.srf?login=user@{domains}

Note: This endpoint returns the FederationBrandName, which is almost never in the same format as the tenant name. Some manual testing may be required at this step, but the project does not reveal what techniques were explicitly performed.

Using this project, or creating a DB of your own, is a temporary (or long-term, albeit costly) solution to enumerate base domains for any given tenant ID.

A Better Approach

We found another method which is possible completely unauthenticated. On a side note, Dr. Nestori Syynimaa has released a new solution as well that requires authentication to access.

https://osint.aadinternals.com/

 We built a free API that uses the method we have discovered and here's the logic:

  • You query “https://azmap.dev” via cURL with parameters
  • The backend handles the actual Microsoft enumeration
  • You get the data back that you need.
  • Your tools keep working after changing a few lines of code.

This approach abstracts the technique behind a stable interface. When one method dies, we'll try to swap in another, hopefully without Microsoft ever becoming wise of the methodologies used.

The infrastructure is running on Cloudflare Workers with a setup that currently costs meus $0 monthly.       

How to Use It

Get core tenant information for any domain:

curl "https://azmap.dev/api/tenant?domain=microsoft.com"

Response:

{
  "tenant_id": "72f988bf-86f1-41af-91ab-2d7cd011db47",
  "tenant_name": "microsoftcan",
  "domain": "microsoft.com"
}

Extract all email domains associated with a tenant:

curl "https://azmap.dev/api/tenant?domain=microsoft.com&extract=true"

Response:

{
  "tenant_id": "72f988bf-86f1-41af-91ab-2d7cd011db47",
  "tenant_name": "microsoftcan",
  "domain": "microsoft.com",
  "email_domains": [
    "microsoft.com",
    "xbox.com",
    "mojang.com",
    "linkedin.com"
  ]
}

API Parameters

Parameter

Required

Description

domain

Yes

Domain to query

extract

No

Set to true to return all email domains

Cloudflare's free tier gives us 100,000 requests per day at $0/month. That's enough for the entire offensive security community to share if people are reasonable about it.

So please, be reasonable. Don't run this in a loop. Don't query the same domains thousands of times. Don't write scripts that hammer the endpoint for fun. If this gets too expensive or attracts too much attention, weI'll have to shut it down.

Integration

Tools like onedrive_user_enum can integrate this API as a fallback method when direct enumeration fails. Other tool maintainers should feel free to do the same.

The integration is straightforward, it's just an HTTP GET request:

import requests

response = requests.get(
    "https://azmap.dev/api/tenant",
    params={"domain": "example.com", "extract": "true"}
)

data = response.json()

No authentication, no complex OAuth flows, no dependencies. Hit the endpoint, parse the JSON, move on with your engagement.

Why This Matters

Let's be realistic about what we're dealing with here.

This is a stopgap, not a permanent solution. Microsoft will eventually discover this approach and patch it if this change was driven by security in some way. When they do, we'll find another method and update the backend. The cycle continues. But the API approach buys us something valuable: time and stability.

Instead of every researcher independently discovering and burning the same technique, we centralize it.

I really like this approach and really think certain techniques should be abstracted away to services like Cloudflare workers when sharing techniques with the community. With this methodology, we can share cool stuff without burning a technique.

Hope everyone enjoys!