示例#1
0
    def process_report_data(self, report_data, number_of_days_verdict_valid,
                            number_of_days_judgement_valid,
                            number_of_days_indicator_valid, limit):
        bundle = Bundle()

        bundle.add(
            self.extract_verdict(report_data, number_of_days_verdict_valid))

        bundle.add(
            self._judgement(report_data['result']['score'],
                            number_of_days_judgement_valid))

        categories = report_data.get('result', {}).get('cats', {})
        categories = sorted(categories.items())[:limit]

        for category, flag in categories:
            s = self._sighting(category)
            i = self._indicator(category,
                                number_of_days_indicator_valid,
                                flag=flag)
            bundle.add(s)
            bundle.add(i)
            bundle.add(self._relationship(s, i, 'sighting-of'))

        return bundle
示例#2
0
    def process_resolutions(self, resolutions):
        bundle = Bundle()

        related = self._extract_related(resolutions)
        if related:
            related = sorted(related)
            description = self._resolution_description()
            sighting = self._sighting(DNS_INFORMATION_CATEGORY,
                                      description=description)
            sighting['relations'] = [self._resolved_to(r) for r in related]
            bundle.add(sighting)

        return bundle
示例#3
0
def deliberate(observable):
    output = get_cyberprotect_outputs(observable)

    result = Bundle()
    if output:
        scores = output.get('scores', [])
        if len(scores) >= current_app.config['CTR_ENTITIES_LIMIT']:
            scores = scores[:current_app.config['CTR_ENTITIES_LIMIT']]

        for score in scores:
            # need to check because [[]] can be returned in output
            if score and score.get('score') is not None:
                result.add(extract_verdicts(output, score))

    return result
def observe_observables():
    observables = get_observables()

    g.bundle = Bundle()

    key = get_key()

    if key is None:
        raise AuthenticationRequiredError

    url = current_app.config['AVOTX_URL']
    headers = {'User-Agent': current_app.config['CTR_USER_AGENT']}

    client = Client(key, url, headers=headers)
    limit = current_app.config['CTR_ENTITIES_LIMIT']

    for observable in observables:
        observable = Observable.instance_for(**observable)
        if observable is None:
            continue

        bundle = observable.observe(client, limit=limit)
        g.bundle |= bundle

    data = g.bundle.json()

    return jsonify_data(data)
def observe_observables():
    input_observables = get_observables()

    g.bundle = Bundle()

    key = get_key()

    if key is None:
        raise AuthenticationRequiredError

    url = current_app.config['AVOTX_URL']
    headers = {'User-Agent': current_app.config['CTR_USER_AGENT']}

    client = Client(key, url, headers=headers)
    limit = current_app.config['CTR_ENTITIES_LIMIT']

    prepared_observables = []
    for input_observable in input_observables:
        prepared_observable = Observable.instance_for(**input_observable)
        if prepared_observable is not None:
            prepared_observables.append(prepared_observable)

    def make_bundle(observable):
        return observable.observe(client, limit=limit)

    with ThreadPoolExecutor(
            max_workers=get_workers(prepared_observables)) as executor:
        bundles = executor.map(make_bundle, prepared_observables)

    for bundle in bundles:
        g.bundle |= bundle

    data = g.bundle.json()

    return jsonify_data(data)
示例#6
0
def observe_observables():
    observables, error = get_observables()

    if error:
        return jsonify_errors(error)

    observable_types = current_app.config['GTI_OBSERVABLE_TYPES']

    observables = [
        observable
        for observable in observables
        if observable['type'] in observable_types
    ]

    key = get_key()

    bundle = Bundle()

    for observable in observables:
        events, error = get_events_for_observable(key, observable)

        if error:
            # Make sure not to lose any data processed so far.
            return jsonify_errors(error, data=bundle.json())

        indicator_by_rule_uuid = {}

        for event in events:
            sighting = Sighting.map(event)
            bundle.add(sighting)

            if 'detection' in event:
                rule = event['detection']['rule']

                indicator = indicator_by_rule_uuid.get(rule['uuid'])
                if indicator is None:
                    indicator = Indicator.map(rule)
                    indicator_by_rule_uuid[rule['uuid']] = indicator
                    bundle.add(indicator)

                relationship = Relationship.map(sighting, indicator)
                bundle.add(relationship)

    data = bundle.json()

    return jsonify_data(data)
