Esempio n. 1
0
def _fillvalue(shape):
    param = None
    # ignore some types
    if shape.type_name not in ['jsonvalue_string']:
        param = globals()['_fillvalue_%s' % shape.type_name](shape)
    log.debug('_fillvalue_{} with value {}'.format(shape.type_name, param))
    return param
Esempio n. 2
0
def _fillvalue_structure(shape):
    # Validate required fields.
    fillvalue_members = []
    for required_member in shape.metadata.get('required', []):
        fillvalue_members.append(required_member)
    params = dict()
    for param in fillvalue_members:
        val = _fillvalue(shape.members[param])
        log.debug('required: {} is filled with {}'.format(param, val))
        params[param] = val
    return params
Esempio n. 3
0
def cli(ctx, config, dry_run):

    if not ctx.config:
        ctx.config = config

    if not ctx.dry_run:
        ctx.dry_run = dry_run

        log.debug('Current context. DryRun: {} Config: {}'.format(
            ctx.dry_run, json.dumps(ctx.config, indent=2)))

    if not ctx.config.get('botocore_document_json_path', None):
        log.fatal('botocore_document_json_path not defined in config file')
Esempio n. 4
0
def make_call(config, session, service, command, region=None):
    # Grab a region to use for the calls.  This should be us-west-2
    if not region:
        region = session.get_available_regions(service)[-1]

    if config.get('user_agent', None):
        botocore_config.user_agent = config['user_agent']

    # Create a client with parameter validation off
    client = session.client(service,
                            region_name=region,
                            config=botocore_config)

    # Get the functions that you can call
    functions_list = get_boto_functions(client)

    # Get the service file
    service_file_json = get_service_json_files(config)

    # Get a list of params needed to make the serialization pass in botocore
    service_call_params = get_service_call_params(service_file_json[service])

    for function in functions_list:
        if function[0] == command:

            # The service_file_json doesn't have underscores in names so let's remove them
            function_key = function[0].replace('_', '')

            # We need to pull out the parameters needed in the requestUri, ex. /{Bucket}/{Key+} -> ['Bucket', 'Key']
            params = re.findall('\{(.*?)\}',
                                service_call_params.get(function_key, '/'))
            params = [p.strip('+') for p in params]

            func_params = {}

            for param in params:
                func_params[param] = 'testparameter'

            try:
                make_api_call(service, function, region, func_params)
            except ClientError as e:
                log.debug(e)
            except boto3.exceptions.S3UploadFailedError as e:
                log.debug(e)
            except TypeError as e:
                log.debug(e)
            except KeyError as e:
                log.debug('Unknown Exception: {}.{} - {}'.format(
                    service, function[0], e))

            return
Esempio n. 5
0
def simulate_attack(config, commands, dry_run=False):
    log.debug('Attack chain to be executed:')
    log.debug(json.dumps(commands, indent=4))

    session = boto3.Session()

    for command in commands:
        service_event = command['call'].split('.')

        service = service_event[0]
        api_call = service_event[1]

        delay = command.get('time_delay', 0)
        region = command.get('region', None)

        log.info('Making call - {}.{}'.format(service, api_call))
        if not dry_run:
            make_call(config, session, service, api_call, region)
        log.info('Sleeping {} until next call'.format(delay))
        if not dry_run:
            time.sleep(delay)
Esempio n. 6
0
def process_cloudtrail(arn, files):

    api_calls = []

    log.info('EventSource, EventName, Recorded Name, Match')

    for file in files:
        f = None
        log.debug('Processing file: {}'.format(file))

        if file.endswith('.gz'):
            f = gzip.open(file, 'r')
        else:
            f = open(file, 'r')

        try:
            cloudtrail = json.load(f)
        except Exception as e:
            log.error('Invalid JSON File: {} - {}'.format(file, e))
            continue

        for record in cloudtrail['Records']:
            if record.get('userIdentity', {}).get('arn', '').startswith(arn):
                event_source = record['eventSource'].split('.')[0]
                event_name = record['eventName']

                call = '{}.{}'.format(event_source, event_name)

                if call not in api_calls:
                    session = record['userIdentity']['arn'].split('/')[-1]
                    match = (record['eventName'].lower() == session)
                    log.info('{}, {}, {}, {}'.format(
                        record['eventSource'].split('.')[0],
                        record['eventName'], session, match))
                    api_calls.append(call)

        f.close()

    return api_calls
