├── README.md ├── assume-role-check.py ├── check-identity.py ├── check-s3-access.py └── input.txt /README.md: -------------------------------------------------------------------------------- 1 | # Helpful aws boto3 scripts 2 | python3 scripts to help with aws triage needs 3 | 4 | Two of the scripts (check-identity.py and check-s3-access.py) currently run with threading set to 50, but you can adjust that as needed within the script. This allows the script to finish recursive s3 bucket list access checks on large s3 listings in short order. 5 | 6 | 3 scripts currently included: 7 | 1. check-identity.py: This is a threaded python3 script that can take one or many aws key pairs and very quickly check if those keys are active and quickly performs the following checks: 8 | - checks s3 bucket access 9 | - attempts to list role info 10 | - attempts to list group info 11 | - checks for servicesspecificcredentials 12 | - checks secretsmanager info 13 | - checks parameterstore info 14 | - checks for dynamodb list_tables access 15 | 16 | 2. check-s3-access.py: This is a threaded python3 script that can take sets of keys and quickly check to identify which buckets that key can actually view into (i.e., a key pair may be able to list a bucket name but may not be able to view inside of that bucket, so this script helps with identifying which buckets a set of keys can actually see into) 17 | 18 | 3. assume-role-check.py: This script is intended to be run after discovering that a set of aws credentials have iam list-roles privileges. Steps: 1. run aws iam list-roles > output.txt, 2. run aws sts get-caller-identity on the creds and copy the ARN value, 3. python3 assume-role-check.py -a [ARN_value] -f [iam-list-roles-output-file]. The script will then check which roles are potential candidates for sts assume-role operations. IF NO OUTPUT IS RETURNED THEN NO CANDIDATE ROLES FOR STS ASSUME-ROLE WERE FOUND. 19 | 20 | 21 | ## Steps 22 | **For check-identity.py and check-s3access.py:** 23 | 24 | 1. Ensure that boto3 is installed (pip3 install boto3) 25 | 2. Create a file (example: input.txt) and add one set of credentials per row in this format: accesskey,secretkey 26 | 3. in check-identity.py, the region by default is set to **us-west-1**. You can edit that value in the script as needed. 27 | 4. Run `python3 check-identity.py -f input.txt`. This script will take all key pairs inclued in input.txt and perform the checks listed above. 28 | 5. Based on which keys from #2 have s3 bucket access, add just those keys into a new input file (ex: input2.txt). 29 | 6. Run `python3 check-s3-access.py -f input2.txt`. This script will then recursively check across all buckets to see which buckets a key pair can access see into. Results will be written to an outfile in the current directory with the access key in the filename. You can check the output for successes by running `grep "CAN read" [outputfile]` 30 | 31 | **For assume-role-check.py:** 32 | 1. run `aws iam list-roles > output.txt` 33 | 2. run `aws sts get-caller-identity` on the creds and copy the ARN value 34 | 3. run `python3 assume-role-check.py -a [ARN_value] -f [iam-list-roles-output-file-from-above]`. The script will then check which roles are potential candidates for sts assume-role operations. IF NO OUTPUT IS RETURNED THEN NO CANDIDATE ROLES FOR STS ASSUME-ROLE WERE FOUND. 35 | -------------------------------------------------------------------------------- /assume-role-check.py: -------------------------------------------------------------------------------- 1 | import json 2 | import boto3 3 | import optparse 4 | from optparse import OptionParser 5 | import os 6 | import sys 7 | 8 | #steps once you find an account with iam list-roles permissions: 9 | #1. run sts get-caller-identity on those keys and copy the ARN value (don't need to copy the quotes just the value) 10 | #2. run "aws iam list-roles > outfile.txt" with the creds you have 11 | #3. run this script: python3 assume-role-check.py -a [ARN_value] -f [list-roles-output-file.txt]. Results will be displayed to stdout 12 | 13 | if (len(sys.argv) != 5 and '-h' not in sys.argv): 14 | print("Usage: python3 %s -f [path_to_input_file]\n" % sys.argv[0]) 15 | sys.exit(0) 16 | 17 | parser = OptionParser() 18 | parser.add_option("-f", "--file", help="Path to aws iam list-roles output file.") 19 | parser.add_option("-a", "--arn", help="ARN value of your account from running sts get-caller-identity.") 20 | (options,args) = parser.parse_args() 21 | 22 | file = options.file 23 | arn = options.arn 24 | 25 | 26 | try: 27 | myarn = arn.split(':') 28 | myarn2 = myarn[0] + ':' + myarn[1] + ':' + myarn[2] + '::' + myarn[4] 29 | 30 | if os.path.exists(file): 31 | f = open(file,"r") 32 | info = json.loads(f.read()) 33 | 34 | for i in info['Roles']: 35 | z = i['RoleName'] 36 | x = i['Arn'] 37 | q = i['AssumeRolePolicyDocument']['Statement'] 38 | q2 = str(q) 39 | 40 | if "Effect" in q2 and "Allow" in q2 and "Principal" in q2 and "AWS" in q2 and myarn2 in q2 and "'Condition': {}" in q2: 41 | print("") 42 | print("\033[92m\033[4m[+] Potential role for sts-assume role: (current identity: %s)\033[0m"%str(arn)) 43 | print("\033[33mRole Name:\033[0m %s"%str(z)) 44 | print("\033[33mRole Arn:\033[0m %s"%str(x)) 45 | print("\033[33mAssumeRolePolicyDocument Info:\033[0m %s"%str(q2)) 46 | print("\033[33mTest With Command:\033[1maws sts assume-role --role-arn \"%s\" --role-session-name MySession\033[0m"%str(x)) 47 | 48 | print("") 49 | print("") 50 | else: 51 | print("[-] File %s not found"%file) 52 | 53 | except Exception as e: 54 | print(e) 55 | -------------------------------------------------------------------------------- /check-identity.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import os 3 | import sys 4 | import optparse 5 | from optparse import OptionParser 6 | import threading 7 | from queue import Queue 8 | 9 | 10 | ######################### 11 | def checkidentity(worker): 12 | try: 13 | x = worker.split(':') 14 | accessky = x[0] 15 | scrtky = x[1] 16 | client = boto3.client('sts',aws_access_key_id=accessky,aws_secret_access_key=scrtky,region_name='us-west-1') 17 | response = client.get_caller_identity() 18 | print("-------------------------------------------------------") 19 | print("STS Check Results for key pair: \033[33m%s : %s\033[0m" % (accessky,scrtky)) 20 | print("\033[92m===> Account: %s\033[0m"%str(response['Account'])) 21 | print("\033[92m===> UserId: %s\033[0m"%str(response['UserId'])) 22 | print("\033[92m===> Arn: %s\033[0m"%str(response['Arn'])) 23 | print("-------------------------------------------------------") 24 | try: 25 | print("-------------------------------------------------------") 26 | print("Checking for s3 bucket access for key pair: \033[33m%s : %s\033[0m" % (accessky,scrtky)) 27 | client2 = boto3.client('s3',aws_access_key_id=accessky,aws_secret_access_key=scrtky,region_name='us-west-1') 28 | r = client2.list_buckets() 29 | print("\033[92m===>[+] Key pair %s : %s has s3 bucket access\033[0m" % (accessky,scrtky)) 30 | print("-------------------------------------------------------") 31 | except Exception as e: 32 | print("\033[91m===>[+] Key pair %s : %s had an error when attempting to list buckets: %s\033[0m" %(accessky,scrtky,e)) 33 | 34 | try: 35 | print("-------------------------------------------------------") 36 | print("Attempting to list role info for key pair \033[33m%s : %s\033[0m" % (accessky,scrtky)) 37 | client3 = boto3.client('iam',aws_access_key_id=accessky,aws_secret_access_key=scrtky,region_name='us-west-1') 38 | b = client3.list_roles() 39 | b2 = b['Roles'] 40 | b3 = str(b2).split(',') 41 | print("\033[92m%s : %s ====> %s\033[0m"%(accessky,scrtky,b3)) 42 | print("-------------------------------------------------------") 43 | 44 | except Exception as e: 45 | print("\033[91m===>[+] Key pair %s : %s had an error when attempting to list role info: %s\033[0m" %(accessky,scrtky,e)) 46 | 47 | try: 48 | print("-------------------------------------------------------") 49 | print("Attempting to list group info for key pair \033[33m%s : %s\033[0m" % (accessky,scrtky)) 50 | client4 = boto3.client('iam',aws_access_key_id=accessky,aws_secret_access_key=scrtky,region_name='us-west-1') 51 | c = client4.list_groups() 52 | c2 = c['Groups'] 53 | c3 = str(c2).split(',') 54 | print("\033[92m%s : %s ====> %s\033[0m"%(accessky,scrtky,c3)) 55 | print("-------------------------------------------------------") 56 | 57 | except Exception as e: 58 | print("\033[91m===>[+] Key pair %s : %s had an error when attempting to list group info: %s\033[0m" %(accessky,scrtky,e)) 59 | 60 | try: 61 | print("-------------------------------------------------------") 62 | print("Attempting to list servicesspecificcredentials key pair \033[33m%s : %s\033[0m" % (accessky,scrtky)) 63 | client5 = boto3.client('iam',aws_access_key_id=akey,aws_secret_access_key=skey,region_name='us-west-1') 64 | d= client5.list_service_specific_credentials() 65 | d2 = d['ServiceSpecificCredentials'] 66 | d3 = str(d2).split(',') 67 | print("\033[92m%s : %s ====> %s\033[0m"%(accessky,scrtky,d3)) 68 | print("-------------------------------------------------------") 69 | 70 | except Exception as e: 71 | print("\033[91m===>[+] Key pair %s : %s had an error when attempting to list servicesspecificcredentials info: %s\033[0m" %(accessky,scrtky,e)) 72 | 73 | try: 74 | print("-------------------------------------------------------") 75 | print("Performing a secretsmanager check for key pair \033[33m%s : %s\033[0m" % (accessky,scrtky)) 76 | client6 = boto3.client('secretsmanager',aws_access_key_id=akey,aws_secret_access_key=skey,region_name='us-west-1') 77 | pag = client6.get_paginator('list_secrets') 78 | iterator = pag.paginate() 79 | for page in iterator: 80 | secdict = page['SecretList'] 81 | print("\033[92m%s : %s ====> %s\033[0m"%(accessky,scrtky,secdict)) 82 | print("-------------------------------------------------------") 83 | 84 | except Exception as e: 85 | print("\033[91m===>[+] Key pair %s : %s had an error when attempting to list secretsmanager info: %s\033[0m" %(accessky,scrtky,e)) 86 | 87 | try: 88 | print("-------------------------------------------------------") 89 | print("Performing a parameter store check for key pair \033[33m%s : %s\033[0m" % (accessky,scrtky)) 90 | client7 = boto3.client('ssm',aws_access_key_id=akey,aws_secret_access_key=skey,region_name='us-west-1') 91 | pag2 = client7.get_paginator('describe_parameters') 92 | iterator2 = pag2.paginate() 93 | for pg in iterator2: 94 | mydict = pg['Parameters'] 95 | print("\033[92m%s : %s ====> %s\033[0m"%(accessky,scrtky,mydict)) 96 | print("-------------------------------------------------------") 97 | 98 | except Exception as e: 99 | print("\033[91m===>[+] Key pair %s : %s had an error when attempting to list parameter store info: %s\033[0m" %(accessky,scrtky,e)) 100 | 101 | try: 102 | print("-------------------------------------------------------") 103 | print("Checking dynamodb list tables access for key pair \033[33m%s : %s\033[0m" % (accessky,scrtky)) 104 | client8 = boto3.client('dynamodb',aws_access_key_id=akey,aws_secret_access_key=skey,region_name='us-west-1') 105 | e = client8.list_tables() 106 | print(response['TableNames']); 107 | print("-------------------------------------------------------") 108 | 109 | except Exception as e: 110 | print("\033[91m===>[+] Key pair %s : %s had an error when attempting to list dynamodb table info: %s\033[0m" %(accessky,scrtky,e)) 111 | 112 | except Exception as e: 113 | print("\033[91m %s\033[0m"%e) 114 | 115 | ########################### 116 | def threader(): 117 | while True: 118 | worker = q.get() 119 | checkidentity(worker) 120 | q.task_done() 121 | ########################### 122 | 123 | if (len(sys.argv) != 3 and '-h' not in sys.argv): 124 | print("Usage: python3 %s -f [path_to_input_file]\n" % sys.argv[0]) 125 | sys.exit(0) 126 | 127 | parser = OptionParser() 128 | parser.add_option("-f", "--file", help="Path to input file with AWS creds") 129 | (options,args) = parser.parse_args() 130 | 131 | file = options.file 132 | keylist = [] 133 | 134 | if os.path.exists(file): 135 | with open(file,'r') as credfile: 136 | for line in credfile: 137 | parsed = line.strip().split(",") 138 | akey = parsed[0] 139 | skey = parsed[1] 140 | fullkey = "%s:%s"%(akey,skey) 141 | keylist.append(fullkey) 142 | 143 | q = Queue() 144 | 145 | for x in range(int(50)): 146 | t = threading.Thread(target=threader) 147 | t.daemon = True 148 | t.start() 149 | 150 | for pair in keylist: 151 | q.put(pair) 152 | 153 | q.join() 154 | print("*"*100) 155 | print("[+] DONE!") 156 | 157 | else: 158 | print("[-] %s not found. Exiting..." % file) 159 | -------------------------------------------------------------------------------- /check-s3-access.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import os 3 | import sys 4 | import optparse 5 | from optparse import OptionParser 6 | import threading 7 | from queue import Queue 8 | 9 | ######################### 10 | def listbuckets(bucket): 11 | #s3 = boto3.resource('s3') 12 | try: 13 | objects = client.list_objects(Bucket=bucket, Prefix='',Delimiter='/') 14 | if len(objects) == 9: 15 | print("\033[92m[+] This key CAN read from s3://%s\033[0m\n" %bucket) 16 | output.write("[+] This key CAN read from s3://%s\n"%bucket) 17 | except: 18 | print("\033[91m[-] Unable to view bucket contents for %s\033[0m\n" %bucket) 19 | output.write("[-] This key is unable to view bucket contents for %s\n"%bucket) 20 | ########################### 21 | def threader(): 22 | while True: 23 | worker = q.get() 24 | listbuckets(worker) 25 | q.task_done() 26 | 27 | if (len(sys.argv) != 3 and '-h' not in sys.argv): 28 | print("Usage: python3 %s -f [path_to_input_file]\n" % sys.argv[0]) 29 | sys.exit(0) 30 | 31 | parser = OptionParser() 32 | parser.add_option("-f", "--file", help="Path to input file with AWS creds") 33 | (options,args) = parser.parse_args() 34 | 35 | file = options.file 36 | 37 | if os.path.exists(file): 38 | with open(file,'r') as credfile: 39 | for line in credfile: 40 | parsed = line.strip().split(",") 41 | akey = parsed[0] 42 | skey = parsed[1] 43 | output = open("%s-s3Check.txt" % akey,"w") 44 | output.write("Recursively checking s3 bucket read access for %s : %s\n" % (akey,skey)) 45 | output.write("-----------------------------------------------------------------------------------\n") 46 | 47 | session = boto3.Session( 48 | aws_access_key_id=akey, 49 | aws_secret_access_key=skey) 50 | 51 | client = boto3.client('s3',aws_access_key_id=akey, 52 | aws_secret_access_key=skey) 53 | 54 | s3 = session.resource('s3') 55 | 56 | q = Queue() 57 | 58 | for x in range(int(50)): 59 | t = threading.Thread(target=threader) 60 | t.daemon = True 61 | t.start() 62 | 63 | for worker in s3.buckets.all(): 64 | q.put(worker.name) 65 | 66 | q.join() 67 | print("*"*100) 68 | print("[+] DONE!") 69 | output.close() 70 | 71 | 72 | 73 | else: 74 | print("[-] %s not found. Exiting..." % file) 75 | -------------------------------------------------------------------------------- /input.txt: -------------------------------------------------------------------------------- 1 | accesskeyhere,secretkeyhere 2 | accesskey2here,secretkey2here 3 | accesskey3here,secret3keyehere 4 | --------------------------------------------------------------------------------