diff --git a/rules/integrations/aws/discovery_multiple_discovery_api_calls_via_cli.toml b/rules/integrations/aws/discovery_multiple_discovery_api_calls_via_cli.toml index e89c2921f..f2639c69a 100644 --- a/rules/integrations/aws/discovery_multiple_discovery_api_calls_via_cli.toml +++ b/rules/integrations/aws/discovery_multiple_discovery_api_calls_via_cli.toml @@ -2,7 +2,9 @@ creation_date = "2024/11/04" integration = ["aws"] maturity = "production" -updated_date = "2026/03/24" +min_stack_comments = "aws.cloudtrail.session_credential_from_console field introduced in AWS integration version 4.6.0" +min_stack_version = "9.2.0" +updated_date = "2026/04/01" [rule] author = ["Elastic"] @@ -14,8 +16,9 @@ gain a better understanding of the target's infrastructure. """ false_positives = [ """ - Administrators or automated systems may legitimately perform multiple `Describe`, `List`, `Get` and `Generate` API calls in a short - time frame. Verify the user identity and the purpose of the API calls to determine if the behavior is expected. + Administrators or automated systems may legitimately perform multiple `Describe`, `List`, `Get` and `Generate` API + calls in a short time frame. Verify the user identity and the purpose of the API calls to determine if the behavior + is expected. """, ] from = "now-6m" @@ -29,7 +32,7 @@ note = """## Triage and analysis This rule detects when a single AWS identity executes more than five unique discovery-related API calls (`Describe*`, `List*`, `Get*`, or `Generate*`) within a 10-second window using the AWS CLI. High volumes of diverse “read-only” API calls in such a short period can indicate scripted reconnaissance, often an early phase of compromise after credential exposure or access to a compromised EC2 instance. -#### Possible Investigation Steps +### Possible investigation steps **Identify the actor and session context** - **Actor ARN (`aws.cloudtrail.user_identity.arn`)**: Determine which IAM user, role, or service principal performed the actions. @@ -103,7 +106,10 @@ If the activity is unexpected or originates from unrecognized credentials, follo - [AWS Customer Playbook Framework](https://github.com/aws-samples/aws-customer-playbook-framework) """ -references = ["https://stratus-red-team.cloud/attack-techniques/AWS/aws.discovery.ec2-enumerate-from-instance/"] +references = [ + "https://stratus-red-team.cloud/attack-techniques/AWS/aws.discovery.ec2-enumerate-from-instance/", + "https://kudelskisecurity.com/research/investigating-two-variants-of-the-trivy-supply-chain-compromise", +] risk_score = 21 rule_id = "74f45152-9aee-11ef-b0a5-f661ea17fbcd" severity = "low" @@ -122,6 +128,7 @@ tags = [ "Data Source: AWS Cloudfront", "Data Source: AWS DynamoDB", "Data Source: AWS Elastic Load Balancing", + "Data Source: AWS Organizations", "Use Case: Threat Detection", "Tactic: Discovery", "Resources: Investigation Guide", @@ -136,7 +143,10 @@ from logs-aws.cloudtrail-* metadata _id, _version, _index | where event.dataset == "aws.cloudtrail" - // filter on CloudTrail audit logs for IAM, EC2, S3, etc. + + // exclude service account and console behavior + and source.ip IS NOT NULL + and aws.cloudtrail.session_credential_from_console IS NULL and event.provider in ( "iam.amazonaws.com", "ec2.amazonaws.com", @@ -149,7 +159,8 @@ from logs-aws.cloudtrail-* metadata _id, _version, _index "elasticloadbalancing.amazonaws.com", "cloudtrail.amazonaws.com", "sts.amazonaws.com", - "ses.amazonaws.com" + "ses.amazonaws.com", + "organizations.amazonaws.com" ) // ignore AWS service actions and aws.cloudtrail.user_identity.type != "AWSService" @@ -157,6 +168,7 @@ from logs-aws.cloudtrail-* metadata _id, _version, _index and user_agent.name == "aws-cli" // exclude DescribeCapacityReservations events related to AWS Config and event.action != "DescribeCapacityReservations" + and user.name != "AWSServiceRoleForConfig" // filter for Describe, Get, List, and Generate API calls | where true in ( @@ -166,11 +178,6 @@ from logs-aws.cloudtrail-* metadata _id, _version, _index starts_with(event.action, "Generate") ) -// extract owner, identity type, and actor from the ARN -| dissect aws.cloudtrail.user_identity.arn "%{}::%{Esql_priv.aws_cloudtrail_user_identity_arn_owner}:%{Esql.aws_cloudtrail_user_identity_arn_type}/%{Esql.aws_cloudtrail_user_identity_arn_roles}" - -| where starts_with(Esql.aws_cloudtrail_user_identity_arn_roles, "AWSServiceRoleForConfig") != true - // keep relevant fields (preserving ECS fields and computed time window) | keep @timestamp, @@ -210,6 +217,15 @@ from logs-aws.cloudtrail-* metadata _id, _version, _index [[rule.threat]] framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1087" +name = "Account Discovery" +reference = "https://attack.mitre.org/techniques/T1087/" +[[rule.threat.technique.subtechnique]] +id = "T1087.004" +name = "Cloud Account" +reference = "https://attack.mitre.org/techniques/T1087/004/" + [[rule.threat.technique]] id = "T1526" @@ -221,23 +237,25 @@ id = "T1580" name = "Cloud Infrastructure Discovery" reference = "https://attack.mitre.org/techniques/T1580/" + [rule.threat.tactic] id = "TA0007" name = "Discovery" reference = "https://attack.mitre.org/tactics/TA0007/" + [rule.investigation_fields] field_names = [ - "Esql.event_action_count_distinct", - "Esql.time_window_date_trunc", - "aws.cloudtrail.user_identity.arn", - "Esql.aws_cloudtrail_user_identity_type_values", - "Esql.aws_cloudtrail_user_identity_access_key_id_values", - "Esql.source_ip_values", - "Esql.source_as_organization_name_values", - "Esql.event_provider_values", - "Esql.event_action_values", - "Esql.cloud_account_id_values", - "Esql.cloud_region_values", - "Esql.data_stream_namespace_values" - ] + "Esql.event_action_count_distinct", + "Esql.time_window_date_trunc", + "aws.cloudtrail.user_identity.arn", + "Esql.aws_cloudtrail_user_identity_type_values", + "Esql.aws_cloudtrail_user_identity_access_key_id_values", + "Esql.source_ip_values", + "Esql.source_as_organization_name_values", + "Esql.event_provider_values", + "Esql.event_action_values", + "Esql.cloud_account_id_values", + "Esql.cloud_region_values", + "Esql.data_stream_namespace_values", +] diff --git a/rules/integrations/aws/discovery_organization_discovery_by_rare_user.toml b/rules/integrations/aws/discovery_organization_discovery_by_rare_user.toml new file mode 100644 index 000000000..920192a3a --- /dev/null +++ b/rules/integrations/aws/discovery_organization_discovery_by_rare_user.toml @@ -0,0 +1,157 @@ +[metadata] +creation_date = "2026/04/01" +integration = ["aws"] +maturity = "production" +updated_date = "2026/04/01" +min_stack_version = "9.2.0" +min_stack_comments = "aws.cloudtrail.session_credential_from_console field introduced in AWS integration version 4.6.0" + +[rule] +author = ["Elastic"] +description = """ +Identifies the first time, within a lookback window, an identity performs AWS Organizations or IAM account enumeration +APIs. Attackers with compromised credentials often map the organization (accounts, OUs, roots, delegated admins) and +account-level metadata (aliases, summary) using the AWS CLI or SDKs. This is a New Terms rule detecting a rare +occurrence of the `cloud.account.id` and `user.name` pair for these actions. +""" +false_positives = [ + """ + Organization and security administrators, billing tooling, landing-zone automation, and delegated administrator + workflows may call these APIs legitimately. Interactive or one-off use from unusual principals warrants review. + """, +] +from = "now-6m" +index = ["logs-aws.cloudtrail-*"] +language = "kuery" +license = "Elastic License v2" +name = "AWS Account Discovery By Rare User" +note = """## Triage and analysis + +### Investigating AWS Account Discovery By Rare User + +AWS Organizations and IAM expose read APIs that reveal organization structure, member accounts, delegation, and +account-level aliases. Threat actors and tools such as Pacu (`organizations__enum`) chain these calls to understand +multi-account layout after credential access. + +This rule uses [New Terms](https://www.elastic.co/guide/en/security/current/rules-ui-create.html#create-new-terms-rule) to detect when an identity makes a discovery API call that has not been seen in the configured history window. + +### Possible investigation steps + +**Identify the actor and session context** +- Confirm who `user.name` and `aws.cloudtrail.user_identity.arn` represent (human, workload role, automation). + +**Analyze the source and origin** +- Review source.ip, geolocation, and whether the call aligns with normal egress for that principal. +- Inspect user_agent.original for CLI, Boto3/Botocore, consoles, or unfamiliar tooling. + +**Correlate with additional events** +- Correlate with STS*(`GetCallerIdentity`, `AssumeRole`) and broader discovery or privilege changes in the same session. +- If the principal is new or rarely used, review IAM policies and recent key rotation. + +### False positive analysis + +- Documented org-admin or security roles in the management account; add exceptions by ARN if needed. +- Centralized compliance or CSPM that enumerates org structure on a schedule. + +### Response and remediation + +- If unexpected, rotate credentials for the implicated principal, review CloudTrail for follow-on API activity, and + tighten least privilege on Organizations/IAM read APIs where appropriate. + +### Additional information + +- **[AWS IR Playbooks](https://github.com/aws-samples/aws-incident-response-playbooks)** +""" +references = [ + "https://kudelskisecurity.com/research/investigating-two-variants-of-the-trivy-supply-chain-compromise", + "https://github.com/RhinoSecurityLabs/pacu/blob/master/pacu/modules/organizations__enum/main.py", +] +risk_score = 21 +rule_id = "444c8fad-874f-4f59-b0ea-cf26cea478bd" +severity = "low" +tags = [ + "Domain: Cloud", + "Domain: Identity", + "Data Source: AWS", + "Data Source: Amazon Web Services", + "Data Source: AWS CloudTrail", + "Data Source: AWS Organizations", + "Data Source: AWS IAM", + "Use Case: Threat Detection", + "Tactic: Discovery", + "Resources: Investigation Guide", +] +timestamp_override = "event.ingested" +type = "new_terms" + +query = ''' +event.dataset: "aws.cloudtrail" + and event.outcome: "success" + and source.ip:* + and not aws.cloudtrail.session_credential_from_console: "true" + and not aws.cloudtrail.user_identity.type: "AWSService" + and ( + ( + event.provider: "organizations.amazonaws.com" + and event.action: ( + "DescribeOrganization" or "DescribeOrgnanizationalUnit" or "ListAccounts" or "ListRoots" + or "ListOrganizationalUnitsForParent" or "ListAccountsForParent" or "ListPolicies" + or "ListAWSServiceAccessForOrganization" or "ListDelegatedAdministrators" + or "ListDelegatedServicesForAccount" or "DescribeResourcePolicy" + ) + ) + or ( + event.provider: "iam.amazonaws.com" + and event.action: ("ListAccountAliases" or "GetAccountSummary") + ) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1087" +name = "Account Discovery" +reference = "https://attack.mitre.org/techniques/T1087/" +[[rule.threat.technique.subtechnique]] +id = "T1087.004" +name = "Cloud Account" +reference = "https://attack.mitre.org/techniques/T1087/004/" + + +[[rule.threat.technique]] +id = "T1580" +name = "Cloud Infrastructure Discovery" +reference = "https://attack.mitre.org/techniques/T1580/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + +[rule.investigation_fields] +field_names = [ + "@timestamp", + "user.name", + "user_agent.original", + "source.ip", + "aws.cloudtrail.user_identity.arn", + "aws.cloudtrail.user_identity.type", + "aws.cloudtrail.user_identity.access_key_id", + "event.action", + "event.outcome", + "event.provider", + "cloud.account.id", + "cloud.region", +] + +[rule.new_terms] +field = "new_terms_fields" +value = ["cloud.account.id", "user.name"] +[[rule.new_terms.history_window_start]] +field = "history_window_start" +value = "now-10d" + +