T1591

Gather Victim Org Information

Reconnaissance Last updated:

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/
Microsoft Sentinel / Defender
kusto
// 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.

high severity medium confidence

Data Sources

Azure Active Directory Microsoft Entra ID

Required Tables

AuditLogs

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:


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.

  1. 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.

  2. 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.

  3. 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

  1. 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.
  2. 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.
  3. 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.
  4. 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)?
  5. 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?
  6. 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.
  7. 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

  1. Revoke all active sessions for the suspected account using Azure AD: Revoke-AzureADUserAllRefreshToken or via the Entra portal — Users > [user] > Revoke sessions.
  2. 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.
  3. Reset the account password and require re-registration of MFA factors if account takeover is confirmed.
  4. Apply a Conditional Access policy to block sign-ins from the identified source IP or ASN while investigation is ongoing.
  5. 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

  1. Export full AuditLogs for the initiating account for the 7 days prior to the alert, saved as CSV/JSON for case record.
  2. Export SigninLogs for the same account over the same window, noting device IDs, user agents, IPs, and MFA states.
  3. Capture the complete list of TargetResources (user/group objects) queried to understand exactly what org data was accessed.
  4. 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.
  5. Capture OAuth consent grants for any service principal involved: Get-AzureADServicePrincipalOAuth2PermissionGrant.
  6. 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.

Hunting — KQL
kql
// 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
Hunting — SPL
spl
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.

Hunting — KQL
kql
// 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
Hunting — SPL
spl
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.

Hunting — KQL
kql
// 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
Hunting — SPL
spl
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

Test 1 Azure AD Bulk User Enumeration via Microsoft Graph PowerShell
windows

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

powershell
# 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

powershell
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

Test 2 OSINT Tool Execution — theHarvester Org Reconnaissance
linux

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

bash
# 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

bash
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.

Test 3 Social Engineering Email — Org Structure Elicitation (Phishing for Information)
windows

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

powershell
# 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

powershell
# 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.

Related Detections