示例#7
0
def observe_observables():
    observables, error = get_observables()

    if error:
        return jsonify_errors(error)

    emails = [
        observable['value'] for observable in observables
        if observable['type'] == 'email'
    ]

    key = get_key()

    bundle = Bundle()

    limit = current_app.config['CTR_ENTITIES_LIMIT']

    for email in emails:
        breaches, error = fetch_breaches(key, email)

        if error:
            return jsonify_errors(error, data=bundle.json())

        breaches.sort(key=itemgetter('BreachDate'), reverse=True)

        breaches = breaches[:limit]

        source_uri = current_app.config['HIBP_UI_URL'].format(
            email=quote(email, safe=''))

        for breach in breaches:
            indicator = Indicator.map(breach)
            sighting = Sighting.map(breach, email, source_uri)
            relationship = Relationship.map(indicator, sighting)

            bundle.add(indicator)
            bundle.add(sighting)
            bundle.add(relationship)

    data = bundle.json()

    return jsonify_data(data)
def observe_observables():
    credentials = get_credentials()
    observables = get_observables()

    client = XForceClient(current_app.config['API_URL'], credentials,
                          current_app.config['USER_AGENT'])

    ui_url = current_app.config['UI_URL']
    number_of_days_verdict_valid = int(
        current_app.config['NUMBER_OF_DAYS_VERDICT_IS_VALID'])
    number_of_days_judgement_valid = int(
        current_app.config['NUMBER_OF_DAYS_JUDGEMENT_IS_VALID'])
    number_of_days_indicator_valid = int(
        current_app.config['NUMBER_OF_DAYS_INDICATOR_IS_VALID'])
    limit = current_app.config['CTR_ENTITIES_LIMIT']

    g.bundle = Bundle()

    try:
        for observable in observables:
            refer_link = client.refer_link(ui_url, observable)
            mapping = Mapping.for_(observable, source_uri=refer_link)

            if mapping:
                if limit > 0:
                    report = client.report(observable)
                    if report:
                        report_bundle = mapping.process_report_data(
                            report, number_of_days_verdict_valid,
                            number_of_days_judgement_valid,
                            number_of_days_indicator_valid, limit)
                        limit -= len(report_bundle.get(SIGHTING))
                        g.bundle.merge(report_bundle)

                if limit > 0 and isinstance(mapping, DNSInformationMapping):
                    resolutions_bundle = mapping.process_resolutions(
                        client.resolve(observable))
                    limit -= len(resolutions_bundle.get(SIGHTING))
                    g.bundle.merge(resolutions_bundle)

                if limit > 0:
                    api_linkage = client.api_linkage(observable)
                    if api_linkage:
                        api_linkage_bundle = mapping.process_api_linkage(
                            api_linkage, ui_url,
                            number_of_days_indicator_valid, limit)
                        g.bundle.merge(api_linkage_bundle)

    except KeyError:
        add_error(XForceKeyError())

    return jsonify_result()
示例#9
0
def observe_observables():
    _ = get_jwt()
    relay_input = get_json(ObservableSchema(many=True))

    observables = group_observables(relay_input)

    if not observables:
        return jsonify_data({})

    g.bundle = Bundle()
    for observable in observables:
        g.bundle.merge(observe(observable))

    return jsonify_data(g.bundle.json())
def deliberate_observables():
    def deliberate(observable):
        mapping = Mapping.for_(observable)
        client_data = client.report(observable)
        if client_data:
            return mapping.extract_verdict(client_data,
                                           number_of_days_verdict_valid)

    credentials = get_credentials()

    observables = get_observables()
    observables = [
        ob for ob in observables if ob['type'] in XFORCE_OBSERVABLE_TYPES
    ]

    client = XForceClient(current_app.config['API_URL'], credentials,
                          current_app.config['USER_AGENT'])

    number_of_days_verdict_valid = int(
        current_app.config['NUMBER_OF_DAYS_VERDICT_IS_VALID'])

    g.bundle = Bundle()

    try:
        with ThreadPoolExecutor(
                max_workers=min(len(observables) or 1, (cpu_count() or 1) *
                                5)) as executor:
            iterator = executor.map(deliberate, observables)

        g.bundle = Bundle(
            *[verdict for verdict in iterator if verdict is not None])

    except KeyError:
        add_error(XForceKeyError())

    return jsonify_result()
