black electronics

Cloud Storage

Cloud Storage Enumeration

Cloud Storage Enumeration

Cloud storage services like Amazon S3 and Google Cloud Storage are widely used to store application data, backups and other files, and are often unintentionally exposed to the public. This section covers tools and techniques for discovering cloud storage buckets and determining what information or access they actually expose.

Google Cloud Storage Buckets

Google Cloud Storage (GCS) is Google’s object storage service and is commonly used by web applications, mobile applications and cloud infrastructure to store files and application data.

Just like AWS S3, the existence of a Google Cloud Storage bucket isn’t itself interesting from a security perspective. Many buckets intentionally contain publicly accessible application resources.

What we want to determine is whether the bucket exposes more information or permissions than intended.

This may include anonymous access to sensitive objects, bucket listing, excessive IAM permissions or storage locations that were never intended to be publicly discoverable.

Finding Bucket Names

The first step is normally discovering potential bucket names.

Bucket names may be based on:

Company name
Domain name
Application name
Project name
Environment
Firebase project

Common examples might look like:

example
example-prod
example-production
example-backups
example.appspot.com
example-app.appspot.com

Bucket names can appear in JavaScript, configuration files, mobile applications and API responses.

GCPBucketBrute

GCPBucketBrute from Rhino Security Labs can be used to enumerate Google Storage bucket names and test the access available to discovered buckets.

https://github.com/RhinoSecurityLabs/GCPBucketBrute

Navigate to the tool:

Terminal window
cd ~/Hacking/Pentest_Tools/GCPBucketBrute

A keyword can then be supplied:

Terminal window
sudo python3 gcpbucketbrute.py -k company_name -u

The keyword should generally be based on something associated with the target organisation, such as the company name, application name or domain.

GCPBucketBrute is useful because discovering that a bucket exists is only the first part of the problem. We also want to understand what level of access is available to it.

Checking a Bucket Manually

Google’s Cloud Storage JSON API can also be queried directly.

The following endpoint lists objects within a bucket where the caller has the required permission:

https://www.googleapis.com/storage/v1/b/<BUCKET NAME>/o

This gives us a very quick way of checking a discovered bucket.

For example:

https://www.googleapis.com/storage/v1/b/example.appspot.com/o

The response itself can provide useful information.

In my testing I generally interpret the responses as:

404 Bucket does not exist
401/403
Bucket exists, but anonymous access to the requested
operation is not permitted
Object listing
Bucket exists and the current caller is able to list objects

The exact status code can vary depending on the request and Google’s access controls, so the important distinction is whether the bucket exists and whether the requested operation is permitted.

Google documents storage.objects.list as the permission required to list objects using this API.

Listing Bucket Contents

If object listing is permitted, the API response will contain information about the objects stored within the bucket.

This immediately gives us considerably more information to work with.

Interesting filenames may include:

backup
config
database
export
credentials
users
production
private
secret

We can then investigate individual objects to determine whether sensitive information has actually been exposed.

Remember that the ability to list objects and the ability to retrieve an object are separate permissions. A bucket may expose one without necessarily exposing the other. Google documents these as storage.objects.list and storage.objects.get respectively.

Using gsutil

Google’s gsutil utility can also be used to interact with Cloud Storage.

Documentation:

https://cloud.google.com/storage/docs/gsutil_install

To attempt to list the contents of a bucket:

Terminal window
gsutil ls gs://example.appspot.com

This normally uses the currently authenticated Google identity, but it is also useful when determining whether the bucket permits the requested access without appropriate authorisation.

If access is granted, recursively listing the contents can provide a better picture of what information is stored within the bucket.

Modern Google Cloud environments may also use the equivalent gcloud storage commands:

Terminal window
gcloud storage ls gs://example.appspot.com

Google currently documents gcloud storage ls as the command-line method for listing objects.

Retrieving the Bucket IAM Policy

If our current identity has sufficient permissions, the bucket’s IAM policy can be retrieved through the API:

https://www.googleapis.com/storage/v1/b/<BUCKET NAME>/iam

For example:

https://www.googleapis.com/storage/v1/b/example.appspot.com/iam

The policy can reveal which users, groups and service accounts have access to the bucket.

Pay particular attention to principals such as:

allUsers
allAuthenticatedUsers

allUsers represents anyone on the Internet, while allAuthenticatedUsers can provide access far beyond the organisation.

For example, granting allUsers the roles/storage.objectViewer role can make the bucket’s objects publicly readable and listable.

As with AWS, however, the complete configuration needs to be considered rather than treating a single IAM entry as the entire security picture.

Bucket ACLs

Older Google Cloud Storage configurations may also use ACLs.

Where the caller has sufficient permission, bucket ACL information can be retrieved through:

https://storage.googleapis.com/storage/v1/b/<BUCKET>/acl

Modern environments may use Uniform bucket-level access, in which case ACL operations are disabled and access is controlled through IAM instead.

This distinction is useful when testing because an ACL request failing does not necessarily mean that permissions cannot be assessed—it may simply mean that the bucket is using IAM exclusively.

Finding Buckets in Android Applications

