S3 Security
The bucket someone made public in 2019 is still leaking today.
What you will learn
- -Tell bucket policies, ACLs, and Block Public Access apart
- -Test a bucket for public read, list, and write access
- -Find a target's buckets by guessing and by permutation
More real data has walked out of AWS through open than through any clever . Capital One, Verizon, Accenture, the Pentagon's intelligence contractor: all S3, all misconfiguration, none of them a software bug. A bucket is just a for objects, but it has four separate systems that can each make it public, and people fight all four at once.
The four are ACLs, bucket policies, policies, and Block Public Access. ACLs are the old way, an object-level grant list that AWS now discourages but that still exists everywhere. Bucket policies are attached to the bucket, same shape as IAM policies. IAM policies grant access from the side. Block Public Access is the master that, when on, overrides the other three and refuses to serve anything public. Most modern leaks happen when someone turns that switch off "just to test" and forgets.
Test what a bucket actually allows
Public read of an object and public listing of the bucket are different permissions. A bucket can let you download a file whose exact key you know while refusing to list its contents, or it can hand you the whole index. Check both, plus write, which is the worst of all.
$aws s3 ls s3://target-bucket --no-sign-request$aws s3 cp s3://target-bucket/backup.sql . --no-sign-request$echo test > t.txt && aws s3 cp t.txt s3://target-bucket/ --no-sign-request--no-sign-request is the flag that matters here. It tells the CLI to send the request with no at all, so a success proves the bucket answers to anonymous callers, not just to you. Public write is a full compromise of whatever consumes that bucket: overwrite a file a website loads and you have on their site, or plant a malicious deployment artifact.
You can also just hit the in a browser. https://target-bucket.s3.amazonaws.com/ returns an XML listing if the bucket is publicly listable, and an AccessDenied XML body if it is not. That AccessDenied still confirms the bucket exists, which is useful.
Finding the buckets in the first place
Bucket names are global and -visible, which makes them guessable. Real names around the company: acme-backups, acme-prod-assets, acme-dev, acme-terraform-state. Permutation tools automate the guessing against wordlists.
$python3 s3scanner.py scan --bucket-list names.txtThe other tool worth knowing is awscli against a name list in a loop, but purpose-built scanners like S3Scanner and the classic bucket_finder.rb handle the existence-versus-access distinction for you and are faster. Grayhat Warfare indexes already-public buckets and their file listings, so search there before you scan anything, because the target's bucket may already be catalogued.
Reading a bucket you were not authorized to test is data theft, even if AWS served it to you without a login. "It was public" has not held up as a defense. Scan and pull only from buckets inside your engagement or your own account. Grayhat Warfare browsing is passive, but downloading a specific company's data is not.
For defenders, the fix is boring and total: turn on Block Public Access at the account level, which forces it on for every bucket regardless of what individual policies say. Then use S3 Access Analyzer to flag any bucket that grants access outside your account. Do not bucket-by-bucket ACLs by hand. Let the account-level switch make public exposure impossible by default and treat any exception as an .
You run aws s3 ls s3://acme-assets --no-sign-request and get a full file listing including database-dump-2024.sql. Before you download anything, write down: is this in scope, what does the file name suggest, and what is the single fastest remediation you would report? The point is to separate confirming exposure from exfiltrating data.