예제 #1
0
def create_indicator(ioc_type, ioc_value, scan_results):
    if (ioc_type == "url") or (ioc_type == "ip-src") or (ioc_type == "ip_dst") or (ioc_type == "domain") or (ioc_type == "hostname"):
        ioc_pattern = "[url:value = '" + ioc_value + "']"
        indicator = Indicator(labels=["malicious-activity"], pattern=ioc_pattern, description=scan_results)

    if (ioc_type == "md5") or (ioc_type == "sha256"):
        ioc_pattern = "[file:hashes." + ioc_type + " = '" + ioc_value + "']"
        indicator = Indicator(labels=["malicious-activity"], pattern=ioc_pattern, description=scan_results)

    return indicator
예제 #2
0
def create_indicator(content):
    name = "SHA256 for malware object"
    description = "This hash indicates the present of Malware."
    pattern = ''
    # temp=re.findall('"sha256":"(.*?)"',content)
    # if len(temp)!=0:
    value = get(content, 'sha256')
    if (value != -1):
        pattern = "[file:hashes.'SHA-256'='" + value + "']"
    else:
        return None
    indicator_types = ["malicious-activity"]
    pattern_type = 'stix'
    indicator_list = []
    indicator = Indicator(name=name,
                          description=description,
                          pattern_type=pattern_type,
                          pattern=pattern,
                          indicator_types=indicator_types)
    indicator_list.append(indicator)

    name = "MD5 for malware object"
    description = "This hash indicates the present of Malware."
    md5 = content['md5']
    md5_pattern = "[file:hashes.'MD5'='" + md5 + "']"
    indicator1 = Indicator(name=name,
                           description=description,
                           pattern_type=pattern_type,
                           pattern=md5_pattern,
                           indicator_types=indicator_types)
    indicator_list.append(indicator1)

    name = "SHA1 for malware object"
    description = "This hash indicates the present of Malware."
    sha1 = content['sha1']
    sha1_pattern = "[file:hashes.'SHA-1'='" + sha1 + "']"
    indicator2 = Indicator(name=name,
                           description=description,
                           pattern_type=pattern_type,
                           pattern=sha1_pattern,
                           indicator_types=indicator_types)
    indicator_list.append(indicator2)

    name = "Size of malware object"
    description = "Malware size."
    size = content['static_analysis']['binary_info']['size']
    size_pattern = "[file:size=" + str(size) + "]"
    indicator3 = Indicator(name=name,
                           description=description,
                           pattern_type=pattern_type,
                           pattern=size_pattern,
                           indicator_types=indicator_types)
    indicator_list.append(indicator3)

    return indicator_list
예제 #3
0
 def setUp(self):
     self.ts = datetime.now(timezone.utc).astimezone()
     self.indicator_id = "indicator--de0c3d3f-02ee-4086-88f1-51200ac831f7"
     self.point_ioc = "evil.com"
     self.pattern = f"[domain-name:value = '{self.point_ioc}']"
     self.indicator = Indicator(
         id=self.indicator_id,
         created=self.ts,
         modified=self.ts,
         pattern_type="stix",
         pattern=self.pattern,
     )
     self.module_namespace = "TestNamespace"
     self.logger = getLogger("test")
예제 #4
0
def rel_fs_store():
    cam = Campaign(id=CAMPAIGN_ID, **CAMPAIGN_KWARGS)
    idy = Identity(id=IDENTITY_ID, **IDENTITY_KWARGS)
    ind = Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS)
    mal = Malware(id=MALWARE_ID, **MALWARE_KWARGS)
    rel1 = Relationship(ind, 'indicates', mal, id=RELATIONSHIP_IDS[0])
    rel2 = Relationship(mal, 'targets', idy, id=RELATIONSHIP_IDS[1])
    rel3 = Relationship(cam, 'uses', mal, id=RELATIONSHIP_IDS[2])
    stix_objs = [cam, idy, ind, mal, rel1, rel2, rel3]
    fs = FileSystemStore(FS_PATH)
    for o in stix_objs:
        fs.add(o)
    yield fs

    for o in stix_objs:
        filepath = os.path.join(FS_PATH, o.type, o.id,
                                _timestamp2filename(o.modified) + '.json')

        # Some test-scoped fixtures (e.g. fs_store) delete all campaigns, so by
        # the time this module-scoped fixture tears itself down, it may find
        # its campaigns already gone, which causes not-found errors.
        try:
            os.remove(filepath)
        except OSError as e:
            # 3 is the ERROR_PATH_NOT_FOUND windows error code.  Which has an
            # errno symbolic value, but not the windows meaning...
            if e.errno in (errno.ENOENT, 3):
                continue
            raise
