← Back to Explore
elasticlowTTP
AWS S3 Bucket Enumeration or Brute Force
Identifies a high number of failed S3 operations against a single bucket from a single source address within a short timeframe. This activity can indicate attempts to collect bucket objects or cause an increase in billing to an account via internal "AccessDenied" errors.
Detection Query
data_stream.dataset: "aws.cloudtrail" and
event.provider : "s3.amazonaws.com" and
aws.cloudtrail.error_code : "AccessDenied" and
tls.client.server_name : *
Author
Elastic
Created
2024/05/01
Data Sources
AWSAmazon Web ServicesAWS S3logs-aws.cloudtrail-*
References
Tags
Domain: CloudData Source: AWSData Source: Amazon Web ServicesData Source: AWS S3Resources: Investigation GuideUse Case: Log AuditingTactic: ImpactTactic: DiscoveryTactic: Collection
Raw Content
[metadata]
creation_date = "2024/05/01"
integration = ["aws"]
maturity = "production"
updated_date = "2026/04/10"
[rule]
author = ["Elastic"]
description = """
Identifies a high number of failed S3 operations against a single bucket from a single source address within a short timeframe.
This activity can indicate attempts to collect bucket objects or cause an increase in billing to an account via internal "AccessDenied" errors.
"""
false_positives = [
"""
External account IDs or broken automation may trigger this rule. For AccessDenied (HTTP 403 Forbidden), S3 doesn't charge the bucket owner when the request is initiated outside of the bucket owner's individual AWS account or the bucket owner's AWS organization.
"""]
from = "now-6m"
index = ["logs-aws.cloudtrail-*"]
language = "kuery"
license = "Elastic License v2"
name = "AWS S3 Bucket Enumeration or Brute Force"
note = """
## Triage and analysis
### Investigating AWS S3 Bucket Enumeration or Brute Force
This rule detects when many failed S3 operations (HTTP 403 AccessDenied) hit a single bucket from a single source address in a short window. This can indicate bucket name enumeration, object/key guessing, or brute-force style traffic intended to drive cost or probe for misconfigurations. 403 requests from outside the bucket owner’s account/organization are not billed, but 4XX from inside the owner’s account/org can still incur charges. Prioritize confirming who is making the calls and where they originate.
#### Possible investigation steps
- **Investigate in Timeline.** Investigate the alert in timeline (Take action -> Investigate in timeline) to retrieve and review all of the raw CloudTrail events that contributed to the threshold alert. Threshold alerts only display the grouped fields; Timeline provides a way to see individual event details such as request parameters, full error messages, and additional user context.
- **Confirm entity & target.** Note the rule’s threshold and window. Identify the target bucket (`tls.client.server_name`) and the source (`source.address`). Verify the caller identity details via any available `aws.cloudtrail.user_identity` fields.
- **Actor & session context.** In CloudTrail events, pivot 15–30 minutes around the spike for the same `source.address` or principal. Determine if the source is:
- **External** to your account/organization (recon/cost DDoS risk is lower for you due to 2024 billing change).
- **Internal** (same account/org)—higher cost risk and possible misuse of internal automation.
- **Bucket posture snapshot.** Record S3 Block Public Access, Bucket Policy, ACLs, and whether Versioning/Object Lock are enabled. Capture any recent `PutBucketPolicy`, `PutPublicAccessBlock`, `PutBucketVersioning`, or lifecycle changes.
- **Blast radius.** Check for similar spikes to other buckets/regions, or parallel spikes from the same source. Review any GuardDuty S3 findings and AWS Config drift related to the bucket or principal.
- **Business context.** Contact the bucket/app owner. Validate whether a migration, scanner, or broken job could legitimately cause bursts.
### False positive analysis
- **Expected jobs / broken automation.** Data movers, posture scanners, or failed credentials can generate 403 storms. Validate with `userAgent`, ARNs, change windows, and environment (dev/stage vs prod).
- **External probing.** Internet-origin enumeration often looks like uniform 403s from transient or cloud-provider IPs and typically has no business impact and no billing if outside your account/org. Tune thresholds or allowlist known scanners if appropriate.
### Response and remediation
**Immediate, low-risk actions**
- **Preserve evidence.** Export CloudTrail records (±30 minutes) for the bucket and source address into an evidence bucket with restricted access.
- **Notify owners.** Inform the bucket/application owner and security lead; confirm any maintenance windows.
**Containment options**
- **External-origin spikes:** Verify Block Public Access is enforced and bucket policies are locked down. Optionally apply a temporary deny-all bucket policy allowing only IR/admin roles while scoping.
- **Internal-origin spikes:** Identify the principal. Rotate access keys for IAM users, or restrict involved roles (temporary deny/SCP, remove risky policies). Pause broken jobs/pipelines until validated.
**Scope & hunting**
- Review Timeline and CloudTrail for related events: `PutBucketPolicy`, `PutPublicAccessBlock`, `PutBucketVersioning`, lifecycle changes, unusual `PutObject`/`DeleteObject` volumes, or cross-account access.
- Check GuardDuty S3 and Config drift findings for signs of tampering or lateral movement.
**Recovery & hardening**
- If data impact suspected: with Versioning, restore known-good versions; otherwise, recover from backups/replicas.
- Enable Versioning on critical buckets going forward; evaluate Object Lock legal hold if enabled.
- Ensure Block Public Access, least-privilege IAM policies, CloudTrail data events for S3, and GuardDuty protections are consistently enforced.
### Additional information
- [AWS S3 billing for error responses](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ErrorCodeBilling.html): see latest AWS docs on which error codes are billed.
- [AWS announcement (Aug 2024)](https://aws.amazon.com/about-aws/whats-new/2024/05/amazon-s3-no-charge-http-error-codes/): 403s from outside the account/org are not billed.
- [AWS IR Playbooks](https://github.com/aws-samples/aws-incident-response-playbooks/): NIST-aligned template for evidence, containment, eradication, recovery, post-incident.
- [AWS Customer Playbook Framework](https://github.com/aws-samples/aws-customer-playbook-framework/): Practical response steps for account and bucket-level abuse.
"""
references = [
"https://medium.com/@maciej.pocwierz/how-an-empty-s3-bucket-can-make-your-aws-bill-explode-934a383cb8b1",
"https://docs.aws.amazon.com/AmazonS3/latest/userguide/ErrorCodeBilling.html",
]
risk_score = 21
rule_id = "5f0234fd-7f21-42af-8391-511d5fd11d5c"
severity = "low"
tags = [
"Domain: Cloud",
"Data Source: AWS",
"Data Source: Amazon Web Services",
"Data Source: AWS S3",
"Resources: Investigation Guide",
"Use Case: Log Auditing",
"Tactic: Impact",
"Tactic: Discovery",
"Tactic: Collection",
]
timestamp_override = "event.ingested"
type = "threshold"
query = '''
data_stream.dataset: "aws.cloudtrail" and
event.provider : "s3.amazonaws.com" and
aws.cloudtrail.error_code : "AccessDenied" and
tls.client.server_name : *
'''
[rule.investigation_fields]
field_names = [
"@timestamp",
"source.address",
"aws.cloudtrail.user_identity.type",
"tls.client.server_name"
]
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1657"
name = "Financial Theft"
reference = "https://attack.mitre.org/techniques/T1657/"
[rule.threat.tactic]
id = "TA0040"
name = "Impact"
reference = "https://attack.mitre.org/tactics/TA0040/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1580"
name = "Cloud Infrastructure Discovery"
reference = "https://attack.mitre.org/techniques/T1580/"
[[rule.threat.technique]]
id = "T1619"
name = "Cloud Storage Object Discovery"
reference = "https://attack.mitre.org/techniques/T1619/"
[rule.threat.tactic]
id = "TA0007"
name = "Discovery"
reference = "https://attack.mitre.org/tactics/TA0007/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1530"
name = "Data from Cloud Storage"
reference = "https://attack.mitre.org/techniques/T1530/"
[rule.threat.tactic]
id = "TA0009"
name = "Collection"
reference = "https://attack.mitre.org/tactics/TA0009/"
[rule.threshold]
field = ["tls.client.server_name", "source.address", "aws.cloudtrail.user_identity.type"]
value = 1
[[rule.threshold.cardinality]]
field = "event.id"
value = 40