We Know What You Did (in Azure) Last Summer

Techniques for enumerating cloud resources have had extensive coverage over the years. Most of the existing techniques focus on subdomain enumeration, or identification of hosts in IP spaces associated with cloud providers. Additionally, very few of the prior blogs have focused on confirming the actual owners of cloud resources. Most of the existing research has typically said that there is no way to determine who the real owner of the resource is.
As it turns out, there are ways to determine resource ownership for some Azure resource types. While it doesn’t apply to every Azure service, many services that support Entra ID authentication expose the hosting tenant ID as part of the authentication process. The tenant ID can then be reversed to full domain names associated with the tenant. If this is done at scale, enumeration and attribution can be used to map out resources owned by a specific organization.
TL;DR
- Many Azure resources utilize subdomains for resource addressing
- These resources can be discovered through DNS hostname enumeration
- A subset of Azure resource types that support Entra ID authentication will expose their tenant ID through the authentication process
- An attacker can abuse this exposure to map resources back to specific tenants
- We wrote a tool (ATEAM) to automate this process
Existing Azure Resource Enumeration Techniques
As previously covered on the NetSPI blog, Azure makes significant use of subdomains for addressing resources. We can use Storage Accounts as an example. If we create a $StorageName Storage Account, the following DNS names will be reserved:
- $StorageName.blob.core.windows.net
- $StorageName.file.core.windows.net
- $StorageName.table.core.windows.net
- $StorageName.queue.core.windows.net
Furthermore, if we configure the blob storage component to allow for static web hosting, an additional “web” subdomain will be reserved:
- $StorageName.z4.web.core.windows.net

The story is the same for many other Azure resource types. There is typically one main subdomain used for the resource, with multiple auxiliary domains associated with it. These auxiliary domains can include regional (westus-01, canadaeast, etc.) and capacity (z1,z2, z3, etc.) reservations as well, so this can widen out the DNS enumeration surfaces.
To find potential resources connected to an organization, we’ve traditionally used these hostnames/subdomains in combination with public DNS resources (VirusTotal), certificate records (crt.sh), and brute-force techniques to find live DNS records. Tools like bbot make this process significantly easier, as they can gather subdomains from multiple different sources.