예제 #5
0
def create_indicator(
    pattern: str,
    pattern_type: str,
    created_by: Optional[Identity] = None,
    name: Optional[str] = None,
    description: Optional[str] = None,
    valid_from: Optional[datetime] = None,
    labels: Optional[List[str]] = None,
    confidence: Optional[int] = None,
    object_markings: Optional[List[MarkingDefinition]] = None,
    x_opencti_main_observable_type: Optional[str] = None,
) -> Indicator:
    """Create an indicator."""
    custom_properties: Dict[str, Any] = {
        X_OPENCTI_SCORE: DEFAULT_X_OPENCTI_SCORE
    }

    if x_opencti_main_observable_type is not None:
        custom_properties[
            X_OPENCTI_MAIN_OBSERVABLE_TYPE] = x_opencti_main_observable_type

    return Indicator(
        id=_create_random_identifier("indicator"),
        created_by_ref=created_by,
        name=name,
        description=description,
        pattern=pattern,
        pattern_type=pattern_type,
        valid_from=valid_from,
        labels=labels,
        confidence=confidence,
        object_marking_refs=object_markings,
        custom_properties=custom_properties,
    )
예제 #6
0
def create_indicator(
    name: str,
    author: Identity,
    description: str,
    valid_from: datetime,
    observable_type: str,
    observable_value: str,
    pattern_type: str,
    pattern_value: str,
    indicator_pattern: str,
    object_marking_refs: List[MarkingDefinition],
) -> Indicator:
    """Create an indicator."""
    return Indicator(
        created_by_ref=author,
        name=name,
        description=description,
        pattern=str(pattern_value),
        valid_from=valid_from,
        labels=["malicious-activity"],
        object_marking_refs=object_marking_refs,
        custom_properties={
            CustomProperties.OBSERVABLE_TYPE: observable_type,
            CustomProperties.OBSERVABLE_VALUE: observable_value,
            CustomProperties.PATTERN_TYPE: pattern_type,
            CustomProperties.INDICATOR_PATTERN: indicator_pattern,
        },
    )
예제 #7
0
def create_indicator(
    pattern: str,
    pattern_type: str,
    created_by: Optional[Identity] = None,
    created: Optional[datetime] = None,
    modified: Optional[datetime] = None,
    name: Optional[str] = None,
    description: Optional[str] = None,
    valid_from: Optional[datetime] = None,
    labels: Optional[List[str]] = None,
    confidence: Optional[int] = None,
    object_markings: Optional[List[MarkingDefinition]] = None,
) -> Indicator:
    """Create an indicator."""
    return Indicator(
        id=_create_random_identifier("indicator"),
        created_by_ref=created_by,
        created=created,
        modified=modified,
        name=name,
        description=description,
        pattern=pattern,
        pattern_type=pattern_type,
        valid_from=valid_from,
        labels=labels,
        confidence=confidence,
        object_marking_refs=object_markings,
        custom_properties={X_OPENCTI_SCORE: DEFAULT_X_OPENCTI_SCORE},
    )
    def test_zmq_app_plugin_message_roundtrip(self):
        """
        Backend-agnostic message passing scenario. Sends a fixed amount of
        messages via the threatbus ZeroMQ app plugin, subscribes to Threat Bus,
        and checks if the initially sent messages can be retrieved back.
        """
        result_q = queue.Queue()
        items = 2
        topics = ["stix2/indicator", "stix2/sighting"]
        rec = threading.Thread(target=zmq_receiver.forward,
                               args=(items, topics, result_q),
                               daemon=False)
        rec.start()
        ioc = Indicator(pattern_type="stix",
                        pattern="[ipv4-addr:value = '6.6.6.6']")
        zmq_sender.send(
            "stix2/indicator",
            ioc.serialize(),
            port=13372,
            bind=False,
        )
        sighting = Sighting(sighting_of_ref=ioc.id)
        zmq_sender.send(
            "stix2/sighting",
            sighting.serialize(),
            port=13372,
            bind=False,
        )
        time.sleep(1)
        self.assertEqual(result_q.qsize(), items)

        event = result_q.get(timeout=1)
        self.assertIsNotNone(event)
        self.assertEqual(parse(event), ioc)
        result_q.task_done()

        event = result_q.get(timeout=1)
        self.assertIsNotNone(event)
        self.assertEqual(parse(event), sighting)
        result_q.task_done()

        self.assertEqual(0, result_q.qsize())
        result_q.join()
        rec.join(timeout=1)
