SafeBreach v2 Deprecated

Deprecated. No available replacement.

Data Enrichment & Threat Intelligence · SafeBreach - Breach and Attack Simulation platform · Feed

Details

IDSafeBreach v2
ProviderSafeBreach
CategoryData Enrichment & Threat Intelligence
From Version5.5.0
Docker Imagedemisto/python3:3.10.12.63474
Supported ModulesAgentix XSIAM

README

Deprecated. No available replacement.

Configure SafeBreach v2 (Deprecated) for Cortex XSOAR Integration

  1. Open the Navigation bar → … → CLI Console
  2. Type config accounts to find out the account id
  3. Use the id as the accountId parameter in Cortex XSOAR configuration
  4. Type config apikeys to list existing API keys \
    OR \
    Add a new one by typing: **config apikeys add –name **
  5. Use the generated API token as apiKey parameter in Cortex XSOAR configuration
  6. Use your SafeBreach Management URL as the url parameter in Cortex XSOAR configuration

Configure SafeBreach v2 (Deprecated) on Cortex XSOAR

  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for SafeBreach v2 (Deprecated).
  3. Click Add instance to create and configure a new integration instance.

    Parameter Description Required
    SafeBreach Managment URL For example, https://yourorg.safebreach.com True
    Account ID Obtained with “config accounts” SafeBreach command True
    API Key Generated with “config apikeys add” SafeBreach command True
    Insight Category    
    Insight Data Type    
    Non Behavioral Indicator Reputation Non-Behavioral Indicator from this integration instance will be marked with this reputation  
    Behavioral Reputation Behavioral Indicator from this integration instance will be marked with this reputation  
    Indicators Limit The maximum number of indicators to generate. The default is 1000.  
    Fetch indicators    
    Source Reliability Reliability of the source providing the intelligence data True
    Traffic Light Protocol Color The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed  
         
    Feed Fetch Interval    
    Bypass exclusion list When selected, the exclusion list is ignored for indicators from this feed. This means that if an indicator from this feed is on the exclusion list, the indicator might still be added to the system.  
         
    Trust any certificate (not secure)    
    Use system proxy settings    
    Indicator Reputation Indicators from this integration instance will be marked with this reputation  
    Tags Supports CSV values.  
  4. Click Test to validate the URLs, token, and connection.

Commands

You can execute these commands from the Cortex XSOAR 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.

Configuration parameters

  • url — SafeBreach Managment URL (required)
  • accountId — Account ID (required)
  • apiKey — API Key (required)
  • insightCategory — Insight Category
  • insightDataType — Insight Data Type
  • nonBehavioralReputation — Non Behavioral Indicator Reputation
  • behavioralReputation — Behavioral Reputation
  • indicatorLimit — Indicators Limit
  • feed — Fetch indicators
  • feedReliability — Source Reliability (required)
  • tlp_color — Traffic Light Protocol Color
  • feedExpirationPolicy
  • feedFetchInterval — Feed Fetch Interval
  • feedBypassExclusionList — Bypass exclusion list
  • feedExpirationInterval
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • feedReputation — Indicator Reputation
  • feedTags — Tags

Commands (7)

  • safebreach-get-indicators Deprecated

    Fetches SafeBreach Insights from which indicators are extracted, creating new indicators or updating existing indicators.

  • safebreach-get-insights Deprecated

    Gets SafeBreach Insights for all security control categories.

  • safebreach-get-remediation-data Deprecated

    Gets remediation data for a specific SafeBreach Insight.

  • safebreach-get-simulation Deprecated

    Get SafeBreach simulation

  • safebreach-get-test-status Deprecated

    Gets the status of a SafeBreach test for tracking progress of a run.

  • safebreach-rerun-insight Deprecated

    Reruns a specific SafeBreach Insight related simulations in your environment.

  • safebreach-rerun-simulation Deprecated

    Reruns a specific SafeBreach simulation in your environment.

