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)
def test_zeek_plugin_message_roundtrip(self): """ Backend agnostic message passing screnario. Sends a single MISP Attribute via ZeroMQ to the threatbus MISP plugin, subscribes via broker to threatbus, and checks if the initially sent message got parsed and forwarded correctly as new Intelligence item. """ misp_json_attribute = """{ "Attribute": { "id": "15", "event_id": "1", "object_id": "0", "object_relation": null, "category": "Network activity", "type": "domain", "value1": "example.com", "value2": "", "to_ids": false, "uuid": "5e1f2787-fcfc-4718-a58a-00b4c0a82f06", "timestamp": "1579104545", "distribution": "5", "sharing_group_id": "0", "comment": "", "deleted": false, "disable_correlation": false, "value": "example.com", "Sighting": [] }, "Event": { "id": "1", "date": "2020-01-15", "info": "adsf", "uuid": "5e1ee79d-25c8-42bd-a386-0291c0a82f06", "published": false, "analysis": "0", "threat_level_id": "1", "org_id": "1", "orgc_id": "1", "distribution": "3", "sharing_group_id": "0", "Orgc": { "id": "1", "uuid": "5e1edc98-3984-4321-9003-018bfb195b64", "name": "ORGNAME" } }, "action": "edit" }""" # emulate a zeek subscriber for intel items result_q = queue.Queue() rec = threading.Thread( target=zeek_receiver.forward, args=(1, result_q, "tenzir/threatbus/intel"), daemon=False, ) rec.start() zmq_sender.send(misp_json_attribute) # wait for threatbus to forward intel zeek_intel = result_q.get(block=True) result_q.task_done() result_q.join() rec.join() self.assertEqual( zeek_intel, [ ( "Tenzir::intel", None, "15", {"indicator": "example.com", "intel_type": "DOMAIN"}, ) ], )
def test_intel_sighting_roundtrip(self): """ Backend-agnostic roundtrip scenario, that starts a Zeek subprocess which activates the threatbus.zeek "app" script. The test sends an IoC with a malicious hostname via Threat Bus, using the ZMQ app plugin. Meanwhile, the Zeek subprocess reads a PCAP trace which contains exactly that malicious hostname from the IoC. If all goes well, Zeek subscribes to Threat Bus successfully, receives the IoC and hence reading the PCAP file results in a sighting. Zeek forwards that sighting to the Threat Bus Zeek plugin, where it is converted to a valid STIX-2 Sighting. The integration test subscribes a ZMQ receiver to the `stix2/sighting` topic and verifies all Zeek communication was handled correctly. I.e., Zeek matched the IoC and reported the correct sighting. """ # Start a ZMQ receiver that subscribes to the `stix2/sighting` topic and # forward exactly 1 item to a result queue result_q = queue.Queue() rec = threading.Thread( target=zmq_receiver.forward, args=(1, ["stix2/sighting"], result_q), daemon=True, ) rec.start() # Spawn a Zeek subprocess that runs the `apps/zeek/threatbus.zeek` # script and reads a prepared PCAP trace that contains a network # connection to `example.com` zeek_process = RunZeek() if not zeek_process: self.fail("Error starting Zeek container.") # Let Zeek start up... time.sleep(1) # Send a new indicator (IoC) via the ZMQ test-util, which will be # forwarded to Zeek because Zeek subscribes to `stix2/indicator` ioc_id = "indicator--42d31a5b-2da0-4bdd-9823-1723a98fc2fb" ioc = Indicator( id=ioc_id, pattern_type="stix", pattern="[domain-name:value = 'example.com']", ) zmq_sender.send("stix2/indicator", ioc.serialize(), port=13372, bind=False) # Wait for Zeek to ingest the IoC into its Intel framework, read the # PCAP trace and report back the sighting raw_msg = result_q.get(timeout=10) sighting = parse(raw_msg, allow_custom=True) result_q.task_done() self.assertIsNotNone(sighting) self.assertEqual(sighting.sighting_of_ref, ioc_id) self.assertTrue(ThreatBusSTIX2Constants.X_THREATBUS_SIGHTING_CONTEXT. value in sighting) self.assertEqual(sighting.x_threatbus_sighting_context, {"noisy": False}) rec.join() result_q.join() zeek_process.kill() self.assertTrue(StopZeek())