├── LICENSE ├── README.md ├── config ├── __init__.py ├── banner.py ├── colors.py ├── config.py ├── footer.py └── functions.py ├── requirements.txt └── s3rec0n.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ebryx, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # S3Rec0n 2 | [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=102)](https://github.com/ellerbrock/open-source-badge/) 3 | [![python](https://img.shields.io/badge/python-2.7-blue.svg)](https://www.python.org/downloads/) 4 | [![GitHub version](https://d25lcipzij17d.cloudfront.net/badge.svg?id=gh&type=6.0.1&v=6.0.1&x2=0)](http://badge.fury.io/gh/boennemann%2Fbadges) 5 | [![Open Source Love](https://badges.frapsoft.com/os/mit/mit.svg?v=102)](https://github.com/ellerbrock/open-source-badge/) 6 | 7 | **A colorful cross-platform python utility to test misconfigurations of buckets both through authenticated and unauthenticated checks!** 8 | 9 | 10 | 11 | ### Requirements 12 | 13 | - Python `(3.7.*)` 14 | - Python `pip3` 15 | - Python module `boto3` 16 | - Python module `botocore` 17 | - Python module `jmespath` 18 | - Python module `pygments` 19 | - Python module `requests` 20 | 21 | ### Install python && modules 22 | 23 | sudo apt install python3 python3-pip python3-venv 24 | mkdir ~/.venvs/S3Rec0n/ && python3 -m venv ~/.venvs/S3Rec0n/ && source ~/.venvs/S3Rec0n/bin/activate 25 | pip install -r requirements.txt 26 | 27 | ### Tested on 28 | 29 | - Pop! OS 18.04 30 | - Kali linux (2019.1) 31 | - Ubuntu 18.04 LTS 32 | - Windows 8/8.1/10 33 | - Subsystem Linux 34 | 35 | ### Download/Clone S3Rec0n 36 | 37 | You can download the latest version of S3Rec0n by cloning the GitHub repository. As a best practice, please use python's virtual environment (venv) while running the script to avoid any modules/packages installation errors. 38 | 39 | git clone https://github.com/Ebryx/S3Rec0n 40 | 41 | ### Usage 42 | 43 | ***Initializing Script*** 44 | 45 | python s3rec0n.py 46 | 47 | ***Listing Bucket without S3 API Authorization (anonymously)*** 48 | 49 | python s3rec0n.py --unauthorized --list-bucket --bucket=myTestBucket 50 | 51 | ***Listing Bucket with S3 API Authorization (using access keys)*** 52 | 53 | python s3rec0n.py --authorized --list-bucket --bucket=myTestBucket 54 | 55 | ***Listing Bucket without specifying any flag both auth/unauth S3 API Call (by default it gets set to unauthorized)*** 56 | 57 | python s3rec0n.py --list-bucket --bucket=myTestBucket 58 | 59 | ***Fetching ACL of the Bucket without S3 API Authorization (anonymously)*** 60 | 61 | python s3rec0n.py --unauthorized --get-acl --bucket=myTestBucket 62 | 63 | ***Putting/Over-writing the ACL of the Bucket without S3 API Authorization (anonymously)*** 64 | 65 | python s3rec0n.py --unauthorized --put-acl --bucket=myTestBucket 66 | 67 | ***Fetching readable objects of the Bucket without S3 API Authorization (anonymously)*** 68 | 69 | python s3rec0n.py --unauthorized --readable-objs --bucket=myTestBucket 70 | 71 | ***Trying and uploading a test object on the Bucket without S3 API Authorization (anonymously)*** 72 | 73 | python s3rec0n.py --unauthorized --upload-objs --bucket=myTestBucket 74 | 75 | ***Fetching ACLs of all the objects of the Bucket without S3 API Authorization (anonymously)*** 76 | 77 | python s3rec0n.py --unauthorized --fetch-obj-acl --bucket=myTestBucket 78 | 79 | ### Description of Checks 80 |

 81 | Usage: python s3rec0n.py
 82 | Features/Functions:
 83 | 
 84 |  1). Authenticated Checks (through access keys)
 85 |  2). Unauthenticated Checks (anonymously)
 86 |  3). Buckets Location (AWS Region)
 87 |  4). Static Website Hosting Check
 88 |  5). Bucket Listing
 89 |  6). Fetching ACL (Access Control List) of the Bucket
 90 |  7). Over-writing ACL of the bucket (be careful!)
 91 |  8). Finding readable objects in the bucket
 92 |  9). Uploading test key/object for misconfiguration test
 93 |  10). Fetch ACLs of all the Objects
 94 |   
 95 |   Example:
 96 | 	python s3rec0n.py
 97 | 