Esempio n. 7
0
def enumerate_services(config, services, dry_run=False):

    # Create a boto3 session to use for enumeration
    session = boto3.Session()

    authorized_calls = []

    for service in services:

        if service == 's3control':
            log.info(
                'Skipping {} - End-points do not seem to be working'.format(
                    service))
            continue

        if len(session.get_available_regions(service)) == 0:
            if service in [
                    'budgets', 'ce', 'chime', 'cloudfront', 'iam',
                    'importexport', 'organizations', 'route53', 'sts', 'waf'
            ]:
                region = 'us-east-1'
            else:
                log.info(
                    'Skipping {} - No regions exist for this service'.format(
                        service))
                continue
        else:
            if 'us-east-1' in session.get_available_regions(service):
                region = 'us-east-1'
            else:
                log.info('Skipping {} - Only available in {}'.format(
                    service, session.get_available_regions(service)))
                continue

        # Create a service client
        log.info('Creating {} client...'.format(service))

        # Set the user-agent if specified in the config
        if config.get('user_agent', None):
            botocore_config.user_agent = config['user_agent']

        # Create a client with parameter validation off
        client = session.client(service,
                                region_name=region,
                                config=botocore_config)

        # Get the functions that you can call
        functions_list = get_boto_functions(client)

        # Get the service file
        service_file_json = get_service_json_files(config)

        # Get a list of params needed to make the serialization pass in botocore
        service_call_params = get_service_call_params(
            service_file_json[service])

        # Loop through all the functions and call them
        for function in functions_list:

            # The service_file_json doesn't have underscores in names so let's remove them
            function_key = function[0].replace('_', '')

            # Session Name Can only be 64 characters long
            if len(function_key) > 64:
                session_name = function_key[:63]
                log.info('Session Name {} is for {}'.format(
                    session_name, function_key))
            else:
                session_name = function_key

            # Set the session to the name of the API call we are making
            session = get_assume_role_session(
                account_number=config['account_number'],
                role=config['account_role'],
                session_id=session_name)

            new_client = session.client(service,
                                        region_name=region,
                                        config=botocore_config)
            new_functions_list = get_boto_functions(new_client)

            for new_func in new_functions_list:
                if new_func[0] == function[0]:

                    # We need to pull out the parameters needed in the requestUri, ex. /{Bucket}/{Key+} -> ['Bucket', 'Key']
                    params = re.findall(
                        '\{(.*?)\}',
                        service_call_params.get(function_key, '/'))
                    params = [p.strip('+') for p in params]

                    try:
                        func_params = {}

                        for param in params:
                            # Set something because we have to
                            func_params[param] = 'testparameter'

                        log.info('Calling {}.{} with params {} in {}'.format(
                            service, new_func[0], func_params, region))

                        if not dry_run:
                            make_api_call(service, new_func, region,
                                          func_params)

                    except ClientError as e:
                        if "ValidationError" in str(e):
                            log.error(e)
                        else:
                            log.debug(e)
                    except boto3.exceptions.S3UploadFailedError as e:
                        log.debug(e)
                    except TypeError as e:
                        log.debug(e)
                    except KeyError as e:
                        log.debug('Unknown Exception: {}.{} - {}'.format(
                            service, new_func[0], e))