示例#11
0
    def process_report_data(self, report_data, number_of_days_verdict_valid,
                            number_of_days_judgement_valid, *args):

        bundle = Bundle()
        bundle.add(
            self.extract_verdict(report_data, number_of_days_verdict_valid))

        bundle.add(
            self._judgement(
                report_data.get('malware', {}).get('risk'),
                number_of_days_judgement_valid))

        return bundle
def observe_observables():
    relay_input, error = validate_relay_input()

    if error:
        return jsonify_errors(error)

    observables = group_observables(relay_input)

    if not observables:
        # Optimize a bit by not sending empty requests to the GSB API.
        return jsonify_data({})

    bundle = Bundle()

    start_time = datetime.utcnow()

    # Split the data into chunks and make multiple requests to the GSB API.

    size = current_app.config['GSB_API_MAX_THREAT_ENTRIES_PER_REQUEST']

    for observables in map(dict, chunks(observables.items(), size)):
        gsb_input = build_gsb_input(observables)

        gsb_output, error = fetch_gsb_output(gsb_input)

        if error:
            return jsonify_errors(error, data=bundle.json())

        matches = group_matches(gsb_output)

        # Extract judgements first in order to label each match with some
        # "judgement_id", so that it can be extracted for each verdict later.
        judgements = extract_judgements(observables, matches, start_time)
        verdicts = extract_verdicts(observables, matches, start_time)

        for entity in chain(judgements, verdicts):
            bundle.add(entity)

    relay_output = bundle.json()

    return jsonify_data(relay_output)
def deliberate_observables():
    relay_input, error = validate_relay_input()

    if error:
        return jsonify_errors(error)

    observables = group_observables(relay_input)

    if not observables:
        # Optimize a bit by not sending empty requests to the GSB API.
        return jsonify_data({})

    bundle = Bundle()

    start_time = datetime.utcnow()

    # Split the data into chunks and make multiple requests to the GSB API.

    size = current_app.config['GSB_API_MAX_THREAT_ENTRIES_PER_REQUEST']

    for observables in map(dict, chunks(observables.items(), size)):
        gsb_input = build_gsb_input(observables)

        gsb_output, error = fetch_gsb_output(gsb_input)

        if error:
            return jsonify_errors(error, data=bundle.json())

        matches = group_matches(gsb_output)

        verdicts = extract_verdicts(observables, matches, start_time)

        for entity in verdicts:
            bundle.add(entity)

    relay_output = bundle.json()

    return jsonify_data(relay_output)
示例#14
0
def observe(observable):
    output = get_cyberprotect_outputs(observable)

    result = Bundle()
    if output:
        scores = output.get('scores', [])
        if len(scores) >= current_app.config['CTR_ENTITIES_LIMIT']:
            scores = scores[:current_app.config['CTR_ENTITIES_LIMIT']]

        for score in scores:
            # need to check because [[]] can be returned in output
            if score and score.get('score') is not None:
                result.add(extract_verdicts(output, score))

                details = score['details']
                if len(details) >= \
                        current_app.config['CTR_ENTITIES_LIMIT']:
                    details = \
                        details[:current_app.config['CTR_ENTITIES_LIMIT']]

                for detail in details:
                    if detail.get('score') is not None:
                        result.add(extract_judgement(output, detail))
    return result
    def observe(self, client: Client, limit: Optional[int] = None) -> Bundle:
        """Build a CTIM bundle for the current observable."""

        bundle = Bundle()

        # Implement a workaround instead of using the "/api/v1/search/pulses"
        # endpoint as it works too slow and is not really optimizable...

        category = {
            'ip': 'IPv4',
            'ipv6': 'IPv6',
        }.get(
            self.type(),
            self.category(),
        )

        endpoint = (f'/api/v1/indicators/{category}/'
                    f"{quote(self.value, safe='@:')}/general")

        data = client.query(endpoint)
        if data is None:
            return bundle

        # Make sure to filter out redundant pulses that do not match anyway.
        pulses = [
            pulse for pulse in data['pulse_info']['pulses']
            if data['base_indicator']['type'] in pulse['indicator_type_counts']
        ]
        if not pulses:
            return bundle

        def indicator_for(pulse, page=1):
            # This limit provides a decent tradeoff between the number of
            # requests to be made and the size of each response coming back.
            limit = 10000

            endpoint = f"/api/v1/pulses/{pulse['id']}/indicators"
            params = {'sort': '-created', 'limit': limit, 'page': page}

            data = client.query(endpoint, params=params)

            for indicator in data['results']:
                if indicator['indicator'] == self.value:
                    return indicator

            if data['next'] is None:
                return None

            return indicator_for(pulse, page=(page + 1))

        with ThreadPoolExecutor(max_workers=get_workers(pulses)) as executor:
            iterator = executor.map(indicator_for, pulses)

        indicators = []

        while True:
            try:
                indicator = next(iterator)
            except RelayError:
                continue
            except StopIteration:
                break
            else:
                if indicator is None:
                    continue
                indicators.append(indicator)

        indicators.sort(key=itemgetter('created'), reverse=True)

        if limit is None:
            limit = len(indicators)

        indicators = indicators[:limit]

        observable = self.json()

        for indicator in indicators:
            pulse = next(pulse for pulse in pulses
                         if pulse['id'] == indicator['pulse_key'])

            # Enrich each AVOTX pulse with some additional context in order to
            # simplify further mapping of that pulse into CTIM entities.
            pulse['indicator'] = indicator
            pulse['observable'] = observable
            pulse['url'] = client.url

            sighting = Sighting.map(pulse)
            indicator = Indicator.map(pulse)
            relationship = Relationship.map(sighting, indicator)

            bundle.add(sighting)
            bundle.add(indicator)
            bundle.add(relationship)

        return bundle
 def observe(self, client: Client, limit: Optional[int] = None) -> Bundle:
     # The AVOTX API does not support searching for email addresses as the
     # "/api/v1/indicators/email/{email}/general" endpoint does not exist.
     return Bundle()