98 | 99 | ### Some GIFS 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | ### Note 108 |
 Feel free to make pull requests!
109 | P.S ~ Dont Change The Colors. They're Butiphul like this.
110 | 	~ An0n 3xPloiTeR
111 | 
112 | -------------------------------------------------------------------------------- /config/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | ___________________________ __ ________ 3 | / _____/\_____ \______ \__ __ _______/ |\_____ \______ 4 | \_____ \ _(__ <| | _/ | \/ ___/\ __\_(__ <_ __ \ 5 | / \ / \ | \ | /\___ \ | | / \ | \/ 6 | /_______ //______ /______ /____//____ > |__|/______ /__| 7 | \/ \/ \/ \/ \/ 8 | """ 9 | 10 | from config.functions import * 11 | from config.colors import * 12 | from config.config import * 13 | from config.banner import * 14 | from config.footer import * 15 | -------------------------------------------------------------------------------- /config/banner.py: -------------------------------------------------------------------------------- 1 | import config 2 | 3 | banner = f"""{config.colors.c} ________ _______ _______ ____ ____ ________ ___________ _______ _______ 4 | /" )/" __ )| _ "\\ (" _||_ " | /" )(" _ ")/" __ ) /" \\ 5 | {config.colors.g}(: \\___/(__/ _) ./(. |_) :)| ( ) : |(: \\___/ )__/ \\\\__/(__/ _) ./|: | 6 | \\___ \\ / // |: \\/ (: | | . ) \\___ \\ \\\\_ / / // |_____/ ) 7 | {config.colors.r} __/ \\\\ __ \\_ \\\\ (| _ \\\\ \\\\ \\__/ // __/ \\\\ |. | __ \\_ \\\\ // / 8 | /" \\ :)(: \\__) :\\|: |_) :) /\\\\ __ //\\ /" \\ :) \\: | (: \\__) :\\|: __ \\ {config.colors.w}~> By: {config.colors.g}Syed Umar Arfeen 9 | {config.colors.y}(_______/ \\_______)(_______/ (__________)(_______/ \\__| \\_______)|__| \\___) {config.colors.w}~> Version: {config.colors.g}{config.config.version} 10 | """ 11 | -------------------------------------------------------------------------------- /config/colors.py: -------------------------------------------------------------------------------- 1 | from colorama import init,Fore,Back,Style 2 | import os 3 | 4 | if os.name == "posix": 5 | init(autoreset=True) 6 | # colors foreground text: 7 | fc = "\033[0;96m" 8 | fg = "\033[0;92m" 9 | fw = "\033[0;97m" 10 | fr = "\033[0;91m" 11 | fb = "\033[0;94m" 12 | fy = "\033[0;33m" 13 | fm = "\033[0;35m" 14 | 15 | # colors background text: 16 | bc = "\033[46m" 17 | bg = "\033[42m" 18 | bw = "\033[47m" 19 | br = "\033[41m" 20 | bb = "\033[44m" 21 | by = "\033[43m" 22 | bm = "\033[45m" 23 | 24 | # colors style text: 25 | sd = Style.DIM 26 | sn = Style.NORMAL 27 | sb = Style.BRIGHT 28 | 29 | c = fc 30 | g = fg 31 | w = fw 32 | r = fr 33 | b = fb 34 | y = fy 35 | m = fm 36 | 37 | else: 38 | init(autoreset=True) 39 | # colors foreground text: 40 | fc = Fore.CYAN 41 | fg = Fore.GREEN 42 | fw = Fore.WHITE 43 | fr = Fore.RED 44 | fb = Fore.BLUE 45 | fy = Fore.YELLOW 46 | fm = Fore.MAGENTA 47 | 48 | # colors background text: 49 | bc = Back.CYAN 50 | bg = Back.GREEN 51 | bw = Back.WHITE 52 | br = Back.RED 53 | bb = Back.BLUE 54 | by = Fore.YELLOW 55 | bm = Fore.MAGENTA 56 | 57 | # colors style text: 58 | sd = Style.DIM 59 | sn = Style.NORMAL 60 | sb = Style.BRIGHT 61 | 62 | c = fc + sb 63 | g = fg + sb 64 | w = fw + sb 65 | r = fr + sb 66 | b = fb + sb 67 | y = fy + sb 68 | m = fm + sb 69 | -------------------------------------------------------------------------------- /config/config.py: -------------------------------------------------------------------------------- 1 | from config import * 2 | from sys import argv 3 | 4 | """ 5 | ------------------------------------------------------------------ 6 | Argparse Variables 7 | ------------------------------------------------------------------ 8 | """ 9 | 10 | version = "1.0" 11 | 12 | _usage = f"\r{w}[{c}#{w}] Usage: python {g}{argv[0]}{w} --bucket myTestBucket --all" 13 | _version = "{}[{}~{}] {}Version: {}{}".format(w,c,w,w,g,version) 14 | -------------------------------------------------------------------------------- /config/footer.py: -------------------------------------------------------------------------------- 1 | from config import * 2 | 3 | footer = """ 4 | {white}[{green}${white}] {cyan}Thanks For Using {white}:D 5 | \t{blue}~ {red}An0n 3xPloiTeR {white}:)""".format( 6 | white = w, 7 | green = g, 8 | cyan = c, 9 | blue = b, 10 | red = r 11 | ) 12 | -------------------------------------------------------------------------------- /config/functions.py: -------------------------------------------------------------------------------- 1 | from config.colors import * 2 | 3 | def bucketExists(bucketName): 4 | bucket = f"http://{bucketName}.s3.amazonaws.com" 5 | request = requests.get(bucket) 6 | 7 | if request.status_code == 200: 8 | return(True) # Bucket Exists and is:listable 9 | 10 | elif request.status_code == 403: 11 | return(True) # Bucket Exists and Access's Denied. 12 | 13 | else: 14 | return(False) # Get it ;) 15 | 16 | def deleteFile(bucketName, fileName): 17 | """ 18 | if `file` exists: then delete 19 | """ 20 | path = os.getcwd() 21 | reports_dir = os.path.join(path, 'reports') 22 | bucket_pth = os.path.join(reports_dir, bucketName) 23 | file = os.path.join(bucket_pth, fileName) 24 | 25 | if os.path.isfile(file): 26 | os.remove(file) 27 | 28 | def write(var, color, data): 29 | if var == None: 30 | print(color + str(data)) 31 | elif var != None: 32 | print(w + "[" + g + var + w + "] " + color + str(data)) 33 | 34 | def _heading(heading, c, var): 35 | name = var 36 | # name = u'\u2500' 37 | space = " " * 7 38 | var = str(space + heading + " ..." + space) 39 | length = len(var) + 1; print() # \n 40 | print("{white}" + name * length + name).format(white=w) 41 | print("{color}" + var).format(color=c) 42 | print("{white}" + name * length + name).format(white=w); print() # \n 43 | 44 | def report(bucketName, fileName, stdout, opt="w"): 45 | """ 46 | Useful in dumping output of stdout into /reports/bucketName/specified-file.ext 47 | Will be integrated soon! 48 | """ 49 | path = os.getcwd() 50 | reports_dir = os.path.join(path, 'reports') 51 | bucket_pth = os.path.join(reports_dir, bucketName) 52 | file = os.path.join(bucket_pth, fileName) 53 | 54 | if not(os.path.isdir(reports_dir)): 55 | os.mkdir(reports_dir) 56 | if not(os.path.isdir(bucket_pth)): 57 | os.mkdir(bucket_pth) 58 | 59 | elif os.path.isdir(reports_dir): 60 | if not(os.path.isdir(bucket_pth)): 61 | os.mkdir(bucket_pth) 62 | 63 | with open(file, opt) as f: 64 | f.write(stdout) 65 | 66 | def heading(heading, bucket, color, afterWebHead): 67 | space = " " * 15 68 | var = str(space + heading + " '" + bucket + "'" + str(afterWebHead) + " ..." + space) 69 | length = len(var) + 1 70 | 71 | print() 72 | print(w + "-" * length + "-") 73 | print(color + var) 74 | print(w + "-" * length + "-") 75 | print() 76 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | boto3 2 | botocore 3 | colorama 4 | jmespath 5 | Pygments 6 | requests 7 | -------------------------------------------------------------------------------- /s3rec0n.py: -------------------------------------------------------------------------------- 1 | from jmespath import search as queryJson 2 | from re import findall as parseRegex 3 | from pygments import highlight, lexers, formatters 4 | from requests import get 5 | from json import loads, dumps 6 | from time import sleep 7 | from io import StringIO 8 | from config import * 9 | from config.config import _usage 10 | import botocore 11 | import boto3 12 | import argparse 13 | 14 | class S3: 15 | def __init__(self, bucket): 16 | self.bucket = bucket 17 | 18 | def parseJson(self, query, jsonObj): 19 | return(queryJson(query, jsonObj)) 20 | 21 | def prettifyJSON(self, jsonObject): 22 | return(highlight(jsonObject, lexers.JsonLexer(), formatters.TerminalFormatter())) 23 | 24 | def authorizedClientCall(self): 25 | """ 26 | Makes Authorized Client call to S3 (picks up access keys from ~/.aws/) 27 | """ 28 | client = boto3.client("s3") 29 | return(client) 30 | 31 | def unAuthorizedClientCall(self): 32 | """ 33 | Makes Unauthorized Client call to S3 (i.e. without access keys) 34 | """ 35 | client = boto3.client("s3", config=botocore.config.Config(signature_version=botocore.UNSIGNED)) 36 | return(client) 37 | 38 | def getBucketLocation(self, bucketName): 39 | """ 40 | Returns bucket['LocationConstraint'] 41 | Doesn't work with unsigned requests 42 | So, had to come up with a solution of mine B) 43 | """ 44 | _bucket = f"http://{bucketName}.s3.eu-west-1.amazonaws.com" 45 | request = get(_bucket) 46 | sourceCode = request.content.decode('UTF-8') 47 | regex = r'\(.*?)\<\/Endpoint\>' 48 | location = parseRegex(regex, sourceCode) 49 | result = "" 50 | 51 | if "s3.amazonaws.com" in str(location): 52 | result = f"http://{bucketName}.{location[0]}" 53 | 54 | elif len(location) == 0: 55 | result = _bucket 56 | 57 | else: 58 | result = f"http://{location[0]}" 59 | 60 | write(var="$", color=w, data=result) 61 | return(result) 62 | 63 | def fetchBucketACL(self, clientCall, bucketName): 64 | """ 65 | As the name of the function depicts: It fetches / downloads `ACLs` of the bucket... 66 | """ 67 | 68 | try: 69 | response = clientCall.get_bucket_acl(Bucket=bucketName) 70 | print(self.prettifyJSON(dumps( self.parseJson("Grants", response), indent=4 ))) 71 | 72 | except botocore.exceptions.ClientError as e: 73 | if "AccessDenied" and "GetBucketAcl" in e.args[0]: 74 | write(var=f"{r}!", color=w, data=f"It seems we can't fetch the {r}ACL{w} of this bucket :(") 75 | 76 | def overWriteBucketACL(self, clientCall, bucketName): 77 | """ 78 | Overwrites the current ACL of the bucket even if we aren't able to fetch the ACL of the bucket 79 | Sounds crazy! huh!? 80 | """ 81 | bucketACL = { 82 | 'Owner': { 83 | 'ID': '694f79fd87bab72d3576779c0a2308cc3b2006dfe0e76105562755d701e8c2e1' 84 | }, 85 | 'Grants': [ 86 | { 87 | 'Grantee': { 88 | 'Type': 'Group', 89 | 'URI': 'http://acs.amazonaws.com/groups/global/AllUsers' 90 | }, 91 | 'Permission': 'FULL_CONTROL' 92 | }, 93 | ], 94 | } 95 | 96 | try: 97 | ACL = loads(dumps((lambda c, b: c.get_bucket_acl(Bucket=b))(clientCall, bucketName)))['Grants'][0]['Permission'] 98 | 99 | if ACL == 'FULL_CONTROL': 100 | write(var=f"{c}#", color=w, data=f"It seems we already have {g}FULL_CONTROL{w} over the bucket! :P\n") 101 | return 102 | 103 | except botocore.exceptions.ClientError as e: 104 | if "AccessDenied" and "GetBucketAcl" in e.args[0]: pass 105 | 106 | try: 107 | putACL = (lambda a, b, c: a.put_bucket_acl(Bucket=b, AccessControlPolicy=c))(clientCall, bucketName, bucketACL) 108 | write(var=f"{c}#", color=w, data=f"It seems we were able to {g}overwrite{w} the ACL of the bucket, lets confirm {y}:)\n") 109 | 110 | try: 111 | bucketACL = loads(dumps((lambda c, b: c.get_bucket_acl(Bucket=b))(clientCall, bucketName)))['Grants'][0] 112 | print(self.prettifyJSON(dumps(bucketACL, indent=4))) 113 | permissions = bucketACL['Permission'] 114 | URI = bucketACL['Grantee']['URI'] 115 | 116 | if (URI == "http://acs.amazonaws.com/groups/global/AllUsers" and permissions == "FULL_CONTROL"): 117 | write(var=f"{c}$", color=w, data=f"{r}Hell yeah{w}, {g}we did it{w}!") 118 | 119 | else: 120 | write(var=f"{r}!", color=w, data=f"It seems we {r}weren't successful{w} in over-writing the {c}ACL{w} of the bucket! {r}:(") 121 | 122 | except botocore.exceptions.ClientError as e: 123 | if "AccessDenied" and "GetBucketAcl" in e.args[0]: write(var=f"{r}!", color=w, data=f"It seems we {r}weren't successful{w} in over-writing the {c}ACL{w} of the bucket! {r}:(") 124 | 125 | except botocore.exceptions.ClientError as e: 126 | if "AccessDenied" and "PutBucketAcl" in e.args[0]: write(var=f"{r}!", color=w, data=f"It seems we can't {r}overwrite{w} the {r}ACL{w} of this bucket :(") 127 | 128 | def listBucket(self, clientCall): 129 | """ 130 | Lists the objects in the buckets both through authorized and `--no-sign-request` 131 | Returns False if unauthorized listing of objects is set to false 132 | """ 133 | try: 134 | response = clientCall.list_objects(Bucket=self.bucket) 135 | response = self.parseJson("Contents[].Key", response) 136 | 137 | for objects in response: 138 | write(var=f"{g}#", color=w, data=f"{objects}") 139 | sleep(0.01) 140 | 141 | return(response) 142 | 143 | except botocore.exceptions.ClientError as e: 144 | if "AccessDenied" and "ListObjects" in e.args[0]: 145 | return(None) 146 | 147 | def readableObjects(self, clientCall, bucket, objectsList): 148 | """ 149 | Checks in the objects list provided, if the objects are readable 150 | TL;DR if readable: return contentOfObject else: None 151 | """ 152 | readableObjs = [] 153 | for objects in objectsList: 154 | 155 | try: 156 | response = clientCall.get_object( Bucket=bucket, Key=objects ) 157 | response = response['ResponseMetadata']['HTTPStatusCode'] 158 | write(var=f"{c}#", color=w, data="{:<65} -~> {}{}".format(objects, g, response)) 159 | readableObjs.append(objects) 160 | sleep(0.01) 161 | 162 | except botocore.exceptions.ClientError as e: 163 | if "AccessDenied" and "GetObject" in e.args[0]: 164 | write(var=f"{r}!", color=w, data="{:<65} -~> {}{}".format(objects, r, 403)) 165 | 166 | return(readableObjs) 167 | 168 | def uploadObjectOnBucket(self, clientCall, bucketName): 169 | dataToWrite = b"Pentesting in Progress" 170 | keyName = 'pentest0bject.txt' 171 | 172 | try: 173 | response = clientCall.put_object(Body=dataToWrite, Bucket=bucketName, Key=keyName, ACL="public-read-write") 174 | write(var=f"{c}@", color=w, data=f"Awesome! We just {g}uploaded{w} our object at {g}{bucketName}/{keyName}") 175 | 176 | except botocore.exceptions.ClientError as e: 177 | if "AccessDenied" and "PutObject" in e.args[0]: 178 | write(var=f"{r}!", color=w, data=f"It seems we {r}failed{w} to upload {r}0bject{w} on the {c}bucket{w} {r}:(") 179 | 180 | def fetchObjectsACL(self, clientCall, bucketName, objectsList): 181 | for objects in objectsList: 182 | try: 183 | 184 | if objects[::-1][0] != "/": 185 | response = clientCall.get_object_acl(Bucket=bucketName, Key=objects) 186 | response = loads(dumps(response))['Grants'] 187 | write(var=f"{g}$", color=w, data=f"ACL of \"{g}{objects}{w}\"") 188 | print( self.prettifyJSON(dumps(response, indent=4)) ) 189 | sleep(0.01) 190 | 191 | except botocore.exceptions.ClientError as e: 192 | if "AccessDenied" and "GetObjectAcl" in e.args[0]: 193 | write(var=f"{r}!", color=w, data=f"ACL of {r}\"{objects}\"{w} isn't accessible!") 194 | 195 | def checkBucketStaticHosting(self, clientCall, bucketName): 196 | try: 197 | response = clientCall.get_bucket_website(Bucket=bucketName) 198 | print(response) 199 | 200 | except botocore.exceptions.ClientError as e: 201 | if "AccessDenied" and "GetBucketWebsite" in e.args[0]: 202 | write(var=f"{r}!", color=w, data=f"The bucket doesn't have {r}static hosting{w} enabled!") 203 | 204 | def main(): 205 | print(banner) 206 | parser = argparse.ArgumentParser(description='', usage=f'{_usage}{b}') 207 | parser._optionals.title = "Basic Help" 208 | 209 | basicFuncs = parser.add_argument_group(f'{g}Actions') 210 | basicFuncs.add_argument('--bucket', action="store", dest="bucket", default=False, help='Bucket to test the script against!') 211 | basicFuncs.add_argument("-au", "--authorized", action="store_true", dest="authorized", default=False, help="Perform the checks using Access Keys") 212 | basicFuncs.add_argument("-ua", "--unauthorized", action="store_true", dest="unauthorized", default=False, help="Perform the checks anonymously!") 213 | basicFuncs.add_argument('-a', '--all', action="store_true", dest="all", default=False, help='To run all the functions against the bucket!') 214 | 215 | functions = parser.add_argument_group(f'{y}Functions') 216 | functions.add_argument("-l", "--location", action="store_true", default=False, dest="location", help="Find the Bucket's Location") 217 | functions.add_argument("-s", "--static-hosting", action="store_true", default=False, dest="staticHosting", help="Finds if the bucket has Static Hosting enabled") 218 | functions.add_argument("-ba", "--get-acl", action="store_true", default=False, dest="getBucketACL", help="Fetches the ACL of the Bucket") 219 | functions.add_argument("-pa", "--put-acl", action="store_true", default=False, dest="putBucketACL", help="Puts the ACL with FULL_CONTROL on the bucket") 220 | functions.add_argument("-lb", "--list-bucket", action="store_true", default=False, dest="listBucket", help="List the S3 Bucket Objects/Keys") 221 | functions.add_argument("-r", "--readable-objs", action="store_true", default=False, dest="read0bjs", help="Finds the readable 0bjects/Keys") 222 | functions.add_argument("-up", "--upload-objs", action="store_true", default=False, dest="upload0bjs", help="Uploads a test 0bject on the S3 Bucket") 223 | functions.add_argument("-oa", "--fetch-obj-acl", action="store_true", default=False, dest="read0bjsACL", help="Finds the ACL of Individual 0bjects/Keys") 224 | 225 | args = parser.parse_args() 226 | if args.bucket: 227 | bucket = args.bucket 228 | S30bj = S3(bucket) 229 | 230 | ############################################################################# 231 | 232 | if args.unauthorized: 233 | clientCall = S30bj.unAuthorizedClientCall() 234 | 235 | elif args.authorized: 236 | clientCall = S30bj.authorizedClientCall() 237 | 238 | else: 239 | write(var=f"{r}!", color=w, data=f"No flags were specified for API Calls, moving with unauthorized API Calls") 240 | clientCall = S30bj.unAuthorizedClientCall() 241 | 242 | ############################################################################# 243 | 244 | if args.location: 245 | heading(heading="Finding Location/Region of", bucket=bucket, color=c, afterWebHead="") 246 | S30bj.getBucketLocation(bucket) 247 | 248 | elif args.staticHosting: 249 | heading(heading="Finding Static Web Hosting 0n", bucket=bucket, color=y, afterWebHead="") 250 | S30bj.checkBucketStaticHosting(clientCall, bucket) 251 | 252 | elif args.getBucketACL: 253 | heading(heading="Fetching the ACL of", bucket=bucket, color=g, afterWebHead="") 254 | S30bj.fetchBucketACL(clientCall, bucket) 255 | 256 | elif args.putBucketACL: 257 | heading(heading="Trying to 0verwrite the ACL 0f", bucket=bucket, color=b, afterWebHead="") 258 | S30bj.overWriteBucketACL(clientCall, bucket) 259 | 260 | elif args.listBucket: 261 | heading(heading="Listing Objects of", bucket=bucket, color=y, afterWebHead="") 262 | S30bj.listBucket(clientCall) 263 | 264 | elif args.read0bjs: 265 | heading(heading="Listing Objects of", bucket=bucket, color=r, afterWebHead="") 266 | S30bjs = S30bj.listBucket(clientCall) 267 | 268 | if not(S30bjs == None): 269 | heading(heading="Reading/Fetching 0bjects 0f", bucket=bucket, color=m, afterWebHead="") 270 | S30bj.readableObjects(clientCall, bucket, S30bjs) 271 | 272 | elif S30bjs == None: 273 | write(var=f"{r}!", color=w, data=f"It seems we {r}don't{w} have {r}listing / read objects{w} permissions on the bucket {r}:(") 274 | 275 | else: 276 | write(var=f"{r}!", color=w, data=f"No {r}keys/objects{w} found in the S3 bucket: {r}{bucket}") 277 | 278 | elif args.upload0bjs: 279 | heading(heading="Trying to Upload 0bject on", bucket=bucket, color=g, afterWebHead="") 280 | S30bj.uploadObjectOnBucket(clientCall, bucket) 281 | 282 | elif args.read0bjsACL: 283 | heading(heading="Listing Objects of", bucket=bucket, color=r, afterWebHead="") 284 | S30bjs = S30bj.listBucket(clientCall) 285 | 286 | if not(S30bjs == None): 287 | heading(heading="Fetching ACLs 0f", bucket=bucket, color=g, afterWebHead=" 0bjects") 288 | S30bj.fetchObjectsACL(clientCall, bucket, S30bjs) 289 | 290 | elif S30bjs == None: 291 | write(var=f"{r}!", color=w, data=f"It seems we {r}don't{w} have {r}listing / read objects{w} permissions on the bucket {r}:(") 292 | 293 | else: 294 | write(var=f"{r}!", color=w, data=f"No {r}keys/objects{w} found in the S3 bucket: {r}{bucket}") 295 | 296 | elif args.all: 297 | heading(heading="Finding Location/Region of", bucket=bucket, color=c, afterWebHead="") 298 | S30bj.getBucketLocation(bucket) 299 | sleep(0.1) 300 | 301 | heading(heading="Finding Static Web Hosting 0n", bucket=bucket, color=y, afterWebHead="") 302 | S30bj.checkBucketStaticHosting(clientCall, bucket) 303 | sleep(0.1) 304 | 305 | heading(heading="Fetching the ACL of", bucket=bucket, color=g, afterWebHead="") 306 | S30bj.fetchBucketACL(clientCall, bucket) 307 | sleep(0.1) 308 | 309 | heading(heading="Trying to 0verwrite the ACL 0f", bucket=bucket, color=b, afterWebHead="") 310 | S30bj.overWriteBucketACL(clientCall, bucket) 311 | sleep(0.1) 312 | 313 | heading(heading="Listing Objects of", bucket=bucket, color=y, afterWebHead="") 314 | S30bjs = S30bj.listBucket(clientCall) 315 | sleep(0.1) 316 | 317 | if not(S30bjs == None): 318 | heading(heading="Reading/Fetching 0bjects 0f", bucket=bucket, color=m, afterWebHead="") 319 | S30bj.readableObjects(clientCall, bucket, S30bjs) 320 | sleep(0.1) 321 | 322 | heading(heading="Fetching ACLs 0f", bucket=bucket, color=g, afterWebHead=" 0bjects") 323 | S30bj.fetchObjectsACL(clientCall, bucket, S30bjs) 324 | sleep(0.1) 325 | 326 | elif S30bjs == None: 327 | write(var=f"{r}!", color=w, data=f"It seems we {r}don't{w} have {r}listing / read objects{w} permissions on the bucket {r}:(") 328 | 329 | else: 330 | write(var=f"{r}!", color=w, data=f"No {r}keys/objects{w} found in the S3 bucket: {r}{bucket}") 331 | 332 | else: 333 | write(var=f"{r}!", color=w, data=f"Please specify an argument to execute! :(") 334 | 335 | ############################################################################# 336 | 337 | else: 338 | parser.print_help() 339 | exit(footer) 340 | 341 | print(footer) 342 | 343 | if __name__ == '__main__': 344 | main() 345 | --------------------------------------------------------------------------------