diff --git a/APIKey.py b/APIKey.py index f7a6e0f..6f4c9f0 100644 --- a/APIKey.py +++ b/APIKey.py @@ -21,9 +21,15 @@ class APIKey: elif provider == Provider.AI21: self.trial_elapsed = False + elif provider == Provider.AWS: + self.useless = True + self.username = "" + self.admin_priv = False + class Provider(Enum): OPENAI = 1, ANTHROPIC = 2 AI21 = 3 PALM = 4 + AWS = 5 diff --git a/AWS.py b/AWS.py new file mode 100644 index 0000000..2920e42 --- /dev/null +++ b/AWS.py @@ -0,0 +1,55 @@ +import boto3 +import APIKey +import botocore.exceptions + + +def check_aws(key: APIKey): + line = key.api_key.split(":") + access_key = line[0] + secret = line[1] + + try: + session = boto3.Session(aws_access_key_id=access_key,aws_secret_access_key=secret) + sts_client = session.client("sts") + iam_client = session.client("iam") + username = sts_client.get_caller_identity()['Arn'].split('/')[1] + policies = iam_client.list_attached_user_policies(UserName=username)['AttachedPolicies'] + + if username is not None: + key.username = username + + if policies is None: + return + + for policy in policies: + if "AdministratorAccess" in policy["PolicyName"]: + key.admin_priv = True + key.useless = False + break + + # should be a catch-all? idk haven't found a non slop key yet + policy_ver = iam_client.get_policy(PolicyArn=policy['PolicyArn'])['Policy']['DefaultVersionId'] + policy_doc = iam_client.get_policy_version(PolicyArn=policy['PolicyArn'], VersionId=policy_ver) + for statement in policy_doc['Statement']: + if statement['Effect'] == 'Allow' and 'iam:CreateUser' in statement['Action']: + key.useless = False + continue + + if key.useless: + return + return True + + except botocore.exceptions.ClientError as e: + # print(f"error occurred: {e}") usually thrown when a key cant list the policies + return + + +def pretty_print_aws_keys(keys): + print('-' * 90) + admin_count = 0 + print(f'Validated {len(keys)} working AWS keys:') + for key in keys: + if key.admin_priv: + admin_count += 1 + print(f'{key.api_key}' + (' | admin' if key.admin_priv else "")) + print(f'\n--- Total Valid AWS Keys: {len(keys)} ({admin_count} with admin priv) ---\n') diff --git a/README.md b/README.md index b86103a..62d8cbc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # keychecker a bulk key checker for various AI services -currently supports openai, anthropic, ai21 and palm keys. it also lists various attributes for each (org, rpm limit, pozzed status etc) +currently supports openai, anthropic, ai21, palm and AWS keys. it also lists various attributes for each (org, rpm limit, pozzed status etc) -may add support for aws or azure keys in the future +may add support for azure keys in the future diff --git a/main.py b/main.py index c44c04c..40b1339 100644 --- a/main.py +++ b/main.py @@ -4,6 +4,7 @@ from Logger import Logger from OpenAI import get_oai_model, get_oai_key_attribs, get_oai_org, pretty_print_oai_keys from AI21 import check_ai21, pretty_print_ai21_keys from Palm import check_palm, pretty_print_palm_keys +from AWS import check_aws, pretty_print_aws_keys from APIKey import APIKey, Provider from concurrent.futures import ThreadPoolExecutor, as_completed @@ -13,7 +14,8 @@ import re api_keys = set() -print("Enter API keys (OpenAI/Anthropic/AI21/PaLM) one per line. Press Enter on a blank line to start validation") +print("Enter API keys (OpenAI/Anthropic/AI21/PaLM/AWS) one per line. Press Enter on a blank line to start validation") +print("Expected format for AWS keys is accesskey:secret") inputted_keys = set() while True: @@ -63,10 +65,17 @@ def validate_palm(key: APIKey): api_keys.add(key) +def validate_aws(key: APIKey): + if check_aws(key) is None: + return + api_keys.add(key) + + oai_regex = re.compile('(sk-[A-Za-z0-9]{20}T3BlbkFJ[A-Za-z0-9]{20})') anthropic_regex = re.compile(r'sk-ant-api03-[A-Za-z0-9\-_]{93}AA') ai21_regex = re.compile('[A-Za-z0-9]{32}') palm_regex = re.compile(r'AIzaSy[A-Za-z0-9\-_]{33}') +aws_regex = re.compile(r'^(AKIA[0-9A-Z]{16}):([A-Za-z0-9+/]{40})$') executor = ThreadPoolExecutor(max_workers=100) @@ -91,6 +100,12 @@ def validate_keys(): continue key_obj = APIKey(Provider.OPENAI, key) futures.append(executor.submit(validate_openai, key_obj)) + elif ":" and "AKIA" in key: + match = aws_regex.match(key) + if not match: + continue + key_obj = APIKey(Provider.AWS, key) + futures.append(executor.submit(validate_aws, key_obj)) else: match = ai21_regex.match(key) if not match: @@ -103,12 +118,13 @@ def validate_keys(): futures.clear() -def get_invalid_keys(valid_oai_keys, valid_anthropic_keys, valid_ai21_keys, valid_palm_keys): +def get_invalid_keys(valid_oai_keys, valid_anthropic_keys, valid_ai21_keys, valid_palm_keys, valid_aws_keys): valid_oai_keys_set = set([key.api_key for key in valid_oai_keys]) valid_anthropic_keys_set = set([key.api_key for key in valid_anthropic_keys]) valid_ai21_keys_set = set([key.api_key for key in valid_ai21_keys]) valid_palm_keys_set = set([key.api_key for key in valid_palm_keys]) - invalid_keys = inputted_keys - valid_oai_keys_set - valid_anthropic_keys_set - valid_ai21_keys_set - valid_palm_keys_set + valid_aws_keys_set = set([key.api_key for key in valid_aws_keys]) + invalid_keys = inputted_keys - valid_oai_keys_set - valid_anthropic_keys_set - valid_ai21_keys_set - valid_palm_keys_set - valid_aws_keys_set if len(invalid_keys) < 1: return print('\nInvalid Keys:') @@ -122,6 +138,7 @@ def output_keys(): valid_anthropic_keys = [] valid_ai21_keys = [] valid_palm_keys = [] + valid_aws_keys = [] for key in api_keys: if key.provider == Provider.OPENAI: valid_oai_keys.append(key) @@ -131,13 +148,15 @@ def output_keys(): valid_ai21_keys.append(key) elif key.provider == Provider.PALM: valid_palm_keys.append(key) + elif key.provider == Provider.AWS: + valid_aws_keys.append(key) output_filename = "key_snapshots.txt" sys.stdout = Logger(output_filename) print("#" * 90) print(f"Key snapshot from {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print("#" * 90) print(f'\n--- Checked {len(inputted_keys)} keys | {len(inputted_keys) - len(api_keys)} were invalid ---') - get_invalid_keys(valid_oai_keys, valid_anthropic_keys, valid_ai21_keys, valid_palm_keys) + get_invalid_keys(valid_oai_keys, valid_anthropic_keys, valid_ai21_keys, valid_palm_keys, valid_aws_keys) print() if valid_oai_keys: pretty_print_oai_keys(valid_oai_keys) @@ -147,6 +166,8 @@ def output_keys(): pretty_print_ai21_keys(valid_ai21_keys) if valid_palm_keys: pretty_print_palm_keys(valid_palm_keys) + if valid_aws_keys: + pretty_print_aws_keys(valid_aws_keys) sys.stdout.file.close()