Esempio n. 8
0
def enumerate_services(config, services, dry_run=False):
    # read a CSV file for seen functions
    apis = defaultdict(list)
    with open('botocore_api_2_event_names.csv', 'rb') as csvfile:
        reader = csv.reader(csvfile)
        for row in reader:
            x = row[1].split('_')
            if len(x) > 1:
                # service_name without '-'
                apis[x[0]].append(row[1])
            else:
                # event_source as a service_name without '-'
                apis[row[0].replace('-', '')].append(row[1])

    # Create a boto3 session to use for enumeration
    session = boto3.Session()

    authorized_calls = []

    for service in services:

        if len(session.get_available_regions(service)) == 0:
            log.debug('Skipping {} - No regions exist for this service'.format(
                service))
            continue

        # Create a service client
        log.info('Creating {} client...'.format(service))

        # Grab a region to use for the calls.  This should be us-west-2
        region = session.get_available_regions(service)[-1]

        # Set the user-agent if specified in the config
        if config.get('user_agent', None):
            botocore_config.user_agent = config['user_agent']

        # Create a client with parameter validation off
        client = session.client(service,
                                region_name=region,
                                config=botocore_config)

        # Get the functions that you can call
        functions_list = get_boto_functions(client)

        # Get the service file
        service_file_json = get_service_json_files(config)

        # Get a list of params needed to make the serialization pass in botocore
        service_call_params = get_service_call_params(
            service_file_json[service])

        # Loop through all the functions and call them
        for function in functions_list:

            # The service_file_json doesn't have underscores in names so let's remove them
            function_key = function[0].replace('_', '')

            ## Session Name Can only be 64 characters long
            srv_len = len(service)
            session_name = service.replace('-', '')
            if srv_len > 20:
                session_name = service[:19]
                srv_len = 20
            func_key_limit = 64 - srv_len - 1
            if len(function_key) > func_key_limit:
                session_name += '_' + function_key[:func_key_limit - 1]
                log.info('Session Name {} is for {}:{}'.format(
                    session_name, service, function_key))
            else:
                session_name += "_" + function_key

            # check session_name in the seen functions
            if session_name in apis[service.replace('-', '')]:
                log.info('found {}:{}, skipping'.format(service, session_name))
                continue

            # Set the session to the name of the API call we are making
            session = get_assume_role_session(
                account_number=config['account_number'],
                role=config['account_role'],
                session_id=session_name)

            new_client = session.client(service,
                                        region_name=region,
                                        config=botocore_config)
            new_functions_list = get_boto_functions(new_client)

            for new_func in new_functions_list:
                if new_func[0] == function[0]:

                    # We need to pull out the parameters needed in the requestUri, ex. /{Bucket}/{Key+} -> ['Bucket', 'Key']
                    params = re.findall(
                        '\{(.*?)\}',
                        service_call_params.get(function_key, '/'))
                    params = [p.strip('+') for p in params]

                    try:
                        func_params = {}

                        for param in params:
                            # Set something because we have to
                            func_params[param] = 'testparameter'

                        log.info('Calling {}:{} with params {} in {}'.format(
                            service, new_func[0], func_params, region))

                        # fill values for required members
                        operation_name = new_client._PY_TO_OP_NAME[new_func[0]]
                        operation_model = new_client._service_model.operation_model(
                            operation_name)
                        input_shape = operation_model.input_shape
                        if service == 'sts' and operation_name == 'AssumeRole':
                            log.info(
                                'skipped sts:AssumeRole for required member')
                        elif input_shape.type_name == 'structure':
                            # find the required members
                            extra_params = _fillvalue(input_shape)
                            if extra_params:
                                func_params.update(extra_params)
                            else:
                                log.info('skipped this input_shape: {}'.format(
                                    input_shape))

                        if not dry_run:
                            make_api_call(service, new_func, region,
                                          func_params)

                    except ClientError as e:
                        log.error('ClientError: {}:{} - {}'.format(
                            service, new_func[0], e))
                    except EndpointConnectionError as e:
                        log.error('EndpointConnectionError: {}:{} - {}'.format(
                            service, new_func[0], e))
                    except boto3.exceptions.S3UploadFailedError as e:
                        log.error('S3UploadFailedError: {}:{} - {}'.format(
                            service, new_func[0], e))
                    except TypeError as e:
                        log.error('TypeError: {}:{} - {}'.format(
                            service, new_func[0], e))
                    except KeyError as e:
                        log.error('Unknown Exception: {}:{} - {}'.format(
                            service, new_func[0], e))