S3 Misconfiguration
S3 buckets are still one of the most reliable ways to get a medium-high on a cloud program. Public listing is usually P3/medium, but write access or exposed PII bumps it to P2/high easily. Bucket policy misconfigs are the sneaky ones - the bucket isn't "public" in the classic sense but the policy grants s3:GetObject to * on specific prefixes.
Finding Buckets
Start with permutations of the company name, product names, and known subdomains:
# s3scanner - fast bulk checking
s3scanner scan --buckets-file wordlist.txt
# Manual permutations to try
company-name
company-name-assets
company-name-backup
company-name-dev
company-name-staging
company-name-prod
company-name-logs
company-name-data
assets.company.com (CNAME -> S3 sometimes)Also check:
- JS files for bucket names (hardcoded S3 URLs)
- Network traffic in Burp while using the app (S3 presigned URLs reveal bucket names)
- GitHub/GitLab for config files, terraform, CloudFormation templates
Testing Access
# Check if listing is enabled (unauthenticated)
aws s3 ls s3://BUCKET_NAME --no-sign-request
# List all objects if listing is on
aws s3 ls s3://BUCKET_NAME --recursive --no-sign-request
# Check read access on a specific object
aws s3 cp s3://BUCKET_NAME/somefile.txt /tmp/test --no-sign-request
# Check write access - always use a clearly-named bounty file
echo "bugbounty-test-$(date +%s)" > /tmp/bb_test.txt
aws s3 cp /tmp/bb_test.txt s3://BUCKET_NAME/bugbounty-test.txt --no-sign-request
# Clean up immediately after confirming
aws s3 rm s3://BUCKET_NAME/bugbounty-test.txt --no-sign-request
# Check ACL on bucket
aws s3api get-bucket-acl --bucket BUCKET_NAME --no-sign-requestPolicy Abuse
Even when a bucket isn't fully public, the bucket policy might grant access under certain conditions. Check the policy if you have any authenticated access:
aws s3api get-bucket-policy --bucket BUCKET_NAMEWatch for:
"Principal": "*"with any action - fully public"Principal": {"AWS": "arn:aws:iam::*:root"}- any AWS account- Conditions keyed on
aws:Refereroraws:SourceIp- bypass with the right header/IP - Overly broad resource ARNs:
arn:aws:s3:::bucket/*grants access to everything
Presigned URL Abuse
Presigned URLs are time-limited but can expose more than intended:
- Long expiry times (days or weeks) - report as misconfig
- Predictable key names - if you can guess the key, you can generate valid paths
- Presigned URLs for write (PUT) operations shared with users who shouldn't have write
- URL in logs or referrer headers that gets captured by third parties
Bucket Takeover
If a subdomain CNAMEs to an S3 bucket that no longer exists, you can register that bucket name and serve content from their subdomain. Classic subdomain takeover via S3.
# Check if a CNAME points to S3
dig CNAME assets.company.com
# If it resolves to something.s3.amazonaws.com and returns 404/NoSuchBucket, it's takeableImpact Tiers
| Finding | Typical Severity |
|---|---|
| Public listing only (no sensitive content) | P4/Low |
| Public listing with PII/sensitive data | P2/High |
| Unauthenticated write access | P2/High |
| Bucket takeover via CNAME | P2/High |
| Sensitive backup/config files publicly readable | P1/Critical depending on content |
Related
- IAM Privilege Escalation - if you find creds in an exposed bucket
- AWS Overview