Recently I needed to confirm if an s3 bucket was indeed publicly writable (by trying to write to it from a different account). I decided to document how to confirm this for your organization.
Prerequisites
- AWS CLI installed
- Two AWS accounts
- Account A – Has a bucket you suspect may be publicly writable
- Account B – You will test if you can write to a bucket hosted in Account A using credentials from a user in account B
Account A
For this example we will say our bucket is at:
s3://foo
The following is what to look for from the account hosting the suspect bucket
Access Control List
Public Access Group “Everyone” – List Objects “Yes”
Bucket Policy
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:Put*",
"s3:Get*",
"s3:List*"
],
"Resource": "arn:aws:s3:::REDACTED/*"
}
]
}
CORS configuration
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Account B
Set up the aws cli for a user in Account B. This account and user should have nothing to do with account A.
Create a test file
echo "this is a test file to see if we can write to this s3 bucket" > testwrite.txt
Attempt to write to the bucket
aws s3 cp testwrite.txt s3://foo
Successful Write
The response looks like this:
upload: ./testwrite.txt to s3://foo/testwrite.txt
Failed Write
If you do not have permission to write to the bucket the response will look like this:
upload failed: ./testwrite.txt to s3://foo/testwrite.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
If you didn’t set up the aws cli with an API key and password than you will see this message
upload failed: ./testwrite.txt to s3://foo/testwrite.txt Unable to locate credentials