예제 #9
0
def rel_mem_store():
    cam = Campaign(id=CAMPAIGN_ID, **CAMPAIGN_KWARGS)
    idy = Identity(id=IDENTITY_ID, **IDENTITY_KWARGS)
    ind = Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS)
    mal = Malware(id=MALWARE_ID, **MALWARE_KWARGS)
    rel1 = Relationship(ind, 'indicates', mal, id=RELATIONSHIP_IDS[0])
    rel2 = Relationship(mal, 'targets', idy, id=RELATIONSHIP_IDS[1])
    rel3 = Relationship(cam, 'uses', mal, id=RELATIONSHIP_IDS[2])
    stix_objs = [cam, idy, ind, mal, rel1, rel2, rel3]
    yield MemoryStore(stix_objs)
예제 #10
0
    def setUp(self):
        self.ts = datetime.now().astimezone()
        self.ioc_id = "indicator--42d31a5b-2da0-4bdd-9823-1723a98fc2fb"
        self.ioc_value = "example.com"
        self.ioc = Indicator(
            id=self.ioc_id,
            pattern_type="stix",
            pattern=f"[domain-name:value = '{self.ioc_value}']",
        )

        self.sighting_context = {
            "ts": "2017-03-03T23:56:09.652643840",
            "uid": "CMeLkt11aTqwgN4FI9",
            "id.orig_h": "172.31.130.19",
            "id.orig_p": 43872,
            "id.resp_h": "172.31.129.17",
            "id.resp_p": 20004,
            "proto": "tcp",
            "service": None,
            "duration": 0.025249,
            "orig_bytes": 311,
            "resp_bytes": 999,
            "conn_state": "SF",
            "local_orig": None,
            "local_resp": None,
            "missed_bytes": 0,
            "history": "ShADadFf",
            "orig_pkts": 9,
            "orig_ip_bytes": 787,
            "resp_pkts": 7,
            "resp_ip_bytes": 1371,
            "tunnel_parents": [],
            "alert": {
                "signature": "VAST-RETRO Generic IoC match for: 172.31.129.17",
                "category": "Potentially Bad Traffic",
                "action": "allowed",
            },
            "event_type": "alert",
            "_extra": {
                "vast-ioc": "172.31.129.17"
            },
            "source": "VAST",
        }
        self.sighting = Sighting(sighting_of_ref=self.ioc_id)

        self.snapshot_id = "SNAPSHOT_UUID"
        self.snapshot = timedelta(days=42, hours=23, minutes=13, seconds=37)
        self.snapshot_request = SnapshotRequest(MessageType.SIGHTING,
                                                self.snapshot_id,
                                                self.snapshot)

        self.snapshot_envelope_indicator = SnapshotEnvelope(
            MessageType.INDICATOR, self.snapshot_id, self.ioc)
        self.snapshot_envelope_sighting = SnapshotEnvelope(
            MessageType.SIGHTING, self.snapshot_id, self.sighting)
예제 #11
0
    def _map_to_threatbus(
        self, data: dict, opencti_action: str
    ) -> Union[Indicator, None]:
        """
        Inspects the given OpenCTI data point and either returns a valid STIX-2
        Indicator or None.
        @param data A dict object with OpenCTI SSE data
        @param opencti_action A string indicating what happened to this item
            (either `create`, `update` or `delete`)
        @return a STIX-2 Indicator or None
        """
        opencti_id: str = data.get("x_opencti_id", None)
        if not opencti_id:
            self.opencti_helper.log_error(
                "Cannot process data without 'x_opencti_id' field"
            )
            return

        event_id = data.get("id", None)
        update = data.get("x_data_update", {})
        added = update.get("add", {})
        added_ids = added.get("x_opencti_stix_ids", [])
        type_ = data.get("type", None)
        if type_ == "indicator" and len(added_ids) == 1 and added_ids[0] == event_id:
            # Discard the update if it was empty. An update is empty when the
            # only "changed" attribute is the stix_id and it changed to its own
            # already existing value. Example:
            # data ~ {'id': 'XXX', 'x_data_update': {'add': {'x_opencti_stix_ids': ['XXX']}}}
            return

        if opencti_action == "delete":
            indicator: dict = data
            indicator[
                ThreatBusSTIX2Constants.X_THREATBUS_UPDATE.value
            ] = Operation.REMOVE.value
        else:
            indicator: dict = self.opencti_helper.api.indicator.read(id=opencti_id)
            if not indicator:
                # we are only interested in indicators at this time
                return
            # overwrite custom OpenCTI ID
            indicator["id"] = indicator.get("standard_id")
            if opencti_action == "update":
                indicator[
                    ThreatBusSTIX2Constants.X_THREATBUS_UPDATE.value
                ] = Operation.EDIT.value

        # only propagate indicators that are toggled for detection or the user
        # enabled forwarding of all indicators regardless of the toggle
        detection_enabled: bool = indicator.get("x_opencti_detection", False)
        if not detection_enabled and self.forward_all_iocs is not True:
            return

        return Indicator(**indicator, allow_custom=True)
