def enumerate_using_iam(access_key, secret_key, session_token, region): output = dict() logger = logging.getLogger() # Connect to the IAM API and start testing. logger.info('Starting permission enumeration for access-key-id "%s"', access_key) iam_client = boto3.client('iam', aws_access_key_id=access_key, aws_secret_access_key=secret_key, aws_session_token=session_token) # Try for the kitchen sink. try: everything = iam_client.get_account_authorization_details() except (botocore.exceptions.ClientError, botocore.exceptions.EndpointConnectionError, botocore.exceptions.ReadTimeoutError): pass else: logger.info( 'Run for the hills, get_account_authorization_details worked!') logger.info('-- %s', json.dumps(everything, indent=4, default=json_encoder)) output['iam.get_account_authorization_details'] = remove_metadata( everything) enumerate_user(iam_client, output) enumerate_role(iam_client, output) return output
def check_one_permission((access_key, secret_key, session_token, region, service_name, operation_name)): logger = logging.getLogger() service_client = get_client(access_key, secret_key, session_token, service_name, region) if service_client is None: return try: action_function = getattr(service_client, operation_name) except AttributeError: # The service might not have this action (this is most likely # an error with generate_bruteforce_tests.py) logger.error('Remove %s.%s action' % (service_name, operation_name)) return logger.debug('Testing %s.%s() in region %s' % (service_name, operation_name, region)) try: action_response = action_function() except (botocore.exceptions.ClientError, botocore.exceptions.EndpointConnectionError, botocore.exceptions.ConnectTimeoutError, botocore.exceptions.ReadTimeoutError): return except botocore.exceptions.ParamValidationError: logger.error('Remove %s.%s action' % (service_name, operation_name)) return msg = '-- %s.%s() worked!' args = (service_name, operation_name) logger.info(msg % args) key = '%s.%s' % (service_name, operation_name) return key, remove_metadata(action_response)
def enumerate_user(iam_client, output): logger = logging.getLogger() output['root_account'] = False # Attempt to get user to start. try: user = iam_client.get_user() except botocore.exceptions.ClientError as err: arn, arn_id, arn_path = report_arn(str(err)) output['arn'] = arn output['arn_id'] = arn_id output['arn_path'] = arn_path # The checks which follow all required the user name to run, if we were # unable to get that piece of information just return return else: output['iam.get_user'] = remove_metadata(user) if 'UserName' not in user['User']: if user['User']['Arn'].endswith(':root'): # OMG logger.warn('Found root credentials!') output['root_account'] = True return else: logger.error('Unexpected iam.get_user() response: %s' % user) return else: user_name = user['User']['UserName'] # Attempt to get policies attached to this user. try: user_policies = iam_client.list_attached_user_policies( UserName=user_name) except botocore.exceptions.ClientError as err: pass else: output['iam.list_attached_user_policies'] = remove_metadata( user_policies) logger.info('User "%s" has %0d attached policies', user_name, len(user_policies['AttachedPolicies'])) # List all policies, if present. for policy in user_policies['AttachedPolicies']: logger.info('-- Policy "%s" (%s)', policy['PolicyName'], policy['PolicyArn']) # Attempt to get inline policies for this user. try: user_policies = iam_client.list_user_policies(UserName=user_name) except botocore.exceptions.ClientError as err: pass else: output['iam.list_user_policies'] = remove_metadata(user_policies) logger.info('User "%s" has %0d inline policies', user_name, len(user_policies['PolicyNames'])) # List all policies, if present. for policy in user_policies['PolicyNames']: logger.info('-- Policy "%s"', policy) # Attempt to get the groups attached to this user. user_groups = dict() user_groups['Groups'] = [] try: user_groups = iam_client.list_groups_for_user(UserName=user_name) except botocore.exceptions.ClientError as err: pass else: output['iam.list_groups_for_user'] = remove_metadata(user_groups) logger.info('User "%s" has %0d groups associated', user_name, len(user_groups['Groups'])) # Attempt to get the group policies output['iam.list_group_policies'] = dict() for group in user_groups['Groups']: try: group_policy = iam_client.list_group_policies( GroupName=group['GroupName']) output['iam.list_group_policies'][ group['GroupName']] = remove_metadata(group_policy) logger.info('-- Group "%s" has %0d inline policies', group['GroupName'], len(group_policy['PolicyNames'])) # List all group policy names. for policy in group_policy['PolicyNames']: logger.info('---- Policy "%s"', policy) except botocore.exceptions.ClientError as err: pass return output
def enumerate_role(iam_client, output): logger = logging.getLogger() # This is the closest thing we have to a role ARN user_or_role_arn = output.get('arn', None) if user_or_role_arn is None: # The checks which follow all required the user name to run, if we were # unable to get that piece of information just return return # Attempt to get role to start. try: role = iam_client.get_role(RoleName=user_or_role_arn) except botocore.exceptions.ClientError as err: arn, arn_id, arn_path = report_arn(str(err)) if arn is not None: output['arn'] = arn output['arn_id'] = arn_id output['arn_path'] = arn_path if 'role' not in user_or_role_arn: # We did out best, but we got nothing from iam return else: role_name = user_or_role_arn else: output['iam.get_role'] = remove_metadata(role) role_name = role['Role']['RoleName'] # Attempt to get policies attached to this user. try: role_policies = iam_client.list_attached_role_policies( RoleName=role_name) except botocore.exceptions.ClientError as err: pass else: output['iam.list_attached_role_policies'] = remove_metadata( role_policies) logger.info('Role "%s" has %0d attached policies', role['Role']['RoleName'], len(role_policies['AttachedPolicies'])) # List all policies, if present. for policy in role_policies['AttachedPolicies']: logger.info('-- Policy "%s" (%s)', policy['PolicyName'], policy['PolicyArn']) # Attempt to get inline policies for this user. try: role_policies = iam_client.list_role_policies(RoleName=role_name) except botocore.exceptions.ClientError as err: pass else: output['iam.list_role_policies'] = remove_metadata(role_policies) logger.info('User "%s" has %0d inline policies', role['Role']['RoleName'], len(role_policies['PolicyNames'])) # List all policies, if present. for policy in role_policies['PolicyNames']: logger.info('-- Policy "%s"', policy) return output
def enumerate_role(iam_client, output): logger = logging.getLogger() # This is the closest thing we have to a role ARN user_or_role_arn = output.get('arn', None) if user_or_role_arn is None: # The checks which follow all required the user name to run, if we were # unable to get that piece of information just return return # Attempt to get role to start. try: role = iam_client.get_role(RoleName=user_or_role_arn) except botocore.exceptions.ClientError as err: arn, arn_id, arn_path = report_arn(str(err)) if arn is not None: output['arn'] = arn output['arn_id'] = arn_id output['arn_path'] = arn_path if 'role' not in user_or_role_arn: # We did out best, but we got nothing from iam return else: role_name = user_or_role_arn else: output['iam.get_role'] = remove_metadata(role) role_name = role['Role']['RoleName'] # Attempt to get policies attached to this user. try: role_policies = iam_client.list_attached_role_policies( RoleName=role_name) except botocore.exceptions.ClientError as err: pass else: output['iam.list_attached_role_policies'] = remove_metadata( role_policies) logger.debug('%s', json.dumps(role_policies, indent=4, default=json_encoder)) logger.info('Role "%s" has %0d attached policies', role['Role']['RoleName'], len(role_policies['AttachedPolicies'])) # List all policies, if present. for policy in role_policies['AttachedPolicies']: logger.info('-- Policy "%s" (%s)', policy['PolicyName'], policy['PolicyArn']) try: get_policy = iam.get_role_policy( PolicyName=policy['PolicyName']) policy_version = iam_client.get_policy_version( PolicyArn=policy['PolicyArn'], VersionId=policy['DefaultVersionId']) logger.debug('Role attached policy: {}'.format( policy['PolicyName'])) logger.debug( '%s', json.dumps(policy_version, indent=4, default=json_encoder)) key = 'iam.role_attached_policies' if key not in output.keys(): output[key] = [] output[key].append(remove_metadata(policy_version)) except: pass # Attempt to get inline policies for this user. try: role_policies = iam_client.list_role_policies(RoleName=role_name) except botocore.exceptions.ClientError as err: pass else: output['iam.list_role_policies'] = remove_metadata(role_policies) logger.info('Role "%s" has %0d inline policies', role['Role']['RoleName'], len(role_policies['PolicyNames'])) # List all policies, if present. for policy in role_policies['PolicyNames']: logger.info('-- Policy "%s"', policy) try: get_policy = iam_client.get_user_policy(RoleName=role_name, PolicyName=policy) logger.debug( 'Role inline policy:\n%s', json.dumps(get_policy['PolicyDocument'], indent=4, default=json_encoder)) key = 'iam.role_inline_policies' if key not in output.keys(): output[key] = [] output[key].append( remove_metadata(get_policy['PolicyDocument'])) except: pass return output