diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2c7e77b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.7-alpine3.8 + +WORKDIR /app +COPY requirements.txt /app/ + +RUN pip install -r requirements.txt + +COPY . /app + +ENTRYPOINT ["python", "gcpbucketbrute.py"] \ No newline at end of file diff --git a/README.md b/README.md index 0cebccd..b9a9e09 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,20 @@ A script to enumerate Google Storage buckets, determine what access you have to 2. `cd GCPBucketBrute/` 3. `pip3 install -r requirements.txt` or `python3 -m pip install -r requirements.txt` +### Using Docker + +1. Build the [Docker](https://docs.docker.com/) image: + +```bash +sudo docker build -t gcpbucketbrute https://github.com/RhinoSecurityLabs/GCPBucketBrute.git +``` + +2. Run the Docker image (mount volume from host to provide files inside the image): + +```bash +sudo docker run -v /tmp:/data gcpbucketbrute -k evilcorp -f /data/gcp-service-creds.json -w /data/words.txt +``` + ## Usage First, determine the type of authentication you want to use for enumeration between a user account, service account, or unauthenticated. If you are using a service account, provide the file path to the private key via the `-f`/`--service-account-credential-file-path` argument. If you are using a user account, don't provide an authentication argument. You will then be prompted to enter the access token of your user account for accessing the GCP APIs. If you want to scan completely unauthenticated, pass the `-u`/`--unauthenticated` argument to hide authentication prompts. diff --git a/gcpbucketbrute.py b/gcpbucketbrute.py index 2318fcd..a8a3ba6 100644 --- a/gcpbucketbrute.py +++ b/gcpbucketbrute.py @@ -23,7 +23,7 @@ def outprint(data='', file_path='', normal_print=''): normal_print(data) -def generate_bucket_permutations(keyword): +def generate_bucket_permutations(keyword, wordlist): permutation_templates = [ '{keyword}-{permutation}', '{permutation}-{keyword}', @@ -32,7 +32,7 @@ def generate_bucket_permutations(keyword): '{keyword}{permutation}', '{permutation}{keyword}' ] - with open('./permutations.txt', 'r') as f: + with open(wordlist, 'r') as f: permutations = f.readlines() buckets = [] for perm in permutations: @@ -83,7 +83,7 @@ def main(args): subprocesses = [] if args.keyword: - buckets = generate_bucket_permutations(args.keyword) + buckets = generate_bucket_permutations(args.keyword, args.wordlist) elif args.check_single: buckets = [args.check_single] @@ -203,7 +203,7 @@ def check_permissions(self, bucket_name): if __name__ == '__main__': - parser = argparse.ArgumentParser(description='This script will generate a list of permutations from ./permutations.txt using the keyword passed into the -k/--keyword argument. Then it will attempt to enumerate Google Storage buckets with those names without any authentication. If a bucket is found to be listable, it will be reported (buckets that allow access to "allUsers"). If a bucket is found but it is not listable, it will use the default "gcloud" CLI credentials to try and list the bucket. If the bucket is listable with credentials it will be reported (buckets that allow access to "allAuthenticatedUsers"), otherwise it will reported as existing, but unlistable.') + parser = argparse.ArgumentParser(description='This script will generate a list of permutations from wordlist specified by -w/--wordlist (default ./permutations.txt) using the keyword passed into the -k/--keyword argument. Then it will attempt to enumerate Google Storage buckets with those names without any authentication. If a bucket is found to be listable, it will be reported (buckets that allow access to "allUsers"). If a bucket is found but it is not listable, it will use the default "gcloud" CLI credentials to try and list the bucket. If the bucket is listable with credentials it will be reported (buckets that allow access to "allAuthenticatedUsers"), otherwise it will reported as existing, but unlistable.') # Add mutually exclusive arguments: keyword or a single bucket group = parser.add_mutually_exclusive_group(required=True) group.add_argument('--check-single', required=False, help='Check a single bucket name instead of bruteforcing names based on a keyword.') @@ -212,7 +212,8 @@ def check_permissions(self, bucket_name): parser.add_argument('-f', '--service-account-credential-file-path', required=False, default=None, help='The path to the JSON file that contains the private key for a GCP service account. By default, you will be prompted for a user access token, then if you decline to enter one it will prompt you to default to the default system credentials. More information here: https://google-auth.readthedocs.io/en/latest/user-guide.html#service-account-private-key-files and here: https://google-auth.readthedocs.io/en/latest/user-guide.html#user-credentials') parser.add_argument('-u', '--unauthenticated', required=False, default=False, action='store_true', help='Force an unauthenticated scan (you will not be prompted for credentials)') parser.add_argument('-o', '--out-file', required=False, default=None, help='The path to a log file to write the scan results to. The file will be created if it does not exist and will append to it if it already exists. By default output will only print to the screen.') - + parser.add_argument('-w', '--wordlist', required=False, default='./permutations.txt', help='Wordlist for generation of bucket-name permutations.') + args = parser.parse_args() main(args)