By identifying and purchasing an expired domain tied to an existing Azure AD organization, an anonymous attacker can use PowerBI or PowerAutomate to create an account and gain access to that organization’s tenant, including resources shared within that tenant (e.g., OneDrive, SharePoint, etc.). The attacker is effectively a “domain user” in that tenant. SRA created a tool called LetItGo that queries an organizations’ domain listing and returning any domains that are expired.
Let It Go
During a recent red team engagement, we successfully compromised the client and gained access to their internal information repositories but had limited access. During the collection phase we stumbled upon a list of domains that were configured for their on-prem Exchange servers. As we were looking to pivot and attempt to phish additional users, we thought that if any of the domains were expired, we could purchase them, and they may bypass some of the mail protections. After looking through the list, we discovered that several had lapsed, and purchased them. While attempting to register the domain to our test Office 365 tenant, we observed an error that stated we had proved we owned the site, however the domain was still tied to another organization (in this case the client’s Office 365 organization).
We spent some time discussing if there was any way that we could use this domain to gain access to the tenant. We confirmed that the client had removed all the user accounts, including the admin account, which eliminated the possibility of receiving password reset emails. We posed a couple of hypothetical questions to some trusted friends to see if they had any insight and could confirm what we were seeing.
A Kingdom of Isolation
After speaking with a friend, they walked us through how to regain access to an unmanaged tenant (one that had been setup but not tied to the organization) along with Microsoft’s own guidance on the matter. As it turns out, if you can receive email for the domain, you can use PowerBI to register a new subscription, which in-turn will create a new account (assuming the account doesn’t already exist). Once you receive the email validation, you can continue the account creation process and gain access to your account (and Office 365). It would then be possible to perform the admin take-over outlined in the Microsoft post and gain administrative access to that tenant.
This seemed very interesting; however, we weren’t trying to regain access to the unmanaged tenant, we were trying to gain access to the primary Azure AD tenant. On a whim, we created a catch-all email forwarder and attempted to create a new account using PowerBI. After receiving the verification code via email, we were able to complete the account creation process and authenticate to PowerBI. The first thing we checked was our account settings and profile, and we were surprised to see that the new account was registered to the client’s primary Azure AD organization, and it was licensed for PowerBI.
Since the account was tied to the client’s organization, we began trying to access known Office 365 applications and services such as OneDrive and SharePoint. We targeted these services because they often are a wealth of knowledge for furthering access, obtaining credentials, or reaching data targets. Our first attempt to access both SharePoint and OneDrive resulted in an access denied error, but forcefully browsing to the search endpoints allowed us to query for things like keys and passwords. We began downloading content that was shared out with all internal users of the organization. At the same time, we also began enumerating data from Azure AD as our user could authenticate using the Azure AD PowerShell modules (or any other tool you’d like to use to perform enumeration).
We determined that we were able to take an expired domain which was previously verified within an Azure AD tenant, create a new account using PowerBI, and gain access to that organization’s resources and data. We notified the client and immediately began attempting to reproduce this against our test tenant to validate this behavior.
Conceal, don’t Feel
Using our test tenant and domains we purchased; we
- Registered those as custom domains to our Azure AD tenant. This is a common process and easy to perform through the admin console.
- Simulated the domain expiring as it did within our client’s domain. To do this, we removed all the existing DNS records which severed the connection to Azure.
Browsing in the Admin console however, we were surprised that we still had a green check next to the domain. As it turns out this will only change if you manually refresh your domain list with the refresh button, once we did that, we were shown that there was an error with our domain configuration. Since our domain in essence was now in the same state as it was in our attack, we began the process of creating our catch-all email and registering a new account in PowerBI.
Once this was completed, we observed that our user had the ability to access the existing tenant.
After documenting our findings, we reported this to the Microsoft Security Response Center as we thought that we shouldn’t be able to go from no access to the equivalent of “domain user” access, even if the client let the domain expire. We also pointed out the static nature of the admin console reporting on the state of registered domain names which could be improved. Microsoft responded back that while there was potential for improvement of their services, our observations did not meet the bar for immediate security servicing and tracking. Microsoft’s stance on the issue was that it is the responsibility of the tenant to renew and update information on the expiration of domains they own.
Let the Storm Rage On
After concluding our red team engagement, we attempted to verify this attack with other clients to determine the potential breadth of the attack. Using the Azure AD PowerShell library, we could confirm:
- If a domain was registered in Office 365, we could return the name of the tenant
- If the domain was managed or federated
- If the domain was in a vulnerable state, specifically if it is set up for self-service.
The attack path had some obstacles:
- Identifying these domains through WHOIS and other registrar data took significant effort per client
- Validating that the domain was not owned by another party and part of their own tenant
- Any other domains we suspected could be tied to a tenant could not be confirmed since the tenant information returned may not have been unique.
These obstacles were made easier to overcome after we found an interesting reconnaissance technique from Lars Karlslund (@lkarlslund) posted on Twitter. He demonstrated using the AAD Internals PowerShell  modules from Nestori Syynimaa could retrieve the full list of configured domains from an organization unauthenticated.
This request is to the Autodiscover service, something we had failed to look at for the domain listing during our testing. Once we observed it was possible to pull the configured domains, we began developing a tool to:
- Enumerate domains tied to a tenant and
- Perform lookups to see if any of the configured domains are expired
We created “LetItGo” as a utility for admins and security professionals to use for querying their organizations’ domain listing and returning any domains that are expired. When we started down our journey, we hypothesized that the scope of this attack would be limited to a few organizations; however, after creating the tool we performed a check against the Fortune 500 list and found that 1 in 5 (20%) of the organizations were susceptible to this attack.
Important Note: We only used the primary domain for Fortune 500 organizations and did not include ANY subsidiaries which could have increased our observed numbers.
Using “LetItGo” is relatively straightforward, it takes a single domain as an input and performs a lookup against the Autodiscover service for the tenant’s domain list. Once retrieved it uses the Whois protocol to perform lookups and parses the results to determine if any domains in the list are expired and vulnerable to this attack.
Don’t let them in
Prevention: Like everything in security, the basics are a good start. Preventing this attack can be done through good domain management which includes preventing domains that are in use from expiring. Additionally, if domains are configured for Azure but no longer used, remove these domains from the tenant. Within the Admin Portal you can check if a domain is “In Use”, meaning there are emails addresses or aliases associated.
Detection: As this attack requires the attacker to register the expired domain, it is possible for brand monitoring to alert on this activity, however based on our experience, this process can be delayed and may not result in a high-fidelity alert.
We have created some detections to identify user account creation in real-time and methods to search for it in an existing tenant.
Sigma Rule for anomalous account creation:
title: AzureAD forceful user creation via expired domain id: b1242f6e-0504-40a4-8979-a768a3c1e82d description: Detects when a user is created in an enviornment via a SignUp process author: SRA status: development date: 2021/11/17 date: 2021/11/17 references: - https://sra.io/blog/letitgo-a-case-study-in-expired-domains-and-azure-ad/ logsource: product: AzureAD service: Audit Logs detection: selection: initiatedBy.app.displayName: Signup operationName: Add user condition: selection level: high tags: - attack.impact falsepositives: - Users legitimately signing up via PowerBI/PowerAutomate - Users signing up using the self-service portal: https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/directory-self-service-signup
Threat Hunt: The goal of the threat hunt is to determine if there are any suspicious users within your tenant that require investigation. To identify anomalous users:
- Go to the AzureAD portal and access the user list
- Add a filter with the following parameters
- Filters: Creation type
- Operator: ==
- Value: EmailVerified
- Users that appear here were not added to the tenant directly, but rather had an email address with a valid domain for the tenant, and signed up using an external sign up portal.
- Note: If this is not functionality you want or expect, follow the directions in the documentation above to block the functionality.
- Validate these users are appropriate for the tenant. Some validation steps include:
- Directory Sync status – if users in your tenant are supposed to be directory synced, validate these users are directory synced
- UPN domain – validate the domains for the UPNs are approved domains to access the tenant
- Domains such as <tenantname>.onmicrosoft.com are the default tenant domain, while they may indicate a configuration issue, they are not malicious
- It is also possible to have vendors added to the tenant for ease of sharing, while this isn’t a malicious user, it does expose the entire tenant to that vendor
- Licenses applied to users – users created with this attack will likely only have one license applied to the account, most commonly Power BI (free). Some other licenses include:
- Power Apps Free
- Power Automate Free
- RMS for individuals
- Microsoft Stream
- Dynamics 365 free trial
- Users with no organization attributes applied
- Finally, validate all domains in the tenant to ensure they are held by expected organizations, either yours or a trusted third-party.
After creating LetItGo and validating impact with some of our trusted partners we engaged MSRC once again and shared our results. Microsoft acknowledged the impact as “important” and notified us that a fix was implemented on December 15, 2021 (unfortunately the same time O365 suffered a severe outage). After this was confirmed, we validated in our test tenant that the issue was partially fixed and that two new vectors were identified. We notified MSRC which resulted in a separate case, also rated “important”, and a subsequent fix issued on January 14, 2022. As of that time, a retest resulted in the inability to add users to tenants with domains identified by LetItGo regardless of tenant settings for AllowEmailVerifiedUsers and AllowAdHocSubscriptions unless the tenant is marked as viral.
Although Microsoft was able to prevent individuals from potentially enrolling unauthorized users in organizations’ tenants, LetItGo still has value for OSINT purposes. The ability to poll tenants for phishing campaigns, red teams and other engagements can provide an operator with a validated list of domains to hunt for, or potentially purchase, which may provide access or information disclosure in other ways.
Update (March 23, 2022):
On 3/7/2022 our CyberSOC reached out to us because our Sigma rule for detecting self-service signups fired, as debuted in our LetItGo blog post. We hopped on a call to speak with the client and confirm that the detected activity was a false positive; the user signed up for PowerBI using an email domain that was owned by the client and aliased to their primary email domain.
While that was going on, and in preparation for our ShmooCon talk, we went back to our test tenant to validate if Microsoft had rolled back the changes that we validated in January to fix our two Important severity observations. At some point between January and March the fixes appear to have been rolled back, as we could enroll rogue users again using the techniques we disclosed to Microsoft.
We reached back out to MSRC on 3/8/2022 to notify them that the fixes were rolled back and to get clarification, as the other suggestions we offered had not been implemented. To date, we have not received a response. However, we will continue to try and work with Microsoft, but we will also raise awareness of this issue at ShmooCon on Thursday 3/24/2022 during our scheduled presentation.
It appears that some things you just cannot let go.
- Mark Arnold for validating the tenant takeover process
- Lars Karlslund for the domain retrieval idea
- Nestori Syynimaa for creating and maintaining AADInternals
- Peter Crampton and Pb— for helping with LetItGo