import json
import pytest
import demistomock as demisto
from CommonServerPython import *
from SafeBreach_v2 import get_insights_command, get_remediation_data_command, rerun_simulation_command, \
    get_safebreach_simulation_command, get_indicators_command, insight_rerun_command, Client

MOCK_URL = "https://safebreach-fake-api.com"
MOCK_ACCOUNT_ID = '1234567'
MOCK_API_KEY = 'a1b2c3d4e5'
INSIGHT_ID = '9'
SIMULATION_ID = '8fae303defd52a7745044ce2ba54a391'

client = Client(
    base_url=MOCK_URL,
    api_key=MOCK_API_KEY,
    account_id=MOCK_ACCOUNT_ID,
    proxies=handle_proxy(),
    verify=False,
    tags=['tag1', 'tag2'],
)


def load_test_data(json_path):
    with open(json_path) as f:
        return json.load(f)


REMEDATION_DATA_LIST = load_test_data('./test_data/remediation_data.json')
GET_INSIGHTS_LIST = load_test_data('./test_data/insights.json')
SIMULATION = load_test_data('./test_data/simulation.json')
NODES = load_test_data('./test_data/nodes.json')
REMEDATION_DATA_LIST_UNVAILD_STRING = load_test_data('./test_data/remediation_data_with_unvaild_string.json')


def test_get_insights(requests_mock, mocker):
    requests_mock.get(f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/insights?type=actionBased',
                      json=GET_INSIGHTS_LIST)
    requests_mock.get(
        f'{MOCK_URL}/api/config/v1/accounts/{MOCK_ACCOUNT_ID}/nodes?details=true&deleted=true&assets=true',
        json=NODES)
    mocker.patch.object(demisto, 'args', return_value={'insightIds': [9]})
    mocker.patch.object(demisto, 'results')
    mocker.patch.object(demisto, 'params', return_value={'url': MOCK_URL})

    res = get_insights_command(client, demisto.args(), True)
    assert demisto.results.call_count == 1
    outputs = demisto.results.call_args[0][0]
    context = outputs['EntryContext']
    fake_safebreach_context = {
        "Id": 9,
        "Category": 'Endpoint',
        "Severity": "High"
    }

    assert fake_safebreach_context['Id'] == context['SafeBreach.Insight(val.Id == obj.Id)'][0]['Id']
    assert fake_safebreach_context['Category'] == context['SafeBreach.Insight(val.Id == obj.Id)'][0]['Category']
    assert fake_safebreach_context['Severity'] == context['SafeBreach.Insight(val.Id == obj.Id)'][0]['Severity']
    assert len(res) == 1


def test_get_remediation_data(requests_mock, mocker):
    mocker.patch.object(demisto, 'args', return_value={'insightId': INSIGHT_ID})
    mocker.patch.object(demisto, 'results')
    mocker.patch.object(demisto, 'params', return_value={'url': MOCK_URL})

    requests_mock.get(f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/insights?type=actionBased',
                      json=GET_INSIGHTS_LIST)
    requests_mock.get(f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/insights/{INSIGHT_ID}/remediation',
                      json=REMEDATION_DATA_LIST)
    requests_mock.get(
        f'{MOCK_URL}/api/config/v1/accounts/{MOCK_ACCOUNT_ID}/nodes?details=true&deleted=true&assets=true',
        json=NODES)
    get_remediation_data_command(client, demisto.args(), True)
    assert demisto.results.call_count == 1
    outputs = demisto.results.call_args[0][0]
    context = outputs['EntryContext']
    sha256_to_check = '109c702578b261d0eda01506625423f5a2b8cc107b0d8dfad84d39fb02bfa5cb'
    assert context['SafeBreach.Insight(val.Id == obj.Id)'][0]['Id'] == INSIGHT_ID
    assert context['SafeBreach.Insight(val.Id == obj.Id)'][0]['RawRemediationData'][0]['type'] == 'SHA256'
    assert context['SafeBreach.Insight(val.Id == obj.Id)'][0]['RawRemediationData'][0]['value'] == sha256_to_check
    assert context['File(val.SHA256 == obj.SHA256)'][0]['SHA256'] == sha256_to_check
    assert context['DBotScore(val.Indicator == obj.Indicator)'][0]['Indicator'] == sha256_to_check