예제 #12
0
def forge_indicator(url, score):

    indicator = Indicator(
        name="Suspicious URL",
        labels=["malicious-activity"],
        created=get_time(),
        description="This URL has been detected as malicious with a score of "
        + str(score) + ".",
        pattern="[url:value = '" + url + "']")

    return indicator
예제 #13
0
    def test_indicator_to_vast_query(self):
        ## test IP
        ip = "6.6.6.6"
        expected_vast_query = f"{ip}"
        ioc = Indicator(pattern_type="stix",
                        pattern=f"[ipv4-addr:value = '{ip}']")
        self.assertEqual(expected_vast_query, indicator_to_vast_query(ioc))

        ## test URL
        url = "example.com/foo/bar?query=123"
        expected_vast_query = f'"{url}" == net.uri'
        ioc = Indicator(pattern_type="stix", pattern=f"[url:value = '{url}']")
        self.assertEqual(expected_vast_query, indicator_to_vast_query(ioc))

        ## test domain
        domain = "example.com"
        expected_vast_query = f'"{domain}" == net.domain || "{domain}" == net.hostname'
        ioc = Indicator(pattern_type="stix",
                        pattern=f"[domain-name:value = '{domain}']")
        self.assertEqual(expected_vast_query, indicator_to_vast_query(ioc))
예제 #14
0
    def test_indicator_to_vast_query(self):
        ## test IP
        expected_vast_query = f"{self.ioc_value}"
        self.assertEqual(expected_vast_query,
                         indicator_to_vast_query(self.indicator))

        ## test URL
        url = "example.com/foo/bar?query=123"
        expected_vast_query = f'"{url}" in net.uri'
        other_ioc = Indicator(pattern_type="stix",
                              pattern=f"[url:value = '{url}']")
        self.assertEqual(expected_vast_query,
                         indicator_to_vast_query(other_ioc))

        ## test domain
        domain = "example.com"
        expected_vast_query = f'"{domain}" == net.domain || "{domain}" == net.hostname'
        other_ioc = Indicator(pattern_type="stix",
                              pattern=f"[domain-name:value = '{domain}']")
        self.assertEqual(expected_vast_query,
                         indicator_to_vast_query(other_ioc))
예제 #15
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
예제 #16
0
 def _create_or_update_indicator(self, indicator: Indicator):
     """
     Creates or updates a STIX-2 Indicator in OpenCTI
     @param indicator The STIX-2 Indicator
     """
     ioc_dct = json.loads(indicator.serialize())
     ioc_dct["name"] = ioc_dct.get("name", indicator.id)  #  default to UUID
     ioc_dct["stix_id"] = indicator.id
     del ioc_dct["id"]
     obs_type = ioc_dct.get("x_opencti_main_observable_type", "Unknown")
     ioc_dct["x_opencti_main_observable_type"] = obs_type
     resp = self.opencti_helper.api.indicator.create(**ioc_dct)
     self.opencti_helper.log_info(f"Created or added to indicator: {resp}")
예제 #17
0
 def setUp(self):
     self.ts = datetime.now(timezone.utc).astimezone()
     self.indicator_id = "indicator--46b3f973-5c03-41fc-9efe-49598a267a35"
     self.operation = Operation.REMOVE
     self.ioc_value = "6.6.6.6"
     self.pattern = f"[ipv4-addr:value = '{self.ioc_value}']"
     self.indicator = Indicator(
         pattern_type="stix",
         pattern=self.pattern,
         created=self.ts,
         id=self.indicator_id,
     )
     self.valid_query_result = f'{{"timestamp": "{self.ts}", "flow_id": 1840147514011873, "pcap_cnt": 626, "src_ip": "{self.ioc_value}", "src_port": 1193, "dest_ip": "65.54.95.64", "dest_port": 80, "proto": "TCP", "event_type": "http", "community_id": "1:AzSEWwmsqEKUX5qrReAHI3Rpizg=", "http": {{"hostname": "download.windowsupdate.com", "url": "/v9/windowsupdate/a/selfupdate/WSUS3/x86/Other/wsus3setup.cab?0911180916", "http_port": null, "http_user_agent": "Windows-Update-Agent", "http_content_type": "application/octet-stream", "http_method": "HEAD", "http_refer": null, "protocol": "HTTP/1.1", "status": 200, "redirect": null, "length": 0}}, "tx_id": 0}}'
     self.valid_matcher_result = f'{{"ts": "{self.ts}", "data_id": 8, "indicator_id": 5, "matcher": "threatbus-syeocdkfcy", "value": "{self.ioc_value}", "reference": "threatbus__{self.indicator_id}"}}'