Mobile applications are a particularly useful source of Google Cloud Storage bucket names.

Firebase and Google Cloud configuration values frequently survive application compilation and can therefore be identified after decompiling an APK.

One quick method is to recursively search the decompiled application for:

google_storage_bucket

Using PowerShell:

Terminal window
Get-ChildItem -Path .\app\ -Recurse |
Select-String -Pattern "google_storage_bucket"

We may find something similar to:

"google_storage_bucket": "example-mobile-app-production.appspot.com"

This gives us a bucket name that can immediately be tested using the same techniques discussed above.

For example:

https://www.googleapis.com/storage/v1/b/example-mobile-app-production.appspot.com/o

This is one reason mobile application testing and cloud enumeration often overlap. Information embedded in the client application can expose cloud resources that were not obvious from the organisation’s website.

Don’t Stop at Bucket Discovery

Finding the bucket is only the beginning.

Once a bucket has been identified, determine what the current user can actually do.

Questions worth asking include:

Can I determine that the bucket exists?
Can I list its objects?
Can I retrieve individual objects?
Can I upload objects?
Can I overwrite objects?
Can I delete objects?
Can I retrieve its IAM policy?
Can I read its ACLs?
Do I have access when unauthenticated?
Do I have additional access using my supplied account?

Different permissions have very different security implications.

A bucket containing intentionally public images is unlikely to be interesting.

A bucket containing private documents that can be downloaded anonymously is.

A bucket that allows an unauthenticated user to upload or overwrite application content could have significantly greater impact.

What Should We Look For?

Interesting Cloud Storage content may include:

Application configuration
Database backups
API keys
Service-account information
Credentials
Customer documents
Internal documents
Source code
Environment files
Logs
Exports
Mobile application data
Infrastructure configuration
Backups

Don’t report a bucket simply because it exists.

The important part is determining what information or capability is exposed and whether that exposure crosses the intended security boundary.

AWS S3 Buckets

Amazon Simple Storage Service (S3) is AWS’s object storage service. Applications use S3 buckets to store almost anything, including images, documents, backups, application data, log files and static website content.

From a penetration testing perspective, S3 becomes interesting when buckets or individual objects have been exposed unintentionally, permissions are too broad, or sensitive information has been uploaded to storage that was intended to be public.

A bucket being accessible from the Internet isn’t automatically a vulnerability. S3 is commonly used intentionally for public content. What we really want to establish is what an unauthenticated or low-privileged user can actually do with the bucket and what information is exposed.

Useful resources:

https://buckets.grayhatwarfare.com/
https://book.hacktricks.xyz/pentesting/pentesting-web/buckets/aws-s3#amazon-s3-buckets

Finding S3 Buckets

The first problem is normally identifying the bucket name.

Bucket names frequently contain information relating to the organisation, application or environment:

company
company-backups
company-prod
company-production
company-dev
company-assets
company-static
application-name
application-name-prod

References to S3 buckets can also appear throughout an application’s client-side resources and configuration.

When assessing a web application, search JavaScript, HTML, API responses, configuration files and other client-side resources for strings such as:

amazonaws.com
s3.amazonaws.com
s3-
.amazonaws.com

Mobile applications are another useful source because bucket names may be embedded in configuration files or application code.

We can also use search engines, certificate data, source-code repositories and other reconnaissance sources to identify references to an organisation’s storage infrastructure.

GrayHatWarfare

GrayHatWarfare maintains a searchable database of publicly exposed cloud storage buckets and files:

https://buckets.grayhatwarfare.com/

Searching for the organisation name, domain name, application names and other unique identifiers may identify buckets or files that would otherwise be difficult to discover.

This can be particularly useful during external reconnaissance where we do not initially know the organisation’s bucket naming convention.

Checking Whether a Bucket Exists

Once we have a possible bucket name, we can attempt to access it through S3.

For example:

https://BUCKET.s3.amazonaws.com/

Or:

https://s3.amazonaws.com/BUCKET/

The exact response can provide useful information about whether the bucket exists and whether anonymous access is permitted.

An access-denied response should not immediately be discarded. It may confirm that the bucket exists even though directory-style listing is not available.

We can then continue testing individual objects or assess the bucket using the AWS CLI.

Anonymous Bucket Listing

One of the first things worth checking is whether the bucket allows its contents to be listed without authentication.

Using the AWS CLI:

Terminal window
aws s3 ls s3://BUCKET --no-sign-request

--no-sign-request tells the AWS CLI not to use configured AWS credentials.

If the bucket permits anonymous listing, the returned object names can reveal considerably more information about the application or organisation.

For example:

backup/
database/
documents/
exports/
logs/
production/
users/

Even when the individual objects are not sensitive, filenames and directory structures can reveal internal application functionality and naming conventions.

Recursively Listing Objects

If anonymous listing is permitted, recursively enumerate the bucket:

Terminal window
aws s3 ls s3://BUCKET --recursive --no-sign-request

For a large bucket we may want to search the results rather than manually reviewing everything:

