T1591

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.

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

Unlock Pro Content

Get the full detection package for T1591 including response playbook, investigation guide, and atomic red team tests.

Response PlaybookInvestigation GuideHunting QueriesAtomic Red Team TestsTuning Guidance

Related Detections