예제 #18
0
 def setUp(self):
     self.ts = datetime.now(timezone.utc).astimezone()
     self.indicator_id = "indicator--46b3f973-5c03-41fc-9efe-49598a267a35"
     self.operation = Operation.REMOVE
     self.ioc_value = "evil.com"
     self.pattern = f"[domain-name:value = '{self.ioc_value}']"
     self.indicator = Indicator(
         pattern_type="stix",
         pattern=self.pattern,
         created=self.ts,
         id=self.indicator_id,
     )
     self.valid_query_result = f'{{"timestamp": "{self.ts}", "flow_id": 1840147514011873, "pcap_cnt": 626, "src_ip": "{self.ioc_value}", "src_port": 1193, "dest_ip": "65.54.95.64", "dest_port": 80, "proto": "TCP", "event_type": "http", "community_id": "1:AzSEWwmsqEKUX5qrReAHI3Rpizg=", "http": {{"hostname": "download.windowsupdate.com", "url": "/v9/windowsupdate/a/selfupdate/WSUS3/x86/Other/wsus3setup.cab?0911180916", "http_port": null, "http_user_agent": "Windows-Update-Agent", "http_content_type": "application/octet-stream", "http_method": "HEAD", "http_refer": null, "protocol": "HTTP/1.1", "status": 200, "redirect": null, "length": 0}}, "tx_id": 0}}'
     self.valid_matcher_result = f'{{"indicator": {{"value": "{self.ioc_value}", "context": "\\"threatbus__{self.indicator_id}\\""}}, "type": "zeek.dns", "event": {{"ts": "{self.ts}", "uid": "CGG3VBvnp9JKfVP56", "id.orig_h": "172.19.0.2", "id.orig_p": 37241, "id.resp_h": "1.1.1.1", "id.resp_p": 53, "proto": "udp", "trans_id": 53396, "rtt": "18.42ms", "query": "reddit.com", "qclass": 1, "qclass_name": "C_INTERNET", "qtype": 1, "qtype_name": "A", "rcode": 0, "rcode_name": "NOERROR", "AA": false, "TC": false, "RD": true, "RA": true, "Z": 2, "answers": ["151.101.193.140", "151.101.65.140", "151.101.1.140", "151.101.129.140"], "TTLs": ["2.47m", "2.47m", "2.47m", "2.47m"], "rejected": false}} }}'
예제 #19
0
def outputstix2(results, config):
    indicators = []
    if results is None:
        return
    if config.debug:
        print("Creating STIX2 indicators", file=sys.stderr)
    for result in results:
        # Indicator setup based on https://oasis-open.github.io/cti-documentation/examples/indicator-for-malicious-url
        description = '|'.join(
            result.get('threat_types', []) + result.get('last_seen_as', []) +
            result.get('malware_family', []))
        if result['type'] == 'url':
            indicator = Indicator(valid_from=result.get(
                'last_seen', result['last_published']),
                                  labels="malicious-activity",
                                  description=description,
                                  pattern="[url:value = '%s']" % result["key"],
                                  pattern_type="stix")
        elif result['type'] == 'domain':
            indicator = Indicator(
                valid_from=result.get('last_seen', result['last_published']),
                labels="malicious-activity",
                description=description,
                pattern="[domain-name:value = '%s']" % result["key"],
                pattern_type="stix")
        elif result['type'] == 'ip':
            indicator = Indicator(
                valid_from=result.get('last_seen', result['last_published']),
                labels="malicious-activity",
                description=description,
                pattern="[ipv4-addr:value = '%s']" % result["key"],
                pattern_type="stix")
        indicators.append(indicator)
    if config.debug:
        print("Creating STIX2 bundle", file=sys.stderr)
    bundle = Bundle(indicators)  # This takes WAY too long, needs measurement
    return bundle
예제 #20
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}")
예제 #21
0
 def setUp(self):
     self.observations = [
         {
             "type": "identity",
         },
         {"type": "observed-data", "some-prop": "value"},
         {
             "type": "observed-data",
             "some-prop": "value",
             "last_observed": "2021-05-04T15:15:58.919Z",
         },
     ]
     self.indicator = Indicator(
         pattern="[ipv4-addr:value = '6.6.6.6']", pattern_type="stix"
     )
예제 #22
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),
    )
