Infoblox BloxOne Threat Defense Event Collector
BloxOne Threat Defense is a hybrid cybersecurity solution that leverages DNS as the first line of defense to detect and block cyber threats.
Data Enrichment & Threat Intelligence · Infoblox Threat Defense with DDI
Details
| ID | Infoblox BloxOne Threat Defense Event Collector |
|---|---|
| Provider | Infoblox |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 6.10.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
BloxOne Threat Defense is a hybrid cybersecurity solution that leverages DNS as the first line of defense to detect and block cyber threats.
Configure Infoblox BloxOne Threat Defense Event Collector in Cortex
| Parameter | Description | Required |
|---|---|---|
| Service API Key | True | |
| First fetch time interval | False | |
| Max events per fetch | The maximum amount of events to retrieve for each event type (up to 10000 events). For more information about event types see the help section. | False |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
bloxone-td-event-collector-get-events
Gets events. This command is for debugging purposes.
Base Command
bloxone-td-event-collector-get-events
Input
| Argument Name | Description | Required |
|---|---|---|
| should_push_events | Set this argument to True in order to create events, otherwise the command will only display them. Possible values are: True, False. Default is False. | Required |
| from | Timestamp indicating when to start fetching events. | Required |
| to | Timestamp indicating when to stop fetching events. | Required |
| limit | Maximum number of events to fetch. Default is 1000. | Required |
| offset | offset of the events. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| TestGetEvents | Unknown | The event data. |
Configuration parameters
credentials— (required)first_fetch— First fetch time intervalmax_fetch— Max events per fetchinsecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (1)
-
bloxone-td-event-collector-get-eventsGets events. This command is for debugging purposes.
import pytest from freezegun import freeze_time from InfobloxBloxOneThreatDefenseEventCollector import * class TestBloxOneTDEventCollectorClient: def test_fetch_url(self, requests_mock): request_mock_get = requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": []}) BloxOneTDEventCollectorClient("").fetch_events(0, 0) assert request_mock_get.called_once def test_event_time_mapping(self, requests_mock): event_time = "the event time" requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": event_time}]}) event = BloxOneTDEventCollectorClient("").fetch_events(0, 0)[0] assert event["event_time"] == event["_time"] == event_time class TestFetchEventsCommand: data_test_fetch_events_command = [ ({"from_ts": 1680307140}, {"from_ts": 1680307200}, 3), ({"from_ts": 1680307140}, {"from_ts": 1680307140, "offset": 5}, 5), ({"from_ts": 1680307140, "offset": 5}, {"from_ts": 1680307140, "offset": 10}, 5), ({"from_ts": 1680307140, "offset": 10}, {"from_ts": 1680307200}, 2), ] @freeze_time("2023-04-01T00:00:00.000Z") @pytest.mark.parametrize("last_run, expected_next_run, events_length", data_test_fetch_events_command) def test_fetch_events_command(self, last_run, expected_next_run, events_length, requests_mock, mocker): requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": "event_time"}] * events_length}) set_last_run = mocker.patch.object(demisto, "setLastRun") send_events_to_xsiam_mock = mocker.patch("InfobloxBloxOneThreatDefenseEventCollector.send_events_to_xsiam") fetch_events_command(BloxOneTDEventCollectorClient(""), {"max_fetch": 5}, last_run) set_last_run.assert_called_once_with(expected_next_run) send_events_to_xsiam_mock.assert_called_once_with( [{"_time": "event_time", "event_time": "event_time"}] * events_length, "Infoblox BloxOne", "Threat Defense" ) @freeze_time("2023-04-01T00:00:00.000Z") def test_fetch_events_first_fetch(self, requests_mock, mocker): get_events_api_call = requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": "event_time"}]}) send_events_to_xsiam_mock = mocker.patch("InfobloxBloxOneThreatDefenseEventCollector.send_events_to_xsiam") fetch_events_command(BloxOneTDEventCollectorClient(""), {"max_fetch": 5, "first_fetch": "5 min"}, {}) send_events_to_xsiam_mock.assert_called_once_with( [{"_time": "event_time", "event_time": "event_time"}], "Infoblox BloxOne", "Threat Defense" ) assert get_events_api_call.last_request.qs["t0"][0] == "1680306900" def test_fetch_events_with_invalid_first_fetch(self, requests_mock, mocker): with pytest.raises(DemistoException): fetch_events_command( BloxOneTDEventCollectorClient(""), {"first_fetch": "this is a test and it should raise an error"}, {} ) class TestGetEventsCommand: def test_get_events_command_without_send_to_xsiam(self, requests_mock, mocker): send_events_to_xsiam_mock = mocker.patch("InfobloxBloxOneThreatDefenseEventCollector.send_events_to_xsiam") get_events_api_call = requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": "event_time"}]}) get_events_command(BloxOneTDEventCollectorClient(""), {"from": 1, "to": 2}) assert get_events_api_call.called_once assert get_events_api_call.last_request.qs["t0"][0] == "1" assert get_events_api_call.last_request.qs["t1"][0] == "2" assert send_events_to_xsiam_mock.call_count == 0 def test_get_events_command_and_send_to_xsiam(self, requests_mock, mocker): send_events_to_xsiam_mock = mocker.patch("InfobloxBloxOneThreatDefenseEventCollector.send_events_to_xsiam") get_events_api_call = requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": "event_time"}]}) get_events_command(BloxOneTDEventCollectorClient(""), {"from": 1, "to": 2, "should_push_events": "yes"}) assert get_events_api_call.called_once assert get_events_api_call.last_request.qs["t0"][0] == "1" assert get_events_api_call.last_request.qs["t1"][0] == "2" send_events_to_xsiam_mock.assert_called_once_with( [{"_time": "event_time", "event_time": "event_time"}], "Infoblox BloxOne", "Threat Defense" ) class TestParseFromTsFromParams: data_test_parse_from_ts_from_params_with_valid_params = [ (None, 1680220800), ("5 min", 1680306900), ] @freeze_time("2023-04-01T00:00:00.000Z") @pytest.mark.parametrize("first_fetch, expected_from_ts", data_test_parse_from_ts_from_params_with_valid_params) def test_parse_from_ts_from_params_with_valid_params(self, first_fetch, expected_from_ts): assert parse_from_ts_from_params(first_fetch) == expected_from_ts def test_parse_from_ts_from_params_with_invalid_params(self): with pytest.raises(DemistoException): parse_from_ts_from_params("this is a test and it should raise an error") class TestCommandTestModule: def test_default_flow(self, requests_mock): requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": "event_time"}]}) assert command_test_module(BloxOneTDEventCollectorClient(""), {}) == "ok" def test_valid_first_fetch(self, requests_mock): requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": "event_time"}]}) assert command_test_module(BloxOneTDEventCollectorClient(""), {"first_fetch": "5 min"}) == "ok" def test_invalid_first_fetch(self, requests_mock): requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": "event_time"}]}) with pytest.raises(DemistoException): command_test_module(BloxOneTDEventCollectorClient(""), {"first_fetch": "invalid"}) def test_invalid_creds(self, requests_mock): requests_mock.get("/api/dnsdata/v2/dns_event", status_code=401, json={"i dont": "really care"}) with pytest.raises(DemistoException): command_test_module(BloxOneTDEventCollectorClient(""), {"first_fetch": "invalid"}) def demisto_input_mocker(mocker, command, params={}, args={}): mocker.patch.object(demisto, "command", return_value=command) mocker.patch.object(demisto, "params", return_value=params) mocker.patch.object(demisto, "args", return_value=args) @pytest.fixture() def return_error_mock(mocker): return mocker.patch("InfobloxBloxOneThreatDefenseEventCollector.return_error") @pytest.fixture() def return_results_mock(mocker): return mocker.patch("InfobloxBloxOneThreatDefenseEventCollector.return_results") class TestMain: def test_command_not_implemented(self, mocker, return_error_mock): demisto_input_mocker(mocker, "not_implemented") main() return_error_mock.assert_called_once() assert "command not_implemented is not implemented." in return_error_mock.call_args.args[0] def test_unauthenticated(self, mocker, return_error_mock, requests_mock): demisto_input_mocker(mocker, "test-module") requests_mock.get("/api/dnsdata/v2/dns_event", status_code=401, json={"i dont": "really care"}) main() return_error_mock.assert_called_once() assert return_error_mock.call_args.args[0] == "authentication error please check your API key and try again." def test_test_module_happy_flow(self, mocker, return_results_mock, requests_mock): demisto_input_mocker(mocker, "test-module") requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": []}) main() return_results_mock.assert_called_once_with("ok") def test_fetch_events_happy_flow(self, mocker, requests_mock): demisto_input_mocker(mocker, "fetch-events") requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": "event_time"}]}) send_events_to_xsiam_mock = mocker.patch("InfobloxBloxOneThreatDefenseEventCollector.send_events_to_xsiam") main() send_events_to_xsiam_mock.assert_called_once_with( [{"_time": "event_time", "event_time": "event_time"}], "Infoblox BloxOne", "Threat Defense" ) def test_get_events_and_send_to_server_happy_flow(self, mocker, requests_mock, return_results_mock): demisto_input_mocker( mocker, "bloxone-td-event-collector-get-events", args={"from": "from", "to": "to", "should_push_events": "yes"} ) requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": "event_time"}]}) send_events_to_xsiam_mock = mocker.patch("InfobloxBloxOneThreatDefenseEventCollector.send_events_to_xsiam") main() send_events_to_xsiam_mock.assert_called_once_with( [{"_time": "event_time", "event_time": "event_time"}], "Infoblox BloxOne", "Threat Defense" ) assert return_results_mock.call_args.args[0].outputs == [{"_time": "event_time", "event_time": "event_time"}] assert return_results_mock.call_args.args[0].outputs_prefix == "TestGetEvents" def test_get_events_without_send_to_server_happy_flow(self, mocker, requests_mock, return_results_mock): demisto_input_mocker( mocker, "bloxone-td-event-collector-get-events", args={"from": "from", "to": "to", "should_push_events": "no"} ) requests_mock.get("/api/dnsdata/v2/dns_event", json={"result": [{"event_time": "event_time"}]}) send_events_to_xsiam_mock = mocker.patch("InfobloxBloxOneThreatDefenseEventCollector.send_events_to_xsiam") main() assert send_events_to_xsiam_mock.call_count == 0 assert return_results_mock.call_args.args[0].outputs == [{"_time": "event_time", "event_time": "event_time"}] assert return_results_mock.call_args.args[0].outputs_prefix == "TestGetEvents"