示例#17
0
    def process_report_data(self, report_data, number_of_days_verdict_valid,
                            number_of_days_judgement_valid,
                            number_of_days_indicator_valid, limit):
        bundle = Bundle()

        bundle.add(
            self.extract_verdict(report_data, number_of_days_verdict_valid))

        categories = sorted(report_data.get('cats', {}).items())[:limit]
        for category, score in categories:
            sighting = self._sighting(category)
            indicator = self._indicator(category,
                                        number_of_days_indicator_valid)
            judgement = self._judgement(score / 10,
                                        number_of_days_judgement_valid)
            bundle.add(sighting)
            bundle.add(indicator)
            bundle.add(judgement)
            bundle.add(self._relationship(sighting, judgement, 'based-on'))
            bundle.add(self._relationship(judgement, indicator, 'based-on'))

        return bundle
示例#18
0
    def process_api_linkage(self, api_linkage_data, ui_url,
                            number_of_days_indicator_valid, limit):

        linked_entities = api_linkage_data.get('linkedEntities', [])

        external_references_map = {
            entity['id']: {
                'source_name':
                SOURCE,
                'external_id':
                entity['id'],
                'url':
                urljoin(ui_url,
                        f'/collection/{entity["title"]}-{entity["id"]}')
            }
            for entity in linked_entities
        }
        external_ids = list(external_references_map.keys())
        external_references = list(external_references_map.values())

        def sighting(entity):
            return {
                **SIGHTING_DEFAULTS,
                'id': transient_id(SIGHTING, entity['id']),
                'observed_time': {
                    'start_time': entity['created'],
                    'end_time': entity['created'],
                },
                # Original values: "1owned", "2shared", "3public", "4premier"
                'internal': entity['category'] == '1owned',
                'observables': [self.observable],
                'title': f'Contained in Collection: {entity["title"]}',
            }

        def indicator(entity):
            return {
                **INDICATOR_DEFAULTS,
                'id': transient_id(INDICATOR, entity['id']),
                'producer': entity['owner']['name'],
                'valid_time': self._valid_time(number_of_days_indicator_valid),
                'title': entity["title"],
            }

        linked_entities = sorted(linked_entities,
                                 key=itemgetter('created'),
                                 reverse=True)[:limit]

        bundle = Bundle()
        for entity in linked_entities:
            external_reference = external_references_map[entity['id']]
            common_value = {
                'external_ids': external_ids,
                'external_references': external_references,
                'source_uri': external_reference['url'],
            }

            s = {**sighting(entity), **common_value}
            i = {**indicator(entity), **common_value}
            bundle.add(s)
            bundle.add(i)
            bundle.add(self._relationship(s, i, 'member-of'))

        return bundle