예제 #23
0
def writeStix(shadyUrl, score):

    # a mettre dans ta callback
    indicator = Indicator(
        name="Malicious site (phishing)",
        labels=["malicious-activity"],
        pattern="[url:value = \'" + shadyUrl + "\']",
        created="{}".format(datetime.datetime.now().date()),
        valid_from="{}".format(datetime.datetime.now().date()),
        description=
        "Possible malicious site detected by LID-TP1 with a score of " +
        str(score) + ", shady url : " + shadyUrl)
    mem.add(indicator)
    mem.save_to_file(
        "./database/{}.json".format(datetime.datetime.now().date())
    )  # end of the function, if the site is a phishing site (score > 0) -> write in STIXv2.0 file
예제 #24
0
def rel_fs_store():
    cam = Campaign(id=CAMPAIGN_ID, **CAMPAIGN_KWARGS)
    idy = Identity(id=IDENTITY_ID, **IDENTITY_KWARGS)
    ind = Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS)
    mal = Malware(id=MALWARE_ID, **MALWARE_KWARGS)
    rel1 = Relationship(ind, 'indicates', mal, id=RELATIONSHIP_IDS[0])
    rel2 = Relationship(mal, 'targets', idy, id=RELATIONSHIP_IDS[1])
    rel3 = Relationship(cam, 'uses', mal, id=RELATIONSHIP_IDS[2])
    stix_objs = [cam, idy, ind, mal, rel1, rel2, rel3]
    fs = FileSystemStore(FS_PATH)
    for o in stix_objs:
        fs.add(o)
    yield fs

    for o in stix_objs:
        os.remove(os.path.join(FS_PATH, o.type, o.id + '.json'))
예제 #25
0
 def setUp(self):
     # self.timestamp = datetime.now(timezone.utc).astimezone()
     self.raw_ts = 1579104545
     self.timestamp = datetime.fromtimestamp(self.raw_ts).astimezone(
         timezone.utc)
     self.ioc_id = "indicator--42d31a5b-2da0-4bdd-9823-1723a98fc2fb"
     self.ioc_value = "example.com"
     self.ioc = Indicator(
         id=self.ioc_id,
         created=self.timestamp,
         pattern_type="stix",
         pattern=f"[domain-name:value = '{self.ioc_value}']",
     )
     self.ep = broker.Endpoint()
     self.ep.peer(self.host, self.port)
     self.subscribe_callback.reset_mock()
     self.unsubscribe_callback.reset_mock()
예제 #26
0
def newioc_view(request):
    #if request.method == 'POST':
    form = IndicatorForm(request.POST)

    if form.is_valid():
        name = form.cleaned_data['name']
        labels = form.cleaned_data['labels']
        pattern = form.cleaned_data['pattern']
        indicator = Indicator(name=name, labels=labels, pattern=pattern)
        print(indicator)

        #saving the indicator to database
        return redirect('/dashboard')

    context = {'form': form}

    return render(request, 'newioc.html', context)
예제 #27
0
 def _ingest_indicator(self, indicator: Indicator):
     """
     Ingests a STIX-2 Indicator into OpenCTI. Does nothing in case the
     indicator already exists.
     @param indicator The STIX-2 Indicator object to ingest
     """
     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
     ioc_dct = json.loads(indicator.serialize())
     ioc_dct["name"] = ioc_dct.get("name", indicator.id)  #  default to UUID
     ioc_dct["stix_id"] = indicator.id
     del ioc_dct["id"]
     obs_type = ioc_dct.get("x_opencti_main_observable_type", "Unknown")
     ioc_dct["x_opencti_main_observable_type"] = obs_type
     resp = self.opencti_helper.api.indicator.create(**ioc_dct)
     self.opencti_helper.log_info(f"Created or added to indicator: {resp}")
예제 #28
0
 def _map_to_threatbus(
     self, data: dict, opencti_action: str
 ) -> Union[Indicator, None]:
     """
     Inspects the given OpenCTI data point and either returns a valid STIX-2
     Indicator or None.
     @param data A dict object with OpenCTI SSE data
     @param opencti_action A string indicating what happened to this item
         (either `create`, `update` or `delete`)
     @return a STIX-2 Indicator or None
     """
     opencti_id: str = data.get("x_opencti_id", None)
     if not opencti_id:
         self.opencti_helper.log_error(
             "Cannot process data without 'x_opencti_id' field"
         )
         return
     indicator: dict = self.opencti_helper.api.indicator.read(id=opencti_id)
     if not indicator:
         # we are only interested in indicators at this time
         return
     detection_enabled: bool = indicator.get("x_opencti_detection", False)
     if not detection_enabled and self.forward_all_iocs is not True:
         # only propagate indicators that are toggled for detection or the
         # user enabled forwarding of all indicators regardless of the toggle
         return
     # overwrite custom OpenCTI ID
     indicator["id"] = indicator.get("standard_id")
     if opencti_action == "update":
         indicator[
             ThreatBusSTIX2Constants.X_THREATBUS_UPDATE.value
         ] = Operation.EDIT.value
     if opencti_action == "delete":
         indicator[
             ThreatBusSTIX2Constants.X_THREATBUS_UPDATE.value
         ] = Operation.REMOVE.value
     return Indicator(**indicator, allow_custom=True)