def test_rerun_insight(requests_mock, mocker):
    mocker.patch.object(demisto, 'args', return_value={'insightIds': '9'})
    mocker.patch.object(demisto, 'results')

    response = {
        "data": {
            "name": "Insight (XSOAR) - Test",
            "moveIds": [
                1,
                2,
                3,
                4,
            ],
            "nodeIds": ['nodeID1', 'nodeID2'],
            "draft": False,
            "ranBy": -1,
            "ranFrom": "UI",
            "isRerun": True,
            "assetIds": [],
            "moveSetIds": [],
            "force": True,
            "queueId": 107,
            "runId": "1584966046845.34",
            "pauseDuration": 0,
            "pausePeriods": [],
            "totalJobs": 0
        }
    }
    requests_mock.post(f'{MOCK_URL}/api/orch/v1/accounts/{MOCK_ACCOUNT_ID}/queue',
                       json=response)
    requests_mock.get(f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/insights?type=actionBased',
                      json=GET_INSIGHTS_LIST)
    insight_rerun_command(client, demisto.args())
    assert demisto.results.call_count == 1
    outputs = demisto.results.call_args[0][0]
    context = outputs['EntryContext']
    assert context['SafeBreach.Insight(val.Id == obj.Id)'][0]['Id'] == int(INSIGHT_ID)
    assert context['SafeBreach.Insight(val.Id == obj.Id)'][0]['Rerun'][0]['Id'] == response['data']['runId']


def test_get_indicators(requests_mock, mocker):
    mocker.patch.object(demisto, 'args', return_value={'limit': '10'})
    mocker.patch.object(demisto, 'results')
    mocker.patch.object(demisto, 'params', return_value={'url': MOCK_URL})

    for insight_id in [5, 6, 8, 9, 13, 14, 17]:
        requests_mock.get(f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/insights/{insight_id}/remediation',
                          json=REMEDATION_DATA_LIST)

    requests_mock.get(
        f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/insights?type=actionBased',
        json=GET_INSIGHTS_LIST)
    requests_mock.get(
        f'{MOCK_URL}/api/config/v1/accounts/{MOCK_ACCOUNT_ID}/nodes?details=true&deleted=true&assets=true',
        json=NODES)
    insight_category = ['Endpoint', 'Web']
    insight_data_type = ['Hash', 'Domain']
    hash_to_search = '109c702578b261d0eda01506625423f5a2b8cc107b0d8dfad84d39fb02bfa5cb'
    res = get_indicators_command(client, insight_category, insight_data_type, 'AMBER', demisto.args())
    assert demisto.results.call_count == 0
    assert res[0]['value'] == hash_to_search
    assert res[0]['type'] == 'File'


def test_get_indicators_exception(requests_mock, mocker):
    mocker.patch.object(demisto, 'args', return_value={'limit': '10'})
    mocker.patch.object(demisto, 'results')
    mocker.patch.object(demisto, 'params', return_value={'url': MOCK_URL})

    for insight_id in [5, 6, 8, 9, 13, 14, 17]:
        requests_mock.get(f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/insights/{insight_id}/remediation',
                          json=REMEDATION_DATA_LIST_UNVAILD_STRING)

    requests_mock.get(
        f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/insights?type=actionBased',
        json=GET_INSIGHTS_LIST)
    requests_mock.get(
        f'{MOCK_URL}/api/config/v1/accounts/{MOCK_ACCOUNT_ID}/nodes?details=true&deleted=true&assets=true',
        json=NODES)
    insight_category = ['Endpoint', 'Web']
    insight_data_type = ['Hash', 'Domain']
    hash_to_search = '0000000000000000000000000000000000000000000000000000000000000000'
    res = get_indicators_command(client, insight_category, insight_data_type, 'AMBER', demisto.args())
    assert demisto.results.call_count == 0
    assert res[0]['value'] == hash_to_search
    assert res[0]['type'] == 'File'


