{
  "technique_id": "T1580",
  "name": "Cloud Infrastructure Discovery",
  "priority": "medium",
  "status": "complete",
  "version": "0.1.0",
  "last_reviewed": "2026-07-23",
  "generated_by": "SOC Response Atlas by Basyrix",
  "tactics": [
    "Discovery"
  ],
  "platforms": [
    "IaaS"
  ],
  "summary": "An adversary may attempt to discover infrastructure and resources that are available within an infrastructure-as-a-service (IaaS) environment. This includes compute service resources such as instances, virtual machines, and snapshots as well as resources of other services including the storage and database services. Cloud providers offer methods such as APIs and commands issued through CLIs to serve information about infrastructure...",
  "soc_recommendation": "Investigate Cloud Infrastructure 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 cloud infrastructure 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: \"Cloud Resource and Tenant Enumeration\" -- Flags bulk enumeration of Azure resources or Entra ID directory objects by a single caller, consistent with post-compromise cloud environment mapping (Azure CLI/PowerShell, Stormspotter, ROADtools, AzureHound)."
    ]
  },
  "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": "Identify the tool making the requests (Azure CLI, SDK, custo",
      "category": "Response",
      "risk": "Low",
      "automation_safe": false,
      "approval_required": true,
      "tool": "See investigation guide",
      "notes": "Identify the tool making the requests (Azure CLI, SDK, custom script)"
    },
    {
      "name": "Revoke the credentials used if compromise confirmed",
      "category": "Response",
      "risk": "Medium",
      "automation_safe": false,
      "approval_required": true,
      "tool": "See investigation guide"
    },
    {
      "name": "Enable Azure Defender for Key Vault and Storage",
      "category": "Response",
      "risk": "Low",
      "automation_safe": false,
      "approval_required": true,
      "tool": "See investigation guide"
    }
  ],
  "queries": {
    "kql": [
      {
        "name": "GEN-DI-004 — Cloud Resource and Tenant Enumeration",
        "description": "Flags bulk enumeration of Azure resources or Entra ID directory objects by a single caller, consistent with post-compromise cloud environment mapping (Azure CLI/PowerShell, Stormspotter, ROADtools, AzureHound). (Source: Bell Integration baseline detection library.)",
        "query": "AzureActivity\n| where TimeGenerated >= ago(1h)\n| where OperationNameValue has_any (\"list\", \"List\", \"get\", \"Get\", \"read\", \"Read\")\n| where ResourceProviderValue has_any (\n    \"Microsoft.KeyVault\", \"Microsoft.Storage\", \"Microsoft.Compute\",\n    \"Microsoft.Sql\", \"Microsoft.Authorization\", \"Microsoft.Network\"\n)\n| summarize\n    StartTime = min(TimeGenerated),\n    EndTime = max(TimeGenerated),\n    ReadCount = count(),\n    ResourceTypes = dcount(ResourceProviderValue),\n    Operations = make_set(OperationNameValue, 10)\n    by Caller, CallerIpAddress, SubscriptionId\n| where ReadCount > 50 and ResourceTypes > 3\n| extend timestamp = StartTime, AccountCustomEntity = Caller, IPCustomEntity = CallerIpAddress\n| order by ReadCount desc"
      },
      {
        "name": "72891de4-da70-44e4-9984-35fcea98d000 — Privileged Machines Exposed to the Internet",
        "description": "These are AWS Ec2 machines that are exposed to the internet. You can further filter by tags so that you can, for example, find exposed machines that are also \"privileged\". (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
        "query": "Authomize_v2_CL\n| where ingestion_time() >= ago(30m)\n| extend EventID = id_s, Policy = policy_name_s, Severity = severity_s,Description = description_s,Recommendation = recommendation_s,URL = url_s,Tactics = tactics_s\n| where Policy has \"Privileged Machines Exposed to the Internet\"\n| project  EventID, Policy, Severity, Description, Recommendation, URL, Category, Tactics"
      },
      {
        "name": "421b38ec-4295-4aed-8299-c92e268ad663 — API - Kiterunner detection",
        "description": "42Crunch API protection against Kiterunner enumeration' (Source: Microsoft's official Azure-Sentinel Detections (MIT licensed).)",
        "query": "let discoveryRecords = FortyTwoCrunchAPIProtection\n| where TimeGenerated >= ago(5m) \n| project-away NonBlockingMode, SourcePort, DestinationPort, Query, ApiId, RequestHeader, ResponseHeader, Errors, EventType, Uuid \n| where Status == 404 and ErrorMessage startswith \"path not defined in OAS\";\nlet discoveryCnt = (toscalar(discoveryRecords | count));\nlet recCount = iff((discoveryCnt > 500), 1, 0);\ndiscoveryRecords | top recCount by Timestamp desc"
      }
    ],
    "spl": [],
    "esql": [
      {
        "name": "74f45152-9aee-11ef-b0a5-f661ea17fbcd — AWS Discovery API Calls via CLI from a Single Resource",
        "description": "(ESQL) Detects when a single AWS resource is running multiple read-only, discovery API calls in a 10-second window. This behavior could indicate an actor attempting to discover the AWS infrastructure using compromised credentials or a compromised instance... (Source: Elastic's official detection-rules repository (Elastic License v2).)",
        "query": "from logs-aws.cloudtrail-* metadata _id, _version, _index\n// create time window buckets of 10 seconds\n| eval Esql.time_window_date_trunc = date_trunc(10 seconds, @timestamp)\n\n| where\n    data_stream.dataset == \"aws.cloudtrail\"\n    \n    // exclude service account and console behavior\n    and source.ip IS NOT NULL\n    and aws.cloudtrail.session_credential_from_console IS NULL\n    and event.provider in (\n      \"iam.amazonaws.com\",\n      \"ec2.amazonaws.com\",\n      \"s3.amazonaws.com\",\n      \"rds.amazonaws.com\",\n      \"lambda.amazonaws.com\",\n      \"dynamodb.amazonaws.com\",\n      \"kms.amazonaws.com\",\n      \"cloudfront.amazonaws.com\",\n      \"elasticloadbalancing.amazonaws.com\", \n      \"cloudtrail.amazonaws.com\",\n      \"sts.amazonaws.com\",\n      \"ses.amazonaws.com\",\n      \"organizations.amazonaws.com\"\n    )\n    // ignore AWS service actions\n    and aws.cloudtrail.user_identity.type != \"AWSService\"\n    // filter for aws-cli specifically\n    and user_agent.name == \"aws-cli\"\n    // exclude DescribeCapacityReservations events related to AWS Config\n    and event.action != \"DescribeCapacityReservations\"\n    and user.name != \"AWSServiceRoleForConfig\"\n\n// filter for Describe, Get, List, and Generate API calls\n| where true in (\n    starts_with(event.action, \"Describe\"),\n    starts_with(event.action, \"Get\"),\n    starts_with(event.action, \"List\"),\n    starts_with(event.action, \"Generate\")\n)\n\n// keep relevant fields (preserving ECS fields and computed time window)\n| keep \n    @timestamp, \n    Esql.time_window_date_trunc, \n    event.action, \n    aws.cloudtrail.user_identity.arn, \n    aws.cloudtrail.user_identity.type, \n    aws.cloudtrail.user_identity.access_key_id, \n    source.ip, \n    cloud.account.id, \n    event.provider, \n    user_agent.name, \n    source.as.organization.name, \n    cloud.region,\n    data_stream.namespace\n\n// count the number of unique API calls per time window and actor\n| stats\n    Esql.event_action_count_distinct = count_distinct(event.action),\n    Esql.event_action_values = VALUES(event.action),\n    Esql.event_timestamp_values = VALUES(@timestamp),\n    Esql.aws_cloudtrail_user_identity_type_values = VALUES(aws.cloudtrail.user_identity.type),\n    Esql.aws_cloudtrail_user_identity_access_key_id_values = VALUES(aws.cloudtrail.user_identity.access_key_id),\n    Esql.source_ip_values = VALUES(source.ip),\n    Esql.cloud_account_id_values = VALUES(cloud.account.id),\n    Esql.event_provider_values = VALUES(event.provider),\n    Esql.user_agent_name_values = VALUES(user_agent.name),\n    Esql.source_as_organization_name_values = VALUES(source.as.organization.name),\n    Esql.cloud_region_values = VALUES(cloud.region),\n    Esql.data_stream_namespace_values = VALUES(data_stream.namespace)\n  by Esql.time_window_date_trunc, aws.cloudtrail.user_identity.arn\n\n// filter for more than 5 unique API calls per 10s window\n| where Esql.event_action_count_distinct > 5\n\n| keep\n    aws.cloudtrail.user_identity.arn,\n    Esql.time_window_date_trunc,\n    Esql.event_action_count_distinct,\n    Esql.event_action_values,\n    Esql.event_timestamp_values,\n    Esql.aws_cloudtrail_user_identity_type_values,\n    Esql.aws_cloudtrail_user_identity_access_key_id_values,\n    Esql.source_ip_values,\n    Esql.cloud_account_id_values,\n    Esql.event_provider_values,\n    Esql.user_agent_name_values,\n    Esql.source_as_organization_name_values,\n    Esql.cloud_region_values,\n    Esql.data_stream_namespace_values"
      },
      {
        "name": "a7577205-88a1-4a08-85d4-7b72a9a2e969 — AWS S3 Rapid Bucket Posture API Calls from a Single Principal",
        "description": "(ESQL) Identifies when the same AWS principal, from the same source IP, successfully invokes read-only S3 control-plane APIs that reveal bucket posture across many buckets in a short period. This pattern can indicate automated reconnaissance or security scanning, similar to CSPM tools and post-compromise enumeration... (Source: Elastic's official detection-rules repository (Elastic License v2).)",
        "query": "from logs-aws.cloudtrail-* metadata _id, _version, _index\n| eval Esql.time_window_date_trunc = date_trunc(10 seconds, @timestamp)\n\n| where\n    data_stream.dataset == \"aws.cloudtrail\"\n    and event.provider == \"s3.amazonaws.com\"\n    and event.outcome == \"success\"\n    and event.action in (\n      \"GetBucketAcl\",\n      \"GetBucketPublicAccessBlock\",\n      \"GetBucketPolicy\",\n      \"GetBucketPolicyStatus\",\n      \"GetBucketVersioning\"\n    )\n    and aws.cloudtrail.user_identity.type != \"AWSService\"\n    and source.ip IS NOT NULL\n    and aws.cloudtrail.resources.arn IS NOT NULL\n    and aws.cloudtrail.user_identity.arn IS NOT NULL\n    and aws.cloudtrail.session_credential_from_console IS NULL\n\n| keep\n    @timestamp,\n    Esql.time_window_date_trunc,\n    event.action,\n    aws.cloudtrail.user_identity.arn,\n    aws.cloudtrail.user_identity.type,\n    aws.cloudtrail.user_identity.access_key_id,\n    source.ip,\n    aws.cloudtrail.resources.arn,\n    cloud.account.id,\n    cloud.region,\n    user_agent.original,\n    source.as.organization.name,\n    data_stream.namespace\n\n| stats\n    Esql.aws_cloudtrail_resources_arn_count_distinct = count_distinct(aws.cloudtrail.resources.arn),\n    Esql.aws_cloudtrail_resources_arn_values = VALUES(aws.cloudtrail.resources.arn),\n    Esql.event_action_values = VALUES(event.action),\n    Esql.timestamp_values = VALUES(@timestamp),\n    Esql.aws_cloudtrail_user_identity_type_values = VALUES(aws.cloudtrail.user_identity.type),\n    Esql.aws_cloudtrail_user_identity_access_key_id_values = VALUES(aws.cloudtrail.user_identity.access_key_id),\n    Esql.cloud_account_id_values = VALUES(cloud.account.id),\n    Esql.cloud_region_values = VALUES(cloud.region),\n    Esql.user_agent_original_values = VALUES(user_agent.original),\n    Esql.source_as_organization_name_values = VALUES(source.as.organization.name),\n    Esql.data_stream_namespace_values = VALUES(data_stream.namespace)\n  by Esql.time_window_date_trunc, aws.cloudtrail.user_identity.arn, source.ip\n\n| where Esql.aws_cloudtrail_resources_arn_count_distinct > 15\n\n| keep\n    aws.cloudtrail.user_identity.arn,\n    source.ip,\n    Esql.time_window_date_trunc,\n    Esql.aws_cloudtrail_resources_arn_count_distinct,\n    Esql.aws_cloudtrail_resources_arn_values,\n    Esql.event_action_values,\n    Esql.timestamp_values,\n    Esql.aws_cloudtrail_user_identity_type_values,\n    Esql.aws_cloudtrail_user_identity_access_key_id_values,\n    Esql.cloud_account_id_values,\n    Esql.cloud_region_values,\n    Esql.user_agent_original_values,\n    Esql.source_as_organization_name_values,\n    Esql.data_stream_namespace_values"
      }
    ]
  },
  "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": [
    "Cloud Infrastructure 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": "T1580 - Cloud Infrastructure Discovery Response Guidance",
    "labels": [
      "mitre",
      "attack",
      "d3fend",
      "secops",
      "basyrix"
    ],
    "sections": [
      "summary",
      "d3fend_mappings",
      "investigation_steps",
      "response_actions",
      "queries",
      "automation",
      "escalation_criteria",
      "false_positive_considerations"
    ]
  }
}