Gather Victim Org Information
This detection identifies adversary attempts to gather organizational information about the victim, including employee roles, departmental structure, business operations, and key personnel. Because T1591 is a PRE-ATT&CK technique primarily executed outside the defender's network, direct endpoint telemetry is limited. Detection pivots to observable side-effects: Azure AD and Microsoft Graph API enumeration of users, groups, and org hierarchy; inbound phishing-for-information email patterns; unusual bulk access to internal directories or SharePoint org charts; and outbound access to known OSINT/data-broker platforms (LinkedIn, ZoomInfo, Hunter.io) at volume. These signals correlate with early-stage targeting by threat actors such as APT28, Kimsuky, Lazarus Group, and FIN7, who conduct org reconnaissance prior to tailored spearphishing campaigns.
What is T1591 Gather Victim Org Information?
Gather Victim Org Information (T1591) maps to the Reconnaissance tactic — the adversary is trying to gather information they can use to plan future operations in MITRE ATT&CK.
This page provides production-ready detection logic for Gather Victim Org Information, covering the data sources and telemetry it touches: Azure Active Directory, Microsoft Entra ID. The queries below are rated high severity at medium confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.
MITRE ATT&CK
- Tactic
- Reconnaissance
- Technique
- T1591 Gather Victim Org Information
- Canonical reference
- https://attack.mitre.org/techniques/T1591/
// T1591 — Gather Victim Org Information
// Detect bulk Azure AD / MS Graph enumeration of org structure (users, groups, roles, org details)
// This pattern indicates an authenticated attacker or compromised account mapping the org before deeper targeting
let LookbackWindow = 1h;
let EnumThreshold = 30;
let DistinctOpThreshold = 3;
AuditLogs
| where TimeGenerated >= ago(LookbackWindow)
| where OperationName in (
"Get users",
"List users",
"Get groups",
"List groups",
"Get members",
"Get organization",
"Get directoryRoles",
"List directoryRoleMembers",
"Get contacts",
"List contacts",
"Get administrativeUnits",
"List administrativeUnits"
)
| where Result == "success"
| extend InitiatorUPN = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatorIP = tostring(InitiatedBy.user.ipAddress)
| extend AppDisplayName = tostring(InitiatedBy.app.displayName)
| where isnotempty(InitiatorUPN) or isnotempty(AppDisplayName)
| summarize
OperationCount = count(),
DistinctOperations = dcount(OperationName),
Operations = make_set(OperationName),
DistinctTargets = dcount(tostring(TargetResources)),
EarliestEvent = min(TimeGenerated),
LatestEvent = max(TimeGenerated)
by InitiatorUPN, InitiatorIP, AppDisplayName, bin(TimeGenerated, LookbackWindow)
| where OperationCount >= EnumThreshold or DistinctOperations >= DistinctOpThreshold
| extend RiskScore = case(
OperationCount >= 100 and DistinctOperations >= 5, "High",
OperationCount >= 50 or DistinctOperations >= 4, "Medium",
"Low"
)
| project
TimeGenerated,
InitiatorUPN,
InitiatorIP,
AppDisplayName,
OperationCount,
DistinctOperations,
DistinctTargets,
Operations,
RiskScore,
EarliestEvent,
LatestEvent
| order by OperationCount desc Detects bulk enumeration of Azure Active Directory organizational structure via Audit Logs. Adversaries with compromised credentials or OAuth tokens enumerate users, groups, roles, and administrative units to map the target organization before launching tailored spearphishing or lateral movement. Alerts fire when a single initiator performs 30+ org-enumeration operations or 3+ distinct operation types within a 1-hour window.
Data Sources
Required Tables
False Positives
- IT automation scripts running bulk user provisioning or deprovisioning workflows
- HR system sync tools (Workday, BambooHR) performing scheduled directory synchronization
- Security tools such as Microsoft Entra ID Governance performing access reviews
- PowerShell scripts run by directory administrators for legitimate reporting
Sigma rule & cross-platform mapping
The detection logic for Gather Victim Org Information (T1591) above is provided in a vendor-neutral
form so you can deploy it on any SIEM. The same logic is shipped here as native
KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the
following logsource:
logsource:
product: azure Browse the community-maintained Sigma rules for this technique:
Platform-specific guides for T1591
References (10)
- https://attack.mitre.org/techniques/T1591/
- https://attack.mitre.org/techniques/T1591/001/
- https://attack.mitre.org/techniques/T1591/002/
- https://attack.mitre.org/techniques/T1591/003/
- https://attack.mitre.org/techniques/T1591/004/
- https://www.microsoft.com/en-us/security/blog/2024/05/28/moonstone-sleet-emerges-as-new-north-korean-threat-actor-with-new-bag-of-tricks/
- https://learn.microsoft.com/en-us/azure/active-directory/reports-monitoring/concept-audit-logs
- https://learn.microsoft.com/en-us/graph/permissions-reference
- https://www.cisa.gov/sites/default/files/2023-01/aa23-025a_joint_csa_understanding_and_mitigating_russian_state-sponsored_cyber_threats_to_us_critical_infrastructure_1.pdf
- https://threatpost.com/broadvoice-leaks-350m-records-exposes-voip-company-client-data/160158/
Testing Methodology
Validate this detection against 3 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 Bulk User Enumeration via Microsoft Graph PowerShell
Expected signal: Azure AD AuditLogs: multiple entries for 'Get users', 'List users', 'Get groups', 'List groups', 'Get directoryRoles' with InitiatedBy set to the test account UPN. Volume should exceed the 30-operation threshold within minutes.
- Test 2OSINT Tool Execution — theHarvester Org Reconnaissance
Expected signal: Outbound HTTP/HTTPS connections to linkedin.com, google.com, bing.com with tool user-agent strings from the attacking host. DNS queries for target domain variations. Proxy logs showing linkedin.com/in/ path access at volume.
- Test 3Social Engineering Email — Org Structure Elicitation (Phishing for Information)
Expected signal: EmailEvents entry with SenderFromDomain=atomictest.invalid, Subject containing 'org chart' and 'reporting structure', DeliveryAction=Delivered. Microsoft Defender for Office 365 may flag based on sender reputation.
Response Playbook
Triage
- Step 1: Identify the initiating account (InitiatorUPN) and application (AppDisplayName). Determine if this is a service principal, user account, or OAuth application performing the enumeration.
- Step 2: Review the source IP (InitiatorIP). Geolocate the IP — unexpected countries, VPN/Tor exit nodes, cloud hosting providers (AWS, Azure, GCP IPs not owned by your org), or anonymization services are high-risk indicators.
- Step 3: Query SigninLogs for the same account in the same time window. Check MFA status, device compliance, conditional access results, and any impossible travel or atypical location signals.
- Step 4: Pull the complete list of OperationNames and TargetResources from AuditLogs for the initiating account over the past 24 hours. Map the breadth of enumeration — did they also access sensitive groups (Domain Admins, Executive Team, Finance)?
- Step 5: Check for downstream activity. Did the same account attempt any email sends, file access (SharePoint/OneDrive), or authentication to other services shortly after the enumeration window?
- Step 6: If an application/service principal: review the OAuth consent grants for that app, check when it was registered, and verify it is in the approved app inventory. Unauthorized OAuth apps are a common post-phishing technique.
- Step 7: Contact the account owner via out-of-band channel (phone or Slack) to confirm whether they initiated this activity. Do not alert via email if account may be compromised.
Containment
- Revoke all active sessions for the suspected account using Azure AD: Revoke-AzureADUserAllRefreshToken or via the Entra portal — Users > [user] > Revoke sessions.
- If a compromised service principal or OAuth app is suspected, immediately revoke its OAuth tokens and disable the application registration in Entra ID App Registrations.
- Reset the account password and require re-registration of MFA factors if account takeover is confirmed.
- Apply a Conditional Access policy to block sign-ins from the identified source IP or ASN while investigation is ongoing.
- If org enumeration data was likely exfiltrated, notify the security team to prepare for targeted spearphishing against the identified employee list within 24-72 hours.
Evidence Collection
- Export full AuditLogs for the initiating account for the 7 days prior to the alert, saved as CSV/JSON for case record.
- Export SigninLogs for the same account over the same window, noting device IDs, user agents, IPs, and MFA states.
- Capture the complete list of TargetResources (user/group objects) queried to understand exactly what org data was accessed.
- If Microsoft Defender for Office 365 is licensed: run an email trace (Get-MessageTrace) for the initiating account's email address for inbound messages in the prior 30 days to identify potential phishing-for-information precursor emails.
- Capture OAuth consent grants for any service principal involved: Get-AzureADServicePrincipalOAuth2PermissionGrant.
- Document the source ASN, hosting provider, and any Threat Intelligence hits on the source IP from VirusTotal, Shodan, or your TI platform.
Escalation Criteria
- ! Escalate immediately if the source IP belongs to a known threat actor ASN or has prior TI hits for credential stuffing, phishing, or APT infrastructure.
- ! Escalate if the enumerated groups include executive leadership, IT admins, finance, or HR — these indicate targeting for business email compromise or executive spearphishing.
- ! Escalate if any subsequent spearphishing emails referencing specific employee names or org structure are received within 72 hours of the enumeration event.
- ! Escalate if the initiating account shows impossible travel (e.g., sign-in from Chicago then Moscow within 2 hours) or other account compromise indicators.
- ! Escalate if a non-approved OAuth application performed the enumeration — indicates a malicious OAuth phishing app may have been consented to by an employee.
Investigation Guide
Forensic Artifacts
- >
Azure AD Audit Logs: OperationName, InitiatedBy, TargetResources, ResultReason - >
Azure AD Sign-In Logs: UserPrincipalName, IPAddress, DeviceDetail, ConditionalAccessStatus, RiskLevel - >
Microsoft Graph API access logs (unified audit log category: AzureActiveDirectory) - >
OAuth consent grant records in Entra ID App Registrations - >
Email headers and body of any phishing-for-information precursor messages - >
Microsoft Defender for Office 365 email entity data (sender reputation, links, attachments) - >
Network proxy logs showing outbound connections to data broker sites (LinkedIn, ZoomInfo, Hunter.io, RocketReach, Clearbit)
Tuning Guidance
The primary tuning lever is the OperationCount threshold (default: 30/hour). In environments with active HR sync tools or Entra ID Governance reviews, this may need to be raised to 100+ or filtered by known service-principal ObjectIDs in an allowlist. Create a watchlist of approved automation service principals (Workday connector, Okta provisioning agent, etc.) and exclude them from the AuditLogs query using '| where InitiatorUPN !in (WatchlistData)'. For the email hunting query, the subject-line keyword list will generate noise in organisations that handle vendor relationship management; tune by excluding known internal sender domains. The proxy/network hunting query for OSINT platforms should be baseline-compared per user — a recruiter accessing LinkedIn 50 times per day is normal, but an engineer in R&D is not. Consider enriching with department/role data from your HR system via a watchlist join.
Hunting Queries
Hunts for OAuth application consent grants that include high-privilege directory read permissions — a common technique where phished users unknowingly consent to a malicious app that then silently enumerates the org.
// Hunt 1: Detect service principals with abnormally broad Graph API enumeration permissions
// that have recently become active — potential malicious OAuth app
AuditLogs
| where TimeGenerated >= ago(30d)
| where Category == "ApplicationManagement"
| where OperationName in ("Consent to application", "Add app role assignment to service principal", "Add delegated permission grant")
| extend AppId = tostring(TargetResources[0].id)
| extend AppName = tostring(TargetResources[0].displayName)
| extend ConsentingUser = tostring(InitiatedBy.user.userPrincipalName)
| extend GrantedPermissions = tostring(TargetResources[0].modifiedProperties)
| where GrantedPermissions has_any ("User.Read.All", "Group.Read.All", "Directory.Read.All", "OrgContact.Read.All", "People.Read.All")
| project TimeGenerated, AppName, AppId, ConsentingUser, GrantedPermissions
| order by TimeGenerated desc index=* (sourcetype="ms:aad:audit" OR sourcetype="o365:management:activity")
OperationName IN ("Consent to application", "Add app role assignment to service principal", "Add delegated permission grant")
| eval AppName=mvindex('TargetResources{}.displayName', 0)
| eval ConsentingUser=coalesce('InitiatedBy.user.userPrincipalName', 'UserId')
| eval Permissions=coalesce('TargetResources{}.modifiedProperties{}.newValue', "")
| where match(Permissions, "User\\.Read\\.All|Group\\.Read\\.All|Directory\\.Read\\.All|OrgContact\\.Read\\.All|People\\.Read\\.All")
| table _time, AppName, ConsentingUser, Permissions
| sort - _time Hunts for inbound emails with subject lines containing organizational reconnaissance language — adversaries may directly email employees requesting org charts, key contacts, or vendor/partner information as part of T1591/T1598 targeting.
// Hunt 2: Detect inbound emails that attempt to elicit org structure information
// using social engineering language patterns (Phishing for Information / T1598)
EmailEvents
| where TimeGenerated >= ago(7d)
| where DeliveryAction != "Blocked"
| where EmailDirection == "Inbound"
| extend SubjectLower = tolower(Subject)
| where SubjectLower has_any (
"org chart",
"organization chart",
"reporting structure",
"team structure",
"who is responsible",
"point of contact",
"key contacts",
"department head",
"vendor list",
"supplier list",
"business partner",
"your cfo",
"your ceo",
"decision maker"
)
| project TimeGenerated, SenderFromAddress, SenderFromDomain, RecipientEmailAddress, Subject, DeliveryLocation, ThreatTypes
| order by TimeGenerated desc index=* sourcetype IN ("ms:o365:emailmessage", "o365:management:activity", "exchange:messagetrace")
Operation=MessageReceived OR RecordType=28
| where Direction="Inbound" OR RecipientStatus!="Blocked"
| eval SubjectLower=lower(Subject)
| where match(SubjectLower, "org chart|organization chart|reporting structure|team structure|who is responsible|point of contact|key contacts|department head|vendor list|supplier list|business partner")
| table _time, SenderAddress, RecipientAddress, Subject, DeliveryStatus
| sort - _time Hunts for endpoints making unusually high-volume requests to OSINT, people-search, and data-broker platforms. An attacker on a compromised internal host, or a malicious insider, may use these services to map the target org's employee structure, business relationships, and contact details.
// Hunt 3: Detect outbound web proxy traffic to known OSINT / people-search / data broker platforms
// at anomalous volume — may indicate an insider or compromised host performing org reconnaissance
DeviceNetworkEvents
| where TimeGenerated >= ago(7d)
| where RemoteUrl has_any (
"linkedin.com/in/",
"linkedin.com/company/",
"zoominfo.com",
"hunter.io",
"rocketreach.co",
"clearbit.com",
"apollo.io",
"lusha.com",
"signalhire.com",
"contactout.com",
"spokeo.com",
"pipl.com",
"intelius.com"
)
| summarize
RequestCount = count(),
DistinctURLs = dcount(RemoteUrl),
Domains = make_set(RemoteUrl),
EarliestAccess = min(TimeGenerated),
LatestAccess = max(TimeGenerated)
by DeviceName, InitiatingProcessAccountName, bin(TimeGenerated, 1d)
| where RequestCount >= 20 or DistinctURLs >= 5
| order by RequestCount desc index=* (sourcetype="cisco:proxy" OR sourcetype="bluecoat:proxysg:access:kv" OR sourcetype="pan:traffic" OR sourcetype="stream:http")
| where match(url, "linkedin\\.com/(in|company)/|zoominfo\\.com|hunter\\.io|rocketreach\\.co|clearbit\\.com|apollo\\.io|lusha\\.com|signalhire\\.com|contactout\\.com|spokeo\\.com|pipl\\.com|intelius\\.com")
| eval domain=replace(url, "^https?://([^/]+)/.*", "\\1")
| bin _time span=1d
| stats
count AS RequestCount,
dc(url) AS DistinctURLs,
values(domain) AS Domains
by _time, src_ip, user
| where RequestCount >= 20 OR DistinctURLs >= 5
| sort - RequestCount Atomic Red Team Tests
Simulates adversary org reconnaissance by authenticating to Microsoft Graph and enumerating all users, groups, and directory roles — generating the AuditLogs signals this detection targets.
Command
# Requires: Install-Module Microsoft.Graph -Scope CurrentUser
# Run with a test account that has User.Read.All / Group.Read.All permissions
Connect-MgGraph -Scopes "User.Read.All","Group.Read.All","Directory.Read.All"
# Enumerate all users (simulates T1591.004 - Identify Roles)
$users = Get-MgUser -All -Property DisplayName,JobTitle,Department,Mail,Manager | Select-Object DisplayName,JobTitle,Department,Mail
Write-Output "Enumerated $($users.Count) users"
# Enumerate all groups (simulates T1591 org structure mapping)
$groups = Get-MgGroup -All -Property DisplayName,Description,GroupTypes | Select-Object DisplayName,Description
Write-Output "Enumerated $($groups.Count) groups"
# Enumerate directory roles (simulates T1591.004 - Identify Roles)
$roles = Get-MgDirectoryRole -All | ForEach-Object {
$members = Get-MgDirectoryRoleMember -DirectoryRoleId $_.Id
[PSCustomObject]@{ Role=$_.DisplayName; MemberCount=$members.Count }
}
$roles | Format-Table
# Output to file for exfil simulation
$users | Export-Csv -Path "$env:TEMP\org_users.csv" -NoTypeInformation
$groups | Export-Csv -Path "$env:TEMP\org_groups.csv" -NoTypeInformation
Write-Output "Org data written to $env:TEMP\org_users.csv and org_groups.csv" Cleanup
Remove-Item "$env:TEMP\org_users.csv" -ErrorAction SilentlyContinue
Remove-Item "$env:TEMP\org_groups.csv" -ErrorAction SilentlyContinue
Disconnect-MgGraph Expected Telemetry
Azure AD AuditLogs: multiple entries for 'Get users', 'List users', 'Get groups', 'List groups', 'Get directoryRoles' with InitiatedBy set to the test account UPN. Volume should exceed the 30-operation threshold within minutes.
Expected Detection
T1591 alert: Bulk Azure AD Org Enumeration — OperationCount >= 30 within 1h window for test account UPN
Simulates adversary OSINT gathering against the target organization using theHarvester to enumerate employee emails, names, and subdomains from public sources. Tests whether proxy/network detections or UEBA tools flag the outbound OSINT queries.
Command
# Install theHarvester if not present
pip3 install theHarvester --quiet
# Replace TARGET_DOMAIN with your authorized test domain
TARGET_DOMAIN="example.com"
# Enumerate using LinkedIn (simulates T1591.004 Identify Roles)
theHarvester -d $TARGET_DOMAIN -b linkedin -l 200 -f /tmp/harvest_linkedin.xml
# Enumerate using search engines for email/name patterns
theHarvester -d $TARGET_DOMAIN -b google,bing,duckduckgo -l 500 -f /tmp/harvest_web.xml
# Parse and display results
grep -oP '(?<=<email>)[^<]+' /tmp/harvest_web.xml 2>/dev/null | sort -u
echo "Harvesting complete. Results in /tmp/harvest_linkedin.xml and /tmp/harvest_web.xml" Cleanup
rm -f /tmp/harvest_linkedin.xml /tmp/harvest_web.xml
pip3 uninstall theHarvester -y --quiet Expected Telemetry
Outbound HTTP/HTTPS connections to linkedin.com, google.com, bing.com with tool user-agent strings from the attacking host. DNS queries for target domain variations. Proxy logs showing linkedin.com/in/ path access at volume.
Expected Detection
Network hunting query: Outbound OSINT platform access (linkedin.com) at anomalous volume from non-recruiter device. UEBA anomaly if baseline deviates significantly.
Simulates a T1598/T1591 phishing-for-information email using PowerShell to send an inbound test message with org-reconnaissance subject/body language. Tests whether email hunting queries and DLP rules detect the social engineering attempt.
Command
# Simulates receiving a phishing-for-information email with social engineering content
# Uses Office 365 REST API to inject a test message into a monitored mailbox
# Replace variables with your authorized test tenant values
$TenantId = "YOUR_TENANT_ID"
$ClientId = "YOUR_APP_CLIENT_ID"
$ClientSecret = "YOUR_APP_CLIENT_SECRET"
$TargetMailbox = "[email protected]"
# Get OAuth token
$body = @{
grant_type = "client_credentials"
client_id = $ClientId
client_secret = $ClientSecret
scope = "https://graph.microsoft.com/.default"
}
$token = (Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" -Method Post -Body $body).access_token
# Craft social engineering org-recon email
$headers = @{ Authorization = "Bearer $token"; "Content-Type" = "application/json" }
$emailPayload = @{
message = @{
subject = "Quick question about your org chart and reporting structure"
body = @{
contentType = "Text"
content = "Hi, I'm reaching out to understand who the key decision makers are in your IT and finance departments. Could you share your org chart or let me know who is responsible for vendor procurement? Also curious about your business partners and who your CFO reports to. Thanks!"
}
toRecipients = @(@{ emailAddress = @{ address = $TargetMailbox } })
from = @{ emailAddress = @{ address = "[email protected]" } }
}
saveToSentItems = $false
} | ConvertTo-Json -Depth 5
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/users/$TargetMailbox/sendMail" -Method Post -Headers $headers -Body $emailPayload
Write-Output "Test phishing-for-information email delivered to $TargetMailbox" Cleanup
# Delete the test email from the target mailbox via Graph API search + delete
# Or manually delete from mailbox in Outlook Expected Telemetry
EmailEvents entry with SenderFromDomain=atomictest.invalid, Subject containing 'org chart' and 'reporting structure', DeliveryAction=Delivered. Microsoft Defender for Office 365 may flag based on sender reputation.
Expected Detection
Email hunting query: Inbound email with subject containing org-reconnaissance keywords ('org chart', 'reporting structure', 'decision maker'). Alert should fire for EmailEvents query.