def test_get_simulation(requests_mock, mocker):
    mocker.patch.object(demisto, 'args', return_value={'simulationId': SIMULATION_ID})
    mocker.patch.object(demisto, 'results')

    requests_mock.get(f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/executions/{SIMULATION_ID}',
                      json=SIMULATION)

    get_safebreach_simulation_command(client, demisto.args())
    assert demisto.results.call_count == 1
    outputs = demisto.results.call_args[0][0]
    context = outputs['EntryContext']
    assert context['SafeBreach.Simulation(val.Id == obj.Id)']['Id'] == SIMULATION_ID


def test_rerun_simulation(requests_mock, mocker):
    mocker.patch.object(demisto, 'args', return_value={'simulationId': SIMULATION_ID})
    mocker.patch.object(demisto, 'results')
    response = {
        "data": {
            "name": "Rerun (Demisto) - Simulation",
            "moveIds": [
                1,
                2,
                3,
                4,
            ],
            "nodeIds": ['nodeID1', 'nodeID2'],
            "draft": False,
            "ranBy": -1,
            "ranFrom": "UI",
            "isRerun": True,
            "assetIds": [],
            "moveSetIds": [],
            "force": True,
            "queueId": 107,
            "runId": "1584966046845.34",
            "pauseDuration": 0,
            "pausePeriods": [],
            "totalJobs": 0
        }
    }
    requests_mock.post(f'{MOCK_URL}/api/orch/v1/accounts/{MOCK_ACCOUNT_ID}/queue',
                       json=response)
    requests_mock.get(f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/executions/{SIMULATION_ID}',
                      json=SIMULATION)
    rerun_simulation_command(client, demisto.args())
    assert demisto.results.call_count == 1
    outputs = demisto.results.call_args[0][0]
    context = outputs['EntryContext']
    assert context['SafeBreach.Simulation(val.Id == obj.Id)']['Id'] == SIMULATION_ID
    assert context['SafeBreach.Simulation(val.Id == obj.Id)']['Rerun']['Id'] == response['data']['runId']


@pytest.mark.parametrize('tlp_color', ['', None, 'AMBER'])
def test_feed_tags_and_tlp_color(requests_mock, mocker, tlp_color):
    """
    Given:
    - client which has tag params
    - different values for tlp_color
    When:
    - Executing get indicators command on feed
    Then:
    - Validate the tags supplied are added to the tags list in addition to the tags that were there before
    - Validate that trafficlightprotocol indicator type is assigned correctly
    """
    mocker.patch.object(demisto, 'args', return_value={'limit': '10'})
    mocker.patch.object(demisto, 'results')
    mocker.patch.object(demisto, 'params', return_value={'url': MOCK_URL})

    for insight_id in [5, 6, 8, 9, 13, 14, 17]:
        requests_mock.get(f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/insights/{insight_id}/remediation',
                          json=REMEDATION_DATA_LIST)

    requests_mock.get(
        f'{MOCK_URL}/api/data/v1/accounts/{MOCK_ACCOUNT_ID}/insights?type=actionBased',
        json=GET_INSIGHTS_LIST)
    requests_mock.get(
        f'{MOCK_URL}/api/config/v1/accounts/{MOCK_ACCOUNT_ID}/nodes?details=true&deleted=true&assets=true',
        json=NODES)
    insight_category = ['Endpoint', 'Web']
    insight_data_type = ['Hash', 'Domain']
    res = get_indicators_command(client, insight_category, insight_data_type, tlp_color, demisto.args())
    assert all(elem in res[0]['fields']['tags'] for elem in ['tag1', 'tag2'])
    if tlp_color:
        assert res[0]['fields']['trafficlightprotocol'] == tlp_color
    else:
        assert not res[0]['fields'].get('trafficlightprotocol')