예제 #29
0
    def setUp(self):
        self.created = datetime.now().astimezone()
        self.indicator_id = "indicator--df0f9a0e-c3b6-4f53-b0cf-5e9c454ee0cc"
        self.pattern = "[ipv4-addr:value = '6.6.6.6']"
        self.pattern_type = "stix2"
        self.operation = Operation.REMOVE
        self.indicator = Indicator(
            id=self.indicator_id,
            pattern=self.pattern,
            pattern_type=self.pattern_type,
            created=self.created,
            valid_from=self.created,
            modified=self.created,
        )

        self.sighting_source = "VAST"
        self.sighting_id = "sighting--df0f9a0e-c3b6-4f53-b0cf-5e9c454ee0cc"
        self.sighting_context = {
            "ts": "2017-03-03T23:56:09.652643840",
            "uid": "CMeLkt11aTqwgN4FI9",
            "id.orig_h": "172.31.130.19",
            "id.orig_p": 43872,
            "id.resp_h": "172.31.129.17",
            "id.resp_p": 20004,
            "proto": "tcp",
            "service": None,
            "duration": 0.025249,
            "orig_bytes": 311,
            "resp_bytes": 999,
            "conn_state": "SF",
            "local_orig": None,
            "local_resp": None,
            "missed_bytes": 0,
            "history": "ShADadFf",
            "orig_pkts": 9,
            "orig_ip_bytes": 787,
            "resp_pkts": 7,
            "resp_ip_bytes": 1371,
            "tunnel_parents": [],
            "alert": {
                "signature": "VAST-RETRO Generic IoC match for: 172.31.129.17",
                "category": "Potentially Bad Traffic",
                "action": "allowed",
            },
            "event_type": "alert",
            "_extra": {
                "vast-ioc": "172.31.129.17"
            },
        }
        self.sighting = Sighting(
            id=self.sighting_id,
            created=self.created,
            modified=self.created,
            sighting_of_ref=self.indicator_id,
            custom_properties={
                ThreatBusSTIX2Constants.X_THREATBUS_SIGHTING_CONTEXT.value:
                self.sighting_context,
                ThreatBusSTIX2Constants.X_THREATBUS_INDICATOR.value:
                self.indicator,
                ThreatBusSTIX2Constants.X_THREATBUS_SOURCE.value:
                self.sighting_source,
            },
        )

        self.snapshot_id = "SNAPSHOT_UUID"
        self.snapshot = timedelta(days=42, hours=23, minutes=13, seconds=37)
        self.snapshot_request = SnapshotRequest(MessageType.SIGHTING,
                                                self.snapshot_id,
                                                self.snapshot)

        self.snapshot_envelope_indicator = SnapshotEnvelope(
            MessageType.INDICATOR, self.snapshot_id, self.indicator)
        self.snapshot_envelope_sighting = SnapshotEnvelope(
            MessageType.SIGHTING, self.snapshot_id, self.sighting)
