{
  "technique_id": "T1087",
  "name": "Account Discovery",
  "priority": "high",
  "status": "draft",
  "version": "0.1.0",
  "last_reviewed": "2026-07-23",
  "generated_by": "SOC Response Atlas by Basyrix",
  "tactics": [
    "Discovery"
  ],
  "platforms": [
    "ESXi",
    "IaaS",
    "Identity Provider",
    "Linux",
    "macOS",
    "Office Suite",
    "SaaS",
    "Windows"
  ],
  "summary": "Adversaries may attempt to get a listing of valid accounts, usernames, or email addresses on a system or within a compromised environment. This information can help adversaries determine which accounts exist, which can aid in follow-on behavior such as brute-forcing, spear-phishing attacks, or account takeovers (e.g., [Valid Accounts](https://attack.mitre.org/techniques/T1078))...",
  "soc_recommendation": "Investigate Account Discovery activity in the context of Discovery: confirm scope, affected host/identity, and whether it matches expected administrative behaviour before deciding this is benign.",
  "d3fend_mappings": [
    {
      "id": "D3-LAM",
      "name": "Local Account Monitoring",
      "relationship": "detect",
      "practical_action": "Monitor for Local Account Monitoring indicators relevant to this technique.",
      "tooling": [
        "Entra ID"
      ]
    },
    {
      "id": "D3-AA",
      "name": "Agent Authentication",
      "relationship": "harden",
      "practical_action": "Apply Agent Authentication to reduce this technique's viability before an incident occurs.",
      "tooling": [
        "Defender for Endpoint"
      ]
    },
    {
      "id": "D3-AL",
      "name": "Account Locking",
      "relationship": "evict",
      "practical_action": "Use Account Locking to remove the adversary's foothold once this technique is confirmed.",
      "tooling": [
        "Entra ID"
      ]
    },
    {
      "id": "D3-UAP",
      "name": "User Account Permissions",
      "relationship": "isolate",
      "practical_action": "Apply User Account Permissions to contain the blast radius once this technique is observed.",
      "tooling": [
        "Entra ID"
      ]
    }
  ],
  "investigation_steps": {
    "microsoft": [
      "Review Defender for Endpoint / Defender XDR alerts and timeline for the affected host or identity.",
      "Check Sentinel analytics rules and incidents correlated with this technique.",
      "Review Entra ID sign-in and audit logs if the technique involves an identity or cloud resource."
    ],
    "generic": [
      "Confirm whether the observed account discovery activity matches expected administrative or application behaviour.",
      "Identify the host, account, or resource where the activity occurred and its business criticality.",
      "Check for related alerts before and after this activity to reconstruct the broader intrusion timeline.",
      "Real detection reference: \"AD Reconnaissance Tooling Execution\" -- Flags execution of common Active Directory enumeration tools (AdFind, dsquery, BloodHound/SharpHound, PowerView) used for domain account and trust discovery."
    ]
  },
  "evidence_to_collect": [
    "Host or resource affected",
    "Account or identity involved",
    "Timestamp of the activity",
    "Related process, file, or network artifact",
    "Any preceding or follow-on alerts"
  ],
  "response_actions": [
    {
      "name": "Contain the affected host or account",
      "category": "Containment",
      "risk": "Medium",
      "automation_safe": false,
      "approval_required": true,
      "tool": "Defender for Endpoint / Entra ID",
      "notes": "Requires approval -- confirm malicious intent before isolating a host or disabling an account."
    },
    {
      "name": "Collect and preserve evidence",
      "category": "Investigation",
      "risk": "Low",
      "automation_safe": true,
      "approval_required": false,
      "tool": "Defender for Endpoint",
      "notes": "Safe -- read-only evidence collection."
    }
  ],
  "queries": {
    "kql": [
      {
        "name": "GEN-DI-001 — AD Reconnaissance Tooling Execution",
        "description": "Flags execution of common Active Directory enumeration tools (AdFind, dsquery, BloodHound/SharpHound, PowerView) used for domain account and trust discovery. (Source: Bell Integration baseline detection library, mapped via sub-technique T1087.002.)",
        "query": "let ReconTools = dynamic([\n    \"adfind.exe\",\n    \"dsquery.exe\",\n    \"sharphound.exe\",\n    \"bloodhound.exe\"\n]);\nlet ReconCommandPatterns = dynamic([\n    \"Get-DomainUser\",\n    \"Get-DomainGroup\",\n    \"Get-DomainTrust\",\n    \"Get-NetUser\",\n    \"Get-NetGroup\",\n    \"Invoke-BloodHound\"\n]);\nDeviceProcessEvents\n| where TimeGenerated >= ago(1d)\n| where FileName in~ (ReconTools) or ProcessCommandLine has_any (ReconCommandPatterns)\n| project\n    TimeGenerated,\n    DeviceName,\n    DeviceId,\n    AccountName,\n    FileName,\n    ProcessCommandLine,\n    InitiatingProcessFileName,\n    InitiatingProcessCommandLine\n| extend timestamp = TimeGenerated,\n         HostCustomEntity = DeviceName,\n         AccountCustomEntity = AccountName\n| order by TimeGenerated desc"
      },
      {
        "name": "25c86f99-0a91-4b7f-88f3-599a008e5ab8 — API - Account Takeover",
        "description": "42Crunch API protection against account takeover' (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
        "query": "let firstRec = FortyTwoCrunchAPIProtection\n| where TimeGenerated >= ago(5m) \n| project-away NonBlockingMode, SourcePort, DestinationPort, Query, ApiId, RequestHeader, ResponseHeader, Errors, EventType, Uuid\n| where (UriPath has \"/api/register\" or UriPath has \"/api/reset\") and Status == 403;\nlet recCount = iff((toscalar(firstRec | count) >= 20), 1, 0);\nfirstRec | take recCount"
      },
      {
        "name": "c63ae777-d5e0-4113-8c9a-c2c9d3d09fcd — Probable AdFind Recon Tool Usage",
        "description": "This query identifies the host and account that executed AdFind, by hash and filename, in addition to the flags commonly utilized by various threat actors during the reconnaissance phase.' (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed), mapped via sub-technique T1087.002.)",
        "query": "let args = dynamic([\"objectcategory\",\"domainlist\",\"dcmodes\",\"adinfo\",\"trustdmp\",\"computers_pwdnotreqd\",\"Domain Admins\", \"objectcategory=person\", \"objectcategory=computer\", \"objectcategory=*\",\"dclist\"]);\nlet parentProcesses = dynamic([\"pwsh.exe\",\"powershell.exe\",\"cmd.exe\"]);\nDeviceProcessEvents\n//looks for execution from a shell\n| where InitiatingProcessFileName in~ (parentProcesses)\n// main filter\n| where FileName =~ \"AdFind.exe\" or SHA256 == \"c92c158d7c37fea795114fa6491fe5f145ad2f8c08776b18ae79db811e8e36a3\"\n   // AdFind common Flags to check for from various threat actor TTPs\n    or ProcessCommandLine has_any (args)\n| extend HostName = split(DeviceName, '.', 0)[0], DnsDomain = strcat_array(array_slice(split(DeviceName, '.'), 1, -1), '.'), FileHashAlgorithm = \"SHA256\""
      }
    ],
    "spl": [],
    "esql": [
      {
        "name": "80aa6cca-b343-457b-877e-5877cd71a1f8 — Azure AD Graph Potential Enumeration (ROADrecon)",
        "description": "(ESQL) Detects an Azure AD Graph (graph.windows.net) burst from a user-agent identifying as \"aiohttp\" (the default HTTP library used by ROADrecon's \"gather\" command) where a single calling identity issues many requests in a short window. ROADrecon walks every interesting directory object type via aiohttp, producing a large volume of requests from one user / source IP / UA triple... (Source: Elastic's official detection-rules repository (Elastic License v2).)",
        "query": "from logs-azure.aadgraphactivitylogs-* metadata _id, _version, _index\n\n| where data_stream.dataset == \"azure.aadgraphactivitylogs\"\n  and to_lower(user_agent.original) like \"*aiohttp*\"\n\n| eval Esql.target_endpoints = case(\n    url.path like \"*/eligibleRoleAssignments*\", \"eligibleRoleAssignments\",\n    url.path like \"*/roleAssignments*\",         \"roleAssignments\",\n    url.path like \"*/users*\",                   \"users\",\n    url.path like \"*/groups*\",                  \"groups\",\n    url.path like \"*/servicePrincipals*\",       \"servicePrincipals\",\n    url.path like \"*/applications*\",            \"applications\",\n    url.path like \"*/devices*\",                 \"devices\",\n    url.path like \"*/directoryRoles*\",          \"directoryRoles\",\n    url.path like \"*/roleDefinitions*\",         \"roleDefinitions\",\n    url.path like \"*/administrativeUnits*\",     \"administrativeUnits\",\n    url.path like \"*/contacts*\",                \"contacts\",\n    url.path like \"*/oauth2PermissionGrants*\",  \"oauth2PermissionGrants\",\n    url.path like \"*/authorizationPolicy*\",     \"authorizationPolicy\",\n    url.path like \"*/settings*\",                \"settings\",\n    url.path like \"*/policies*\",                \"policies\",\n    url.path like \"*/tenantDetails*\",           \"tenantDetails\",\n    \"other\"\n  )\n| where Esql.target_endpoints != \"other\"\n\n| eval Esql.time_window = date_trunc(1 minutes, @timestamp)\n\n| stats\n    Esql.request_count                = count(*),\n    Esql.distinct_endpoints           = count_distinct(Esql.target_endpoints),\n    Esql.api_versions                 = values(azure.aadgraphactivitylogs.properties.api_version),\n    Esql.app_ids                      = values(azure.aadgraphactivitylogs.properties.app_id),\n    Esql.user_agent                   = values(user_agent.original),\n    Esql.http_methods                 = values(http.request.method),\n    Esql.status_codes                 = values(http.response.status_code),\n    Esql.source_ips                   = values(source.ip),\n    Esql.source_asn_orgs              = values(source.`as`.organization.name),\n    Esql.source_countries             = values(source.geo.country_name),\n    Esql.actor_types                  = values(azure.aadgraphactivitylogs.properties.actor_type),\n    Esql.client_auth_methods          = values(azure.aadgraphactivitylogs.properties.client_auth_method),\n    Esql.session_ids                  = values(azure.aadgraphactivitylogs.properties.session_id),\n    Esql.sign_in_activity_ids         = values(azure.aadgraphactivitylogs.properties.sign_in_activity_id),\n    Esql.scopes                       = values(azure.aadgraphactivitylogs.properties.scopes),\n    Esql.first_seen                   = min(@timestamp),\n    Esql.last_seen                    = max(@timestamp)\n  by\n    user.id,\n    azure.tenant_id,\n    Esql.time_window\n\n| where Esql.distinct_endpoints >= 5\n\n| keep\n    user.id,\n    azure.tenant_id,\n    Esql.*"
      },
      {
        "name": "3aec394d-ed2a-4f3e-8ed3-4a2adea39f05 — Azure AD Graph Access with Suspicious User-Agent",
        "description": "(ESQL) Identifies Azure AD Graph (graph.windows.net) requests originating from user-agent strings associated with offensive tooling, scripting libraries, or generic HTTP clients. First-party Microsoft components calling AAD Graph identify with specific user agents such as \"Microsoft Azure Graph Client Library\", \"Microsoft ADO.NET Data Services\", or \"Microsoft.OData.Client\"... (Source: Elastic's official detection-rules repository (Elastic License v2).)",
        "query": "from logs-azure.aadgraphactivitylogs-* metadata _id, _version, _index\n\n| where data_stream.dataset == \"azure.aadgraphactivitylogs\"\n    and azure.aadgraphactivitylogs.properties.actor_type == \"User\"\n    and user_agent.original is not null\n| eval Esql.ua_lower = to_lower(user_agent.original)\n| where Esql.ua_lower like \"*fasthttp*\"\n    or Esql.ua_lower like \"*aiohttp*\"\n    or Esql.ua_lower like \"*hound*\"\n    or Esql.ua_lower like \"*aadinternals*\"\n    or Esql.ua_lower like \"*go-http-client*\"\n    or Esql.ua_lower like \"python*\"\n    or Esql.ua_lower like \"*curl/*\"\n    or Esql.ua_lower like \"*okhttp*\"\n    or Esql.ua_lower like \"*axios*\"\n    or Esql.ua_lower like \"*node-fetch*\"\n    or Esql.ua_lower like \"*go-resty*\"\n    or Esql.ua_lower like \"*bav2ropc*\"\n    or Esql.ua_lower like \"*undici*\"\n| keep\n    _id,\n    _version,\n    _index,\n    @timestamp,\n    user.id,\n    source.ip,\n    source.as.organization.name,\n    user_agent.original,\n    azure.aadgraphactivitylogs.properties.app_id,\n    azure.aadgraphactivitylogs.properties.api_version,\n    url.path,\n    http.response.status_code,\n    azure.tenant_id,\n    Esql.ua_lower"
      }
    ]
  },
  "automation": {
    "safe": [
      "Add recommendation as Sentinel incident comment.",
      "Run enrichment queries.",
      "Create ServiceNow SecOps task."
    ],
    "approval_required": [
      "Contain or disable the affected host/account.",
      "Any change to production configuration."
    ]
  },
  "escalation_criteria": [
    "Account Discovery activity observed on a privileged account or critical system.",
    "Activity follows or precedes other suspicious behaviour in the same investigation.",
    "Automated triage cannot confidently rule out malicious intent."
  ],
  "false_positive_considerations": [
    "Legitimate administrative or maintenance activity matching this pattern.",
    "Approved security testing or red team exercise.",
    "Known benign software producing similar telemetry."
  ],
  "confluence": {
    "title": "T1087 - Account Discovery Response Guidance",
    "labels": [
      "mitre",
      "attack",
      "d3fend",
      "secops",
      "basyrix"
    ],
    "sections": [
      "summary",
      "d3fend_mappings",
      "investigation_steps",
      "response_actions",
      "queries",
      "automation",
      "escalation_criteria",
      "false_positive_considerations"
    ]
  }
}