Terminal window
aws s3 ls s3://BUCKET --recursive --no-sign-request | grep -Ei 'backup|config|database|sql|password|secret|key|env|zip|tar|log'

Interesting extensions may include:

.env
.config
.json
.xml
.yml
.yaml
.sql
.db
.sqlite
.bak
.zip
.tar
.gz
.pem
.key
.pfx
.log

The objective isn’t simply to prove that listing is possible. We want to determine whether the exposed objects contain information that creates meaningful security impact.

Accessing Individual Objects

A bucket may prevent directory listing while still allowing individual objects to be downloaded.

This distinction is important.

Knowing:

https://BUCKET.s3.amazonaws.com/

does not necessarily tell us whether:

https://BUCKET.s3.amazonaws.com/backup.zip

is accessible.

If object names are discovered elsewhere in the application, test those objects directly.

Using the AWS CLI:

Terminal window
aws s3 cp s3://BUCKET/path/to/file.txt - --no-sign-request

Or with HTTP:

Terminal window
curl https://BUCKET.s3.amazonaws.com/path/to/file.txt

This means “I can’t list the bucket” does not necessarily mean “the bucket contains nothing publicly accessible.”

Downloading Public Bucket Content

If anonymous listing and object retrieval are both allowed, content can be copied for further analysis:

Terminal window
aws s3 cp s3://BUCKET ./bucket-data/ --recursive --no-sign-request

Only download information required for the assessment. Large storage buckets may contain significant amounts of data, so indiscriminately synchronising an entire bucket is usually unnecessary.

Authenticated Testing

During an AWS assessment we may have access to AWS credentials rather than testing anonymously.

First determine which identity we are currently using:

Terminal window
aws sts get-caller-identity

We can then test whether that identity can access the identified bucket:

Terminal window
aws s3 ls s3://BUCKET

Authenticated testing is particularly important because a bucket may correctly block anonymous users while granting excessive access to IAM users, roles or external AWS accounts.

The security question therefore becomes:

What can this particular AWS principal do with the bucket?

Bucket ACL

Where our current identity has permission, retrieve the bucket ACL:

Terminal window
aws s3api get-bucket-acl --bucket BUCKET

Review the returned grants and determine which principals have access.

Historically, S3 ACLs were a common source of unintended public access. Modern AWS environments increasingly rely on bucket policies and IAM instead, but ACLs are still worth reviewing where they are enabled.

Bucket Policy

Retrieve the bucket policy:

Terminal window
aws s3api get-bucket-policy --bucket BUCKET

Bucket policies can be particularly interesting because they may grant access to:

Everyone
Specific AWS accounts
IAM users
IAM roles
AWS services
External organisations

Pay particular attention to statements containing broad principals such as:

"Principal": "*"

However, the presence of "Principal": "*" does not automatically mean that the bucket is publicly exploitable. Conditions and S3 Block Public Access settings can significantly change the effective permissions.

The complete policy needs to be reviewed.

Is the Bucket Public?

AWS can report whether a bucket policy is considered public:

Terminal window
aws s3api get-bucket-policy-status --bucket BUCKET

We can also inspect the bucket’s public-access-block configuration:

Terminal window
aws s3api get-public-access-block --bucket BUCKET

S3 Block Public Access provides several protections designed to prevent public ACLs and bucket policies from exposing data.

AWS applies the most restrictive applicable configuration between bucket, account and organisation-level controls, so simply seeing a permissive bucket policy does not necessarily mean the policy is effective.

What Permissions Matter?

When assessing an S3 bucket, think in terms of actions rather than simply “public” or “private”.

We may want to determine whether our current identity can:

List objects
Read objects
Upload objects
Overwrite objects
Delete objects
Read the bucket policy
Read ACLs
Modify ACLs
Modify the bucket policy

These have very different security implications.

A publicly readable marketing image bucket may be completely intentional.

A publicly writable bucket is a very different situation.

Testing Upload Permissions

Where explicitly permitted by the engagement scope, test whether the current principal can upload an object using a harmless test file:

Terminal window
echo "pentest" > test.txt
aws s3 cp test.txt s3://BUCKET/test.txt

For anonymous testing:

Terminal window
aws s3 cp test.txt s3://BUCKET/test.txt --no-sign-request

If the upload succeeds, verify the object and remove it afterwards:

Terminal window
aws s3 rm s3://BUCKET/test.txt

Write access can have considerably greater impact than read access, particularly where the bucket hosts application resources or static website content.

Do not overwrite or modify existing objects merely to demonstrate write access.

What Should We Look For?

Interesting S3 exposures may include:

Database backups
Application backups
Environment files
Configuration files
Source code
API keys
Access keys
Private keys
Certificates
Customer documents
User uploads
Logs
Internal documentation
Infrastructure configuration
Terraform state
CI/CD artefacts

Files such as Terraform state can be particularly valuable because they may contain infrastructure information and sensitive values.

The impact of an exposed bucket should therefore be based on what is actually accessible, rather than simply reporting that an S3 bucket exists.

The interesting question is always:

What information or capability has been exposed to someone who shouldn’t have it?

Useful LinksPentest PayloadsCheat Sheets