Esempio n. 1
0
def map_to_cif(indicator: Indicator, confidence: int, tags: List[str],
               tlp: str, group: str, logger) -> Union[CIFIndicator, None]:
    """
    Maps a STIX-2 Indicator to a CIFv3 compatible indicator format.
    @param indicator The STIX-2 Indicator to map
    @param confidence The confidence to use when building the CIF indicator
    @param tags The tags to use when building the CIF indicator
    @param tlp The tlp to use when building the CIF indicator
    @param group The group to use when building the CIF indicator
    @return the mapped intel item or None
    """
    if not indicator or type(indicator) is not Indicator:
        logger.debug(f"Expected STIX-2 indicator, discarding {indicator}")
        return None
    if (ThreatBusSTIX2Constants.X_THREATBUS_UPDATE.value
            in indicator.object_properties()):
        logger.debug(
            f"CIFv3 only supports adding indicators, not deleting / editing. Discardig {indicator}"
        )
        return None
    if not is_point_equality_ioc(indicator.pattern):
        logger.debug(
            f"CIFv3 only supports point indicators, discardig {indicator}")
        return None

    object_path, ioc_value = split_object_path_and_value(indicator.pattern)
    if object_path not in cif_supported_types:
        logger.debug(
            f"Discardig indicator with unsupported object-path {indicator}")
        return None

    # convert lasttime
    lasttime = indicator.created.strftime("%Y-%m-%dT%H:%M:%S.%fZ")

    ioc_dict = {
        "indicator": ioc_value,
        "confidence": confidence,
        "tags": tags,
        "tlp": tlp,
        "group": group,
        "lasttime": lasttime,
    }

    try:
        return CIFIndicator(**ioc_dict)
    except InvalidIndicator as e:
        logger.error(f"Invalid CIF indicator {e}")
    except Exception as e:
        logger.error(f"CIF indicator error: {e}")
Esempio n. 2
0
def map_indicator_to_broker_event(indicator: Indicator, module_namespace: str,
                                  logger) -> Union[broker.zeek.Event, None]:
    """
    Maps STIX-2 Indicators to Broker events using the Zeek Intel format
    @see https://docs.zeek.org/en/current/scripts/base/frameworks/intel/main.zeek.html#type-Intel::Type
    @param indicator The STIX-2 Indicator to convert
    @param module_namespace A Zeek namespace to use for sending the event
    @return The mapped broker event or None
    """
    if type(indicator) is not Indicator:
        logger.debug(
            f"Discarding message, expected STIX-2 Indicator: {indicator}")
        return None

    if not is_point_equality_ioc(indicator.pattern):
        logger.debug(
            f"Zeek only supports point-IoCs. Cannot map compound pattern to a Zeek Intel item: {indicator.pattern}"
        )
        return None
    object_path, ioc_value = split_object_path_and_value(indicator.pattern)

    # get matching Zeek intel type
    zeek_type = zeek_intel_type_map.get(object_path, None)
    if not zeek_type:
        logger.debug(
            f"No matching Zeek type found for STIX-2 indicator type '{object_path}'"
        )
        return None

    if zeek_type == "URL":
        # remove leading protocol, if any
        parsed = urlparse(ioc_value)
        scheme = f"{parsed.scheme}://"
        ioc_value = parsed.geturl().replace(scheme, "", 1)
    elif zeek_type == "ADDR" and re.match(".+/.+", ioc_value):
        # elevate to subnet if possible
        zeek_type = "SUBNET"

    operation = "ADD"  ## Zeek operation to add a new Intel item
    if (ThreatBusSTIX2Constants.X_THREATBUS_UPDATE.value
            in indicator.object_properties()
            and indicator.x_threatbus_update == Operation.REMOVE.value):
        operation = "REMOVE"
    return broker.zeek.Event(
        f"{module_namespace}::intel",
        (indicator.created, str(
            indicator.id), zeek_type, ioc_value, operation),
    )
Esempio n. 3
0
    def _handle_indicator(self, indicator: Indicator):
        """
        Handles a STIX-2 Indicator update received via Threat Bus. Does nothing
        in case the indicator already exists and the new indicator does not add
        any new fields/values to the existing indicator. By doing so, this
        function effectively avoids double updates that otherwise would result
        in SSE events without a real change.
        @param indicator The STIX-2 Indicator received from Threat Bus
        """
        if type(indicator) is not Indicator:
            self.opencti_helper.log_error(
                f"Error ingesting indicator from Threat Bus. Expected a STIX-2 Indicator: {indicator}"
            )
            return
        if (
            ThreatBusSTIX2Constants.X_THREATBUS_UPDATE.value
            in indicator.object_properties()
            and indicator.x_threatbus_update == Operation.REMOVE.value
        ):
            # OpenCTI does not support indicator removal via API calls (yet)
            return
        lookup_resp = self.opencti_helper.api.indicator.read(id=indicator.id)
        if not lookup_resp:
            # No indicator with that ID exists already.
            self._create_or_update_indicator(indicator)
            return
        lookup_resp["id"] = lookup_resp["standard_id"]
        lookup_indicator = Indicator(**lookup_resp, allow_custom=True)

        # We found an existing indicator. To avoid double updates in the SSE
        # stream we check if the indicator from Threat Bus adds anything new.

        for prop, new_value in indicator.items():
            if prop == "id" or prop.startswith("x_"):
                continue
            existing_value = lookup_indicator.get(prop, None)
            if existing_value is None or new_value != existing_value:
                self._create_or_update_indicator(indicator)
                return