{
  "technique_id": "T1069",
  "name": "Permission Groups Discovery",
  "priority": "high",
  "status": "draft",
  "version": "0.1.0",
  "last_reviewed": "2026-07-23",
  "generated_by": "SOC Response Atlas by Basyrix",
  "tactics": [
    "Discovery"
  ],
  "platforms": [
    "Containers",
    "IaaS",
    "Identity Provider",
    "Linux",
    "macOS",
    "Office Suite",
    "SaaS",
    "Windows"
  ],
  "summary": "Adversaries may attempt to discover group and permission settings. This information can help adversaries determine which user accounts and groups are available, the membership of users in particular groups, and which users and groups have elevated permissions. Adversaries may attempt to discover group permission settings in many different ways. This data may provide the adversary with information about the compromised environment that can be used in follow-on activity and targeting.",
  "soc_recommendation": "Investigate Permission Groups 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-NTA",
      "name": "Network Traffic Analysis",
      "relationship": "detect",
      "practical_action": "Monitor for Network Traffic Analysis indicators relevant to this technique.",
      "tooling": [
        "Sentinel",
        "Defender for Endpoint"
      ]
    }
  ],
  "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 permission groups 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: \"Probable AdFind Recon Tool Usage\" -- 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.'"
    ]
  },
  "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": "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 T1069.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\""
      },
      {
        "name": "9c4b1b9c-6462-41ce-8f2e-ce8c104331fc — OCI - Insecure metadata endpoint",
        "description": "Detects insecure metadata endpoint.' (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
        "query": "OCILogs\n| where data_request_headers_oci_original_url_s contains '/opc/v1' or data_request_headers_oci_original_url_s contains '/openstack'\n| where HttpStatusCode == 200\n| extend IPCustomEntity = DstIpAddr"
      },
      {
        "name": "4a433846-4b05-4a27-99d7-92093feded79 — GCP IAM - Publicly exposed storage bucket",
        "description": "Detects possible misconfiguration for bucket policy making it publicly available.' (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
        "query": "GCP_IAM\n| where PayloadMethodname =~ 'google.iam.v1.IAMPolicy.SetIamPolicy'\n| where ResourceType has 'bucket'\n| extend members = parse_json(todynamic(PayloadRequestPolicyBindings))[0]['members']\n| extend action = parse_json(todynamic(PayloadRequestPolicyBindings))[0]['action']\n| where members in~ ('allUsers', 'allAuthenticatedUsers')\n| where action =~ 'ADD'\n| extend AccountName = tostring(split(PayloadAuthenticationinfoPrincipalemail, \"@\")[0]), AccountUPNSuffix = tostring(split(PayloadAuthenticationinfoPrincipalemail, \"@\")[1])"
      }
    ],
    "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": [
    "Permission Groups 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": "T1069 - Permission Groups Discovery Response Guidance",
    "labels": [
      "mitre",
      "attack",
      "d3fend",
      "secops",
      "basyrix"
    ],
    "sections": [
      "summary",
      "d3fend_mappings",
      "investigation_steps",
      "response_actions",
      "queries",
      "automation",
      "escalation_criteria",
      "false_positive_considerations"
    ]
  }
}