As attackers, we have had to make some assumptions that these live records ($StorageName.blob.core.windows.net) could be tied to a specific target, based on the keywords (company/software name) used for naming.
Until recently, a resource name was not proof of ownership. For Example – the “AWS” Storage Account (in Azure) does not belong to AWS, the company.
Attribution of Azure Resources
Outside of having a custom domain name (IE: storageaccount.netspi.com) pointing to an Azure resource, or an SSL certificate being served, we have not had a reliable way of determining if a resource is associated with a specific tenant. In this blog, we will introduce an option that should be applicable to multiple different Azure services, along with a tool to automate the discovery and attribution process.
To start things off, we will show how this technique works for the Storage Account service. We will use an arbitrarily named Storage Account (0752a779955f4cbda44468) in a tenant (Darksideops.cloud) that we control. For context, the Storage Account does not have any public containers, and it is set up as a private endpoint, so it should have zero public exposure (outside of a DNS name).
We can use the following PowerShell code to make a web request to the Storage Account with the “x-ms-version” header and the “comp=blobs” API method.
try { Invoke-RestMethod -Uri "https://0752a779955f4cbda44468.blob.core.windows.net/?comp=blobs" -Method Get -Headers @{"x-ms-version"="2019-12-12"} } catch { $_.Exception.Response.Headers } Key Value --- ----- x-ms-error-code {NoAuthenticationInformation} WWW-Authenticate {Bearer authorization_uri=https://login.microsoftonline.com/977e0660-d4d3-4752-a79d-3ac9c4dbcf19/oauth2/authorize resource_id=https://storage.azure.com} Date {Sun, 19 Jan 2025 16:02:50 GMT
To make this a little clearer, we’ve included the raw HTTP requests and responses:
GET /?comp=blobs HTTP/1.1 x-ms-version: 2019-12-12 User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.19041.6093 Host: 0752a779955f4cbda44468.blob.core.windows.net Connection: keep-alive
HTTP Response:
HTTP/1.1 401 Server failed to authenticate the request. Please refer to the information in the www-authenticate header. Content-Length: 303 Content-Type: application/xml Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-error-code: NoAuthenticationInformation x-ms-request-id: 32efc751-401e-0024-736d-f77f1b000000 x-ms-version: 2019-12-12 WWW-Authenticate: Bearer authorization_uri=https://login.microsoftonline.com/977e0660-d4d3-4752-a79d-3ac9c4dbcf19/oauth2/authorize resource_id=https://storage.azure.com Date: Sun, 19 Jan 2025 16:02:50 GMT
We can see in the response that the server responds with an error and prompts with a WWW-Authenticate header. This header contains a login.microsoftonline.com link that includes the tenant ID (977e0660-d4d3-4752-a79d-3ac9c4dbcf19
) of the owning tenant. Now that we have the tenant ID, we can use the Graph API (/v1.0/tenantRelationships/findTenantInformationByTenantId(tenantId='$tid')
) to get the associated tenant domain.
Tenant Domain Lookup Via Graph Explorer:

Another thing to note is that this example shows that the technique works for Storage Accounts that are configured as private endpoints. While the account itself does not technically have any external exposures (files/folders/etc.), the DNS name is publicly enumerable, and the same Storage Account APIs are still available for it. This means that we can still identify the account and complete attribution against it. This concept (and the ability to find private endpoint attribution) also applies to multiple other services as well.
We’ve compiled a list of Azure services that are impacted by the attribution issue and highlighted them in the following table:
Resource Type | Subdomains | Enumeration Technique | Attribution Technique |
---|---|---|---|
Key Vaults | vault.azure.net | Subdomain Enumeration | “WWW-Authenticate” Header |
Storage Accounts | blob.core.windows.net | Subdomain Enumeration | “WWW-Authenticate” Header |
SharePoint | sharepoint.com | Subdomain Enumeration | “Report-To” Header |
App Services | azurewebsites.net scm.azurewebsites.net | Subdomain Enumeration | “Location” Header in Redirect |
DataBricks | azuredatabricks.net | Subdomain Enumeration | “Location” Header in Redirect |
Azure Machine Learning | instances.azureml.ms | Subdomain Enumeration | “Location” Header in Redirect |
DevOps | dev.azure.com | Directory Enumeration | “WWW-Authenticate” Header |
Azure Provider String | management.azure.com | Resource String Disclosure | “WWW-Authenticate” Header |
It should be noted that the Azure Provider String listed above refers to the Azure management API URL that’s used for referencing an individual resource.
Example:https://management.azure.com/subscriptions/155c4768-b71c-4e4b-a990-97407f43edda?api-version=2022-12-01
These strings can often be found in source code files or exposed through screenshots. If you’re a security researcher worried about exposing any of your tenant information, you might want to make sure that you’re fully redacting subscription IDs in your screenshots.
One last thing to note is the redirection to the “common” tenant that we see for some resources (primarily App Services). While it seems like a dead end, it is possible to determine the actual tenant for these “common” redirections. Depending on if you approach the resource with or without an active Entra ID session, you will get a different response. An unauthenticated session will give you the “common” tenant, while an authenticated session (ESTSAUTHPERSISTENT cookie present) will start a different redirection flow that exposes the tenant ID of the resource.
It should be noted that we don’t currently support credentials in the ATEAM tool (see below), but they could be added to help support unmasking the “common” tenant resources.
Introducing ATEAM
Given the utility of these techniques, we created a tool to enumerate and attribute Azure resources at scale.
We call it ATEAM – or Azure Tenant Enumeration and Attribution Module
The tool utilizes the methods outlined above for each of the impacted services to find and attribute live resources. For every resource that it finds attribution for, the tool stores a timestamped record in a local sqlite database (azure_tenants.db). The tool also allows for CSV, JSON, and HTML output of the results.
While we’re typically a PowerShell shop for Azure tools, this one made sense to write in Python. The large-scale DNS resolution and the use of a SQLite database were not really compatible with PowerShell.
It should be noted that for each live DNS record, there will typically be two HTTP requests that are sent. One to collect the tenant ID and another to get the company name for the tenant. Otherwise, this is a fairly simple process for each of the resource types that are supported.
Here’s an example HTML report of some discovered resources:

Usage notes:
The tool supports looking up individual resources (-r “myapp”
), multiple keywords (-r “myapp” “myapp2” “myapp3”
), or a list of keywords from a file (-f keywords.txt
).
Additionally, we support generating permutations (prefix and suffix, with and without dashes) on the keywords with the -p
flag. There is a default permutations.txt file in the repository that is used for that generation.
The tool also allows you to scale up the number of workers (-w 10
) to allow for higher throughput.

You can find the tool in the NetSPI GitHub – https://github.com/NetSPI/ATEAM
Results
As part of this research, we compiled a list of observed hostnames under different Azure subdomains. Since there is frequently an overlap of resource names between different services, we thought it would be useful to pull resource names from as many Azure subdomains as possible. This resulted in around 1 million total keywords that could be used for finding and attributing Azure resources.
After enumerating the potential hostnames, we completed DNS enumeration against the vulnerable services to identify the potential attack surface area. This resulted in the following breakdown of live resources by service type:

MSRC Timeline
As part of this research, we reported multiple issues to MSRC. After the three initial reports were closed, we created a combined report, in an attempt to show the wider impact of the issues.
Storage Account Attribution
- Mar 27, 2024 – Initial Report Date
- Apr 23, 2024 – Case Close Date
- Status – Complete, “by-design”
Key Vault Attribution
- Mar 27, 2024 – Initial Report Date
- May 28, 2024 – Case Close Date
- Status – Complete, “working as intended”
App Service Attribution
- Mar 27, 2024 – Initial Report Date
- May 22, 2024 – Case Close Date
- Status – Complete, “working as intended”
Combined Report – Azure Tenant Enumeration
This issue was reported to MSRC and we worked with MSRC on Coordinated Vulnerability Disclosure leading up to the presentation.
- Feb 14, 2025 – Initial Report Date
- Feb 26, 2025 – Case Close Date
- Status – Complete, “valid, but does not pose an immediate threat”
- Feb 28, 2025 – Coordinated Vulnerability Disclosure process begins
- July 2025 – Coordination with MSRC and Product Team
“We appreciate your effort in bringing this to Microsoft’s attention. Upon reviewing the collection of these cases together, we have re-evaluated the ‘by design’ closure of these prior cases, and are investigating approaches to defend against these classes of reconnaissance techniques.”
Conclusion
This research was a year in the making. We initially started discovery on the attribution methods in Q2 of 2024 and slowly progressed the research over the course of a year. Although we had some hurdles, we ultimately were able to get the issues communicated to the right people and were able to publish this research. We want to express our appreciation for all the MSRC folks that looked at our tickets, the individuals that advocated for those issues, and the countless NetSPI co-workers that we kept showing this to over the last year.
Previous Research
As mentioned at the start, there have been multiple other research projects in this space, we’ve included several of them here:
- AWS Eye – https://awseye.com/
- Daniel Grzelak – Plerion
- AAD Internals – https://aadinternals.com/
- Dr Nestori Syynimaa – Microsoft
- cloud_enum – https://github.com/initstring/cloud_enum
- Chris Moberly – GitLab
- Track the Planet – https://www.youtube.com/watch?v=4AY5uS3yFjE
- Nyxgeek – TrustedSec
- Tenant Admin Consent API Name Exposure

Find Unexpected Cloud
Resource Exposures
Explore More Blog Posts

From Pentest Report to Boardroom Strategy in 5 Steps
Learn how to turn technical findings from penetration testing into executive action with a five-step approach for maximizing pentesting value.

DEF CON 33: NetSPI’s “Access Everywhere” Experience
NetSPI security experts share key insights from DEF CON 33's "Access Everywhere" theme, from networking with hackers to expanding security expertise through sessions and workshops.

Assessing the True Business Impact of a Malicious Connected App
Discover the cascading risks of malicious Connected Apps in Salesforce. Learn how to assess business impact, secure your org, and protect critical infrastructure.