[New Rule][Rule Tuning] AWS Organizations/Account Discovery Coverage (#5910)
* [New Rule][Rule Tuning] AWS Organizations/Account Discovery Coverage In response to the supply chain attack highlighted in (Kudelski’s Trivy / TeamPCP analysis)[https://kudelskisecurity.com/research/investigating-two-variants-of-the-trivy-supply-chain-compromise], I've added coverage for AWS Organization and Account reconnaissance which was called out in the research. ### AWS Discovery API Calls via CLI from a Single Resource - Expanded our existing Multi-service discovery rule to include `event.provider: oraganizations.amazonaws.com` - added the new `aws.cloudtrail.session_credential_from_console` field to exclude console behavior from this rule, and added appropriate `min_stack` to account for introduction of the field. GAP: This rule detects aws-cli usage only. In the mentioned reference, attackers used Botocore and Boto3 tooling for this recon activity. SOLUTION: ### AWS Account Discovery By Rare User - Created a new Discovery rule focused solely on Organization/Account reconnaissance. - Made it a new terms rule to reduce false positive noise from common behavior that might be seen using Boto3 or Botocore tooling. - excluded console session behavior and service account behavior Testing: - Ran PACU's organization__enum module - created a script that can be run to validate the query - plenty of test data in our stack to run the query against * Update rules/integrations/aws/discovery_organization_discovery_by_rare_user.toml Co-authored-by: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com> --------- Co-authored-by: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com>
This commit is contained in:
@@ -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",
|
||||
]
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user