Detect Email Addresses in Microsoft Sentinel
Adversaries may gather email addresses that can be used during targeting. Even if internal instances exist, organizations may have public-facing email infrastructure and addresses for employees. Adversaries may gather email addresses from publicly accessible sources such as social media, company websites, and leaked credential databases. Additionally, adversaries may actively enumerate valid email addresses by probing authentication services — for example, querying the Microsoft GetCredentialType API endpoint or Exchange Autodiscover to determine whether a given address is a valid account in Office 365 or on-premises Exchange environments. Gathered email addresses enable spearphishing campaigns, credential brute force attacks, business email compromise, and social engineering operations.
MITRE ATT&CK
- Tactic
- Reconnaissance
- Technique
- T1589 Gather Victim Identity Information
- Sub-technique
- T1589.002 Email Addresses
- Canonical reference
- https://attack.mitre.org/techniques/T1589/002/
KQL Detection Query
// Detect Azure AD email address enumeration via sign-in log error analysis
// Error 50034 = UserAccountNotFound (username does not exist in tenant)
// Error 50126 = InvalidPasswordOrUsername (username exists but wrong credential)
// High ratio of 50034 errors with many unique UPNs from one IP = enumeration
let EnumerationThreshold = 10;
let TimeWindow = 1h;
SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType in ("50034", "50053", "50055", "50056")
| where isnotempty(IPAddress)
| summarize
UniqueUsernames = dcount(UserPrincipalName),
AttemptCount = count(),
UsernameSample = make_set(UserPrincipalName, 25),
AppList = make_set(AppDisplayName, 10),
Earliest = min(TimeGenerated),
Latest = max(TimeGenerated)
by IPAddress, ClientAppUsed, UserAgent, bin(TimeGenerated, 1h)
| where UniqueUsernames >= EnumerationThreshold
| extend DurationMinutes = datetime_diff('minute', Latest, Earliest) + 1
| extend EnumerationRatePerMin = round(toreal(UniqueUsernames) / toreal(DurationMinutes), 2)
| extend Verdict = case(
UniqueUsernames >= 50, "High Confidence Enumeration",
UniqueUsernames >= 20, "Moderate Enumeration",
"Low-Level Enumeration"
)
| project TimeGenerated, IPAddress, ClientAppUsed, UserAgent, UniqueUsernames, AttemptCount, EnumerationRatePerMin, DurationMinutes, AppList, UsernameSample, Verdict, Earliest, Latest
| sort by UniqueUsernames desc Detects email address enumeration against Azure AD / Office 365 by analyzing sign-in failure patterns in SigninLogs. Error code 50034 (UserAccountNotFound) fires when a queried username does not exist in the tenant — enumeration tools such as AADInternals, o365enum, and custom scripts exploit this distinction to identify valid email addresses. The query aggregates unique UserPrincipalName values per source IP within rolling 1-hour windows, flagging IPs that probe more than 10 unique usernames. EnumerationRatePerMin provides velocity context for prioritization.
Data Sources
Required Tables
False Positives & Tuning
- Misconfigured identity federation or SSO systems repeatedly probing with malformed UPN formats across many users during bulk authentication failures
- Penetration testing engagements against the tenant's Office 365 environment using legitimate enumeration tooling
- Automated user provisioning or deprovisioning workflows that check account existence before creating or removing accounts, generating bursts of 50034 errors
- Password reset portal integrations or helpdesk tools that validate email addresses against Azure AD at scale during employee onboarding events
- Load-testing or integration testing of authentication flows using test email addresses that do not exist in the tenant
Other platforms for T1589.002
Testing Methodology
Validate this detection against 5 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1Azure AD Email Enumeration via GetCredentialType API (PowerShell)
Expected signal: Sysmon Event ID 1: PowerShell.exe process with CommandLine containing 'GetCredentialType' and 'login.microsoftonline.com'. Sysmon Event ID 3: Outbound network connections from powershell.exe to login.microsoftonline.com (TCP 443). Proxy/web filter logs: HTTP POST to login.microsoftonline.com/common/GetCredentialType with PowerShell User-Agent. DeviceNetworkEvents in MDE: InitiatingProcessFileName=powershell.exe, RemoteUrl containing GetCredentialType.
- Test 2Azure AD Email Enumeration via AADInternals Module
Expected signal: Sysmon Event ID 1: powershell.exe with CommandLine containing 'AADInternals' and 'UserEnumerationAsOutsider'. Sysmon Event ID 3: Network connections to login.microsoftonline.com and related Microsoft AAD endpoints. PowerShell ScriptBlock Log Event ID 4104 capturing the full module invocation. Windows Security Event ID 4688: Process creation for powershell.exe with command line auditing enabled. Proxy logs: HTTP requests with AADInternals User-Agent string to Microsoft authentication endpoints.
- Test 3Email Enumeration via Sign-in Attempt with Non-Existent Accounts (Generates SigninLogs 50034)
Expected signal: Azure AD SigninLogs: 10 entries with ResultType=50034 (UserAccountNotFound) for each probed address, all from the same source IP. These entries are visible in the Azure Portal under Azure AD > Sign-in logs and in Microsoft Sentinel's SigninLogs table within 5-15 minutes. Field ClientAppUsed will show 'Other clients'.
- Test 4OSINT Email Harvesting Simulation via Python Requests (LinkedIn/Web Scraping Pattern)
Expected signal: Sysmon Event ID 1: python3.exe process creation with CommandLine containing 'theHarvester' User-Agent string. Sysmon Event ID 3: Network connections from python3.exe to target hosts over TCP 443/80. DeviceNetworkEvents in MDE: InitiatingProcessFileName=python3.exe, RemoteUrl matching target sites. Proxy logs: HTTP GET requests with theHarvester User-Agent string — this User-Agent string is well-known and often blocked/alerted by web proxies.
- Test 5Exchange Autodiscover Email Validation Probe (curl)
Expected signal: Sysmon Event ID 1: curl.exe process creation with CommandLine containing 'autodiscover' and target email addresses. Sysmon Event ID 3: Outbound network connections from curl.exe to autodiscover.targetdomain.com over TCP 443. Exchange IIS Access Logs (W3SVC): POST requests to /autodiscover/autodiscover.xml with 401 response codes, source IP, and User-Agent 'curl/*'. Windows Security Event ID 4625 (Logon Failure): if Basic Authentication is attempted against Exchange.
References (9)
- https://attack.mitre.org/techniques/T1589/002/
- https://o365blog.com/post/just-looking/
- https://github.com/gremwell/o365enum
- https://grimhacker.com/2017/07/24/office365-activesync-username-enumeration/
- https://www.hackers-arise.com/email-scraping-and-maltego
- https://www.cnet.com/news/massive-breach-leaks-773-million-emails-21-million-passwords/
- https://learn.microsoft.com/en-us/azure/active-directory/reports-monitoring/concept-sign-ins
- https://github.com/dafthack/MSOLSpray
- https://github.com/0xZDH/o365spray
Unlock Pro Content
Get the full detection package for T1589.002 including response playbook, investigation guide, and atomic red team tests.