S3 Bucket Enumeration and Exploitation: ACLs, Policies, Pre-Signed URL Abuse
Cloud Security
S3 misconfigurations beyond public buckets, covering ACL takeover, policy condition bypass, and pre-signed URL abuse for persistence.
By Arjun Raghavan, Security & Systems Lead, BIPI · December 8, 2024 · 10 min read
S3 has been the poster child for cloud data leaks for a decade. Block Public Access closed the obvious door, but the interesting attack surface today is ACL drift, policy condition logic, and pre-signed URL abuse. This post is the offensive checklist we run against S3 during a cloud engagement.
Bucket discovery without an account
- Permutation enumeration with bucket_finder, S3Scanner, or cloud_enum on company keywords
- Certificate transparency logs for s3-website endpoints and CloudFront origins
- GitHub code search for s3.amazonaws.com paths in client repositories
- DNS brute force on common subdomains, looking for CNAMEs to s3 endpoints
ACL takeover and the AuthenticatedUsers trap
The legacy ACL group AuthenticatedUsers grants access to any authenticated AWS principal, in any account. Buckets created before Block Public Access defaults still carry this ACL. Run aws s3api get-bucket-acl with your own keys; if you see AuthenticatedUsers with WRITE_ACP, you can rewrite the ACL and effectively own the bucket.
Bucket policy condition bypasses
- aws:SourceIp conditions bypassed by routing through an EC2 with a matching Elastic IP
- aws:Referer header conditions bypassed by setting the header in a custom client
- aws:SecureTransport false on legacy buckets, allowing plain HTTP exfil
- Mismatched Deny and Allow with NotPrincipal logic that inverts the intended policy
Pre-signed URL persistence
On engagements we generate a batch of pre-signed URLs with a seven-day TTL, then drop the keys. The defender rotates credentials and feels safe, while the URLs continue to work until either the signing role is revoked or the bucket policy explicitly denies. CloudTrail does not log pre-signed URL usage as the original principal, only as the bucket-level access event.
Exfiltration tradecraft
- Use s3 sync with a low max-concurrent-requests to stay under EDR network heuristics
- Pull through CloudFront when available to break source-IP attribution
- Prefer Range requests for partial object exfil that does not trip full-object access alerts
Block Public Access fixed the unauthenticated bucket. It did not fix the bucket that any AWS user on the planet can write to.
Remediation
- Enforce S3 Block Public Access at the account level, not just the bucket
- Audit ACLs for AuthenticatedUsers and AllUsers across every bucket monthly
- Set Object Ownership to Bucket owner enforced, which disables ACLs entirely
- Tighten signing roles so pre-signed URLs are scoped to specific prefixes
- Enable S3 access logs and CloudTrail data events, then alert on cross-account access patterns
Detection hooks worth wiring up
S3 data events are noisy but cheap with the right filter. Alert on PutBucketAcl, PutBucketPolicy, and any GetObject from a principal outside your org. Pair with Macie if you care about data classification, and accept that pre-signed URL abuse will need network-layer correlation, not just CloudTrail.
Read more field notes, explore our services, or get in touch at info@bipi.in. Privacy Policy · Terms.