def test_watchlist_update_invalid_object(cbcsdk_mock): """Testing Watchlist.update() raising InvalidObjectError when Watchlist ID is missing.""" watchlist = Watchlist(cbcsdk_mock.api, model_unique_id=None, initial_data=None) with pytest.raises(InvalidObjectError): watchlist.update(nonexistant_key="This is ignored")
def test_watchlist_delete(cbcsdk_mock): """Testing Watchlist.delete().""" id = "watchlistId" cbcsdk_mock.mock_request("GET", f"/threathunter/watchlistmgr/v2/watchlist/{id}", WATCHLIST_GET_SPECIFIC_RESP) cbcsdk_mock.mock_request("DELETE", f"/threathunter/watchlistmgr/v3/orgs/test/watchlists/{id}", None) watchlist = Watchlist(cbcsdk_mock.api, model_unique_id="watchlistId") watchlist.delete()
def test_watchlist_enable_tags(cbcsdk_mock): """Testing Watchlist.enable_tags().""" api = cbcsdk_mock.api id = "watchlistId" cbcsdk_mock.mock_request("GET", f"/threathunter/watchlistmgr/v2/watchlist/{id}", WATCHLIST_GET_SPECIFIC_RESP) watchlist = Watchlist(api, model_unique_id="watchlistId") cbcsdk_mock.mock_request("PUT", f"/threathunter/watchlistmgr/v3/orgs/test/watchlists/{id}/tag", {"tag": True}) watchlist.enable_tags()
def test_disable_alerts(cbcsdk_mock): """Testing Watchlist.disable_alerts().""" api = cbcsdk_mock.api id = "watchlistId" cbcsdk_mock.mock_request("GET", f"/threathunter/watchlistmgr/v2/watchlist/{id}", WATCHLIST_GET_SPECIFIC_RESP) watchlist = Watchlist(api, model_unique_id="watchlistId") cbcsdk_mock.mock_request("DELETE", f"/threathunter/watchlistmgr/v3/orgs/test/watchlists/{id}/alert", None) watchlist.disable_alerts()
def test_watchlist_update_api_error(cbcsdk_mock): """Testing Watchlist.update() raising ApiError when passing in "report_ids" with empty list.""" id = "watchlistId" cbcsdk_mock.mock_request("GET", f"/threathunter/watchlistmgr/v2/watchlist/{id}", WATCHLIST_GET_SPECIFIC_RESP) watchlist = Watchlist(cbcsdk_mock.api, model_unique_id="watchlistId", initial_data=None) cbcsdk_mock.mock_request("PUT", f"/threathunter/watchlistmgr/v3/orgs/test/watchlists/{id}", WATCHLIST_GET_SPECIFIC_RESP) with pytest.raises(ApiError): watchlist.update(report_ids=[])
def test_watchlist_update(cbcsdk_mock): """Testing Watchlist.update().""" id = "watchlistId" cbcsdk_mock.mock_request("GET", f"/threathunter/watchlistmgr/v2/watchlist/{id}", WATCHLIST_GET_SPECIFIC_RESP) watchlist = Watchlist(cbcsdk_mock.api, model_unique_id="watchlistId", initial_data=None) assert "description" in watchlist._info assert "nonexistant_key" not in watchlist._info assert watchlist._info["description"] == "Existing description for the watchlist." cbcsdk_mock.mock_request("PUT", f"/threathunter/watchlistmgr/v3/orgs/test/watchlists/{id}", WATCHLIST_GET_SPECIFIC_RESP) watchlist.update(description="My New Description", nonexistant_key="This Is Ignored") assert watchlist._info["description"] == "My New Description"
def test_watchlist_save(cbcsdk_mock): """Testing Watchlist.save().""" api = cbcsdk_mock.api id = "watchlistId" cbcsdk_mock.mock_request("POST", "/threathunter/watchlistmgr/v3/orgs/test/watchlists", WATCHLIST_GET_SPECIFIC_RESP) watchlist = Watchlist(api, model_unique_id="watchlistId", initial_data=CREATE_WATCHLIST_DATA) watchlist.validate() watchlist.save() # if Watchlist response is missing a required field per enterprise_edr.models.Watchlist, raise InvalidObjectError cbcsdk_mock.mock_request("GET", f"/threathunter/watchlistmgr/v2/watchlist/{id}", WATCHLIST_GET_SPECIFIC_MISSING_FIELDS_RESP) watchlist = api.select(Watchlist, "watchlistId") with pytest.raises(InvalidObjectError): watchlist.validate() with pytest.raises(InvalidObjectError): watchlist.save()
def test_watchlist_init(cbcsdk_mock): """Testing Watchlist.__init__().""" id = "watchlistId" cbcsdk_mock.mock_request("GET", f"/threathunter/watchlistmgr/v2/watchlist/{id}", WATCHLIST_GET_SPECIFIC_RESP) watchlist = Watchlist(cbcsdk_mock.api, model_unique_id="watchlistId", initial_data=None) assert watchlist._model_unique_id == "watchlistId"
def test_watchlist_update_id(cbcsdk_mock): """Testing Watchlist.update().""" id = "watchlistId2" id2 = "watchlistId" cbcsdk_mock.mock_request("GET", f"/threathunter/watchlistmgr/v2/watchlist/{id}", WATCHLIST_GET_SPECIFIC_RESP_2) watchlist = Watchlist(cbcsdk_mock.api, model_unique_id="watchlistId2", initial_data=None) assert "description" in watchlist._info assert "nonexistant_key" not in watchlist._info cbcsdk_mock.mock_request("PATCH", "/threathunter/watchlistmgr/v2/watchlist", WATCHLIST_GET_SPECIFIC_RESP) watchlist.id = id2 result_repr = watchlist.__repr__() assert 'id watchlistId' in result_repr assert '(*)' in result_repr watchlist._update_object()
def test_watchlist_disable_tags_no_id(cbcsdk_mock): """Testing Watchlist.disable_tags() raising InvalidObjectError when ID is missing.""" api = cbcsdk_mock.api watchlist = Watchlist(api, model_unique_id=None) with pytest.raises(InvalidObjectError): watchlist.disable_tags()
def test_watchlist_delete_no_id(cbcsdk_mock): """Testing Watchlist.delete() raising InvalidObjectError when ID is missing.""" watchlist = Watchlist(cbcsdk_mock.api, model_unique_id=None) with pytest.raises(InvalidObjectError): watchlist.delete()
def test_watchlist_classifier_empty(cbcsdk_mock): """Testing Watchlist.classifier_ when "classifier" is not in self._info.""" watchlist = Watchlist(cbcsdk_mock.api) assert "classifier" not in watchlist._info assert watchlist.classifier_ is None
def test_watchlist_classifier(cbcsdk_mock): """Testing Watchlist.classifier_ property.""" watchlist = Watchlist(cbcsdk_mock.api, model_unique_id="watchlistId", initial_data=WATCHLIST_GET_SPECIFIC_RESP) assert watchlist.classifier_ == ("feed_id", "feed_id_associated")
def enterprise_edr(): """ Enterprise EDR operations, using research from TAU. 1. Find Processes with Indicators of Compromise (IOC's) matching Egregor ransomware, then 2. Combine observed Process hashes with TAU research into Reports, finally 3. Add the Reports to a new Watchlist. """ print(f"\n{BOLD}****************************************************\n" " 3. Carbon Black Cloud Enterprise EDR Watchlist API \n" f"****************************************************{UNBOLD}\n") logging.info("Building Egregor ransomware Reports and Watchlist from IOCs") egregor_query = "filemod_count:[10000 TO *] filemod_name:recover-files.txt (modload_name:rundll32.exe "\ "OR modload_name:regsvr32.exe)" print( "Using Enterprise EDR to create Threat Reports and a Watchlist, based on Egregor Ransomware IOCs: " f"\n{egregor_query}\n") # Find Enterprise EDR Processes that match Egregor ransomware behavior egregor_ransomware_processes = enterprise_edr_api.select(Process).where( egregor_query) # Extract the Process hashes process_hashes = set() print("Finding Process hashes that matched Egregor IOC query.\n") for process in egregor_ransomware_processes: process_hashes.add(process.process_md5) process_hashes.add(process.process_sha256) # Create an Enterprise EDR Report with the found Process hashes ransomware_hashes_report = create_eedr_report( title="Egregor Ransomware MD5/SHA256 Hashes", description="Process hashes suggesting Egregor ransomware behavior", severity=10, iocs={ "id": 1, "match_type": "equality", "field": "process_hash", "values": list(process_hashes) }) # Save the Report as a Watchlist Report (vs. a Feed Report) ransomware_hashes_report.save_watchlist() egregor_query = ( "filemod_count:[10000 TO *] filemod_name:recover-files.txt " "(modload_name:rundll32.exe OR modload_name:regsvr32.exe)") # Continuously monitor for any Processes that exhibit Egregor ransomware behavior ransomware_query_report = create_eedr_report( title="Egregor Ransomware Query", description="IOCs suggesting ransomware behavior", severity=10, iocs={ "id": 1, "match_type": "query", "values": [egregor_query] }) # Save the Report as a Watchlist Report (vs. a Feed Report) ransomware_query_report.save_watchlist() print("Creating an Engregor ransomware Watchlist.\n") # Create a new Watchlist to track ransomware Process hashes wldata = { "name": "CBCSDK-Test", "description": "Egregor Ransomware Watchlist", "create_timestamp": time.time(), "last_update_timestamp": time.time(), "id": 1 } ransomware_watchlist = Watchlist(enterprise_edr_api, initial_data=wldata) # Save the new Watchlist ransomware_watchlist.save() # Add the Reports to the Watchlist logging.info(f"Adding Reports to Watchlist {ransomware_watchlist.id}") print( "Adding Egregor ransomware SHA256/MD5 hashes Report and Query Report to Watchlist.\n" ) ransomware_watchlist.update( report_ids=[ransomware_hashes_report.id, ransomware_query_report.id]) return ransomware_watchlist.id