예제 #30
0
    def process_attribute(
        self,
        author,
        event_elements,
        event_markings,
        attribute_external_references,
        attribute,
    ):
        try:
            resolved_attributes = self.resolve_type(
                attribute["type"], attribute["value"]
            )
            if resolved_attributes is None:
                return None

            for resolved_attribute in resolved_attributes:
                ### Pre-process
                # Elements
                attribute_elements = self.prepare_elements(attribute["Galaxy"], author)
                # Markings & Tags
                attribute_tags = []
                if "Tag" in attribute:
                    attribute_markings = self.resolve_markings(
                        attribute["Tag"], with_default=False
                    )
                    attribute_tags = self.resolve_tags(attribute["Tag"])
                    if len(attribute_markings) == 0:
                        attribute_markings = event_markings
                else:
                    attribute_markings = event_markings

                ### Create the indicator
                observable_type = resolved_attribute["type"]
                observable_value = resolved_attribute["value"]
                name = resolved_attribute["value"]
                pattern_type = "stix"
                # observable type is yara for instance
                if observable_type in PATTERNTYPES:
                    pattern_type = observable_type
                    observable_type = "Unknown"
                    genuine_pattern = (
                        "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']"
                    )
                    pattern = observable_value
                    name = (
                        attribute["comment"]
                        if len(attribute["comment"]) > 0
                        else observable_type
                    )
                # observable type is not in stix 2
                elif observable_type not in OPENCTISTIX2:
                    return None
                # observable type is in stix
                else:
                    if "transform" in OPENCTISTIX2[observable_type]:
                        if (
                            OPENCTISTIX2[observable_type]["transform"]["operation"]
                            == "remove_string"
                        ):
                            observable_value = observable_value.replace(
                                OPENCTISTIX2[observable_type]["transform"]["value"], ""
                            )
                    lhs = ObjectPath(
                        OPENCTISTIX2[observable_type]["type"],
                        OPENCTISTIX2[observable_type]["path"],
                    )
                    genuine_pattern = str(
                        ObservationExpression(
                            EqualityComparisonExpression(lhs, observable_value)
                        )
                    )
                    pattern = genuine_pattern

                indicator = Indicator(
                    name=name,
                    description=attribute["comment"],
                    pattern=genuine_pattern,
                    valid_from=datetime.utcfromtimestamp(
                        int(attribute["timestamp"])
                    ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                    labels=["malicious-activity"],
                    created_by_ref=author,
                    object_marking_refs=attribute_markings,
                    external_references=attribute_external_references,
                    custom_properties={
                        "x_opencti_indicator_pattern": pattern,
                        "x_opencti_observable_type": observable_type,
                        "x_opencti_observable_value": observable_value,
                        "x_opencti_pattern_type": pattern_type,
                        "x_opencti_tags": attribute_tags,
                    },
                )

                ### Create the relationships
                relationships = []
                # Event threats
                for threat in (
                    event_elements["intrusion_sets"]
                    + event_elements["malwares"]
                    + event_elements["tools"]
                ):
                    relationships.append(
                        Relationship(
                            relationship_type="indicates",
                            created_by_ref=author,
                            source_ref=indicator.id,
                            target_ref=threat.id,
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                            },
                        )
                    )
                # Attribute threats
                for threat in (
                    attribute_elements["intrusion_sets"]
                    + attribute_elements["malwares"]
                    + attribute_elements["tools"]
                ):
                    relationships.append(
                        Relationship(
                            relationship_type="indicates",
                            created_by_ref=author,
                            source_ref=indicator.id,
                            target_ref=threat.id,
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                            },
                        )
                    )
                # Event Attack Patterns
                for attack_pattern in event_elements["attack_patterns"]:
                    if len(event_elements["malwares"]) > 0:
                        threats = event_elements["malwares"]
                    elif len(event_elements["intrusion_sets"]) > 0:
                        threats = event_elements["intrusion_sets"]
                    else:
                        threats = []
                    for threat in threats:
                        relationship_uses = Relationship(
                            relationship_type="uses",
                            created_by_ref=author,
                            source_ref=threat.id,
                            target_ref=attack_pattern.id,
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                                "x_opencti_ignore_dates": True,
                            },
                        )
                        relationships.append(relationship_uses)
                        relationship_indicates = Relationship(
                            relationship_type="indicates",
                            created_by_ref=author,
                            source_ref=indicator.id,
                            target_ref="malware--fa42a846-8d90-4e51-bc29-71d5b4802168",  # Fake
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                                "x_opencti_source_ref": indicator.id,
                                "x_opencti_target_ref": relationship_uses.id,
                            },
                        )
                        relationships.append(relationship_indicates)
                # Attribute Attack Patterns
                for attack_pattern in attribute_elements["attack_patterns"]:
                    if len(attribute_elements["malwares"]) > 0:
                        threats = attribute_elements["malwares"]
                    elif len(attribute_elements["intrusion_sets"]) > 0:
                        threats = attribute_elements["intrusion_sets"]
                    else:
                        threats = []
                    for threat in threats:
                        relationship_uses = Relationship(
                            relationship_type="uses",
                            created_by_ref=author,
                            source_ref=threat.id,
                            target_ref=attack_pattern.id,
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                                "x_opencti_ignore_dates": True,
                            },
                        )
                        relationships.append(relationship_uses)
                        relationship_indicates = Relationship(
                            relationship_type="indicates",
                            created_by_ref=author,
                            source_ref=indicator.id,
                            target_ref="malware--fa42a846-8d90-4e51-bc29-71d5b4802168",  # Fake
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                                "x_opencti_source_ref": indicator.id,
                                "x_opencti_target_ref": relationship_uses.id,
                                "x_opencti_ignore_dates": True,
                            },
                        )
                        relationships.append(relationship_indicates)

                return {
                    "indicator": indicator,
                    "relationships": relationships,
                    "attribute_elements": attribute_elements,
                    "markings": attribute_markings,
                }
        except:
            return None