Automatic Azure AD User Account Enumeration with PowerShell (Scary Stuff)

SniperScope

A common first step in an Azure AD/Office 365 identity based attack is to find real user accounts to target. The username in Azure AD are commonly the users primary email address and email addresses can easily be guessed or found online, on social media for example.

A malicious actor might be extra interested in accounts with names usch as admin@example.com or breakglass@example.onmicrosoft.com. Microsoft makes the user enumeration process easy since there are multiple API endpoints online that you can query without authentication. This is by design.

You can try one of these endpoint yourself by opening this link with the browser of your choice (change USERNAME in the login parameter to any email address you would like to test):

https://login.microsoftonline.com/getuserrealm.srf?login=USERNAME&xml=1

<RealmInfo Success="true">
	<State>4</State>
	<UserState>1</UserState>
	<Login>user1@example.com</Login>
	<NameSpaceType>Managed</NameSpaceType>
	<DomainName>example.com</DomainName>
	<IsFederatedNS>false</IsFederatedNS>
	<FederationBrandName>Example Corp</FederationBrandName>
	<CloudInstanceName>microsoftonline.com</CloudInstanceName>
	<CloudInstanceIssuerUri>urn:federation:MicrosoftOnline</CloudInstanceIssuerUri>
</RealmInfo>

This trick only works for cloud only account since federated accounts are managed by the organisations federation infrastructure (AD FS). For a malicious actor, this is often good enough since the most interesting accounts, like break glass accounts, are cloud-only (as they should be). Please see my other blog post for details on how to monitor your break glass accounts.

I’ve created a PowerShell script which automates the user enumeration process in Azure AD for one or many email addresses at a time. You can run this from any internet connected computer without authentication.

This script is a proof of concept and for testing purposes only. Do not use this script in an unethical or unlawful way. Don’t be stupid!

function Test-AzureADUserExistence {
<#
    .SYNOPSIS
        Check if an account exists in Azure AD for specified email addresses.
    
    .DESCRIPTION
        The script will connect to public endpoints in Azure AD to find out if an account exists for specified email addresses or not. This script works without any authentication to Azure AD. The script can't see accounts for federated domains but it will tell you what organisation the federated domain belongs to.
    
    .PARAMETER Users
        An array of one or more user email addresses to test.
    
    .EXAMPLE
        Test-AzureADUserExistence -Users "user1@example.com", "user2@example.com", "user3@example.onmicrosoft.com"
    
    .NOTES
        Version:        1.0
        Author:         Daniel Chronlund
        Creation Date:  2020-03-12
        
        Warning: This script is a proof of concept and for testing purposes only. Do not use this script in an unethical or unlawful way.
#>

    param ($Users)

    foreach ($User in $Users) {
        # Create custom object for output.
        $TestObject = New-Object -TypeName psobject

        # Add username.
        $TestObject | Add-Member -MemberType NoteProperty -Name "Username" -Value $User

        # Check if user account exists in Azure AD.
        if (((Invoke-WebRequest -Method "POST" -Uri "https://login.microsoftonline.com/common/GetCredentialType" -Body "{`"Username`":`"$User`"}").Content | ConvertFrom-Json).IfExistsResult -eq 0) {   
            # Check domain federation status.
            [xml]$Response = (Invoke-WebRequest -Uri "https://login.microsoftonline.com/getuserrealm.srf?login=$User&xml=1").Content

            # Add org information.
            $TestObject | Add-Member -MemberType NoteProperty -Name "FederationBrandName" -Value $Response.RealmInfo.FederationBrandName
            
            # If domain is Federated we can't tell if the account exists or not :(
            if ($Response.RealmInfo.IsFederatedNS -eq $true) {
                $TestObject | Add-Member -MemberType NoteProperty -Name "UserExists" -Value "Unknown (Federated domain handled by $((($Response.RealmInfo.AuthURL -split "//")[1] -split "/")[0]))"
            }
            # If the domain is Managed (not federated) we can tell if an account exists in Azure AD :)
            else {
                $TestObject | Add-Member -MemberType NoteProperty -Name "UserExists" -Value "Yes"
            }
        }
        else {
            $TestObject | Add-Member -MemberType NoteProperty -Name "UserExists" -Value "No"
        }

        $TestObject
    }   
}


# Example:
Test-AzureADUserExistence -Users "user1@example.com", "user2@example.com", "user3@example.onmicrosoft.com"

 

Since you really can’t protect your organisation from this first step in the attack, to find out which accounts are real and which ones to attack, you need to think about how to protect the next step, the authentication process.

Ones the malicious actor has a real username, it’s easy to launch a password brute-force attack or a password spray attack or maybe a targeted spear-phishing attack. In short, you need to protect authentication with Conditional Access and MFA. A password isn’t enough. You also need to monitor your most sensitive accounts for any activity and act on alerts.

Microsoft is putting a lot of effort into getting rid of old brute-force friendly legacy protocols, and real password-less setups are on the horizon. Make sure to follow the current best practices when securing your tenant and don’t get lacy, because the ones who want’s to get in will never be.

 

Please follow me here, on LinkedIn and on Twitter!

@DanielChronlund