Пример #1
0
def post(program_state, endpoint, body, outfile):
    """
    Send a POST request to Darktrace.

    \b
    Note: The Darktrace API requires the body content to be reflected in the URL for
    a valid signature to be generated.

    \b
    Arguments:
        ENDPOINT        The Darktrace API endpoint including URL parameters

    \b
    Examples:
        dtctl query post "/intelfeed?addentry=www.evildomain.com" -b addentry=www.evildomain.com
    """
    if not endpoint.startswith('/'):
        endpoint = '/' + endpoint

    parsed_endpoint = urlparse(endpoint)

    if '=' not in body:
        raise click.UsageError('Invalid POST body. Body must be of format key=value')

    key, value = body.split('=')

    output_json = program_state.api.post('{path}?{query}'.format(path=parsed_endpoint.path,
                                                                 query=parsed_endpoint.query),
                                         postdata={key: value})
    process_output(output_json, outfile)
Пример #2
0
def input_diff(program_state, arg, infile, days, start_date, end_date,
               enhanced_only, active_only, outfile):
    """
    List differences in models based on a input list. Input list must contain full model names
    with one name per line.

    \b
    Example file contents:
        Anomalous Connection::Data Sent to Rare Domain
        SaaS::AWS::Anonymous S3 File Download

    \b
    Arguments:
        new                 Models present in Darktrace but not in the input list
        deleted             Models present in the input list but not in Darktrace
        changed             Models in the input list that have been modified within date range

    """
    end_date, start_date = determine_date_range(days, end_date, start_date)

    diff_by_type = {
        'new': get_new_models,
        'deleted': get_deleted_models,
        'changed': get_models_with_changes
    }

    output = diff_by_type[arg](program_state.api,
                               enhanced_only,
                               active_only,
                               infile,
                               start_date=start_date,
                               end_date=end_date)
    process_output(output, outfile)
Пример #3
0
def coverage(program_state, outfile, infile, input_format, network_col, netmask_col, log, cef):
    """
    Calculate coverage based on list of subnets expected to be monitored. Each subnet seen by
    Darktrace is matched against each entry in the input file using Python's ipaddress library.

    Coverage calculation is quite simplistic and naive:

    \b
    a = nr of expected subnets to be monitored
    b = nr of subnets seen by Darktrace that match an entry in the input file

    coverage in percentage = a / b * 100
    """
    click.echo('Calculating coverage, this will take a while...')
    output = calculate_coverage(program_state.api, infile, input_format, network_col, netmask_col)
    append = False
    to_json = True

    if log or cef:
        append = True
        to_json = False

    if log:
        output = convert_json_to_log_lines([output])

    if cef:
        cef_object = Cef(device_event_class_id=140, name='Subnet Coverage')
        output = cef_object.generate_logs([output])

    process_output(output, outfile, append, to_json)
Пример #4
0
def message_details(program_state, text, days, start_date, end_date, outfile):
    """
    Get notice event details for a specified message. Typically used to specify user credential strings.

        Example: USER123
    """
    end_date, start_date = determine_date_range(days, end_date, start_date)
    output = get_message_details(program_state.api, text, start_date, end_date)
    process_output(output, outfile)
Пример #5
0
def host_details(program_state, hostname, days, start_date, end_date, outfile):
    """Time sorted list of connections and events for an EXTERNAL host"""
    if not (is_valid_domain(hostname) or is_valid_hostname(hostname)):
        raise click.UsageError('Hostname contains invalid characters')

    end_date, start_date = determine_date_range(days, end_date, start_date)
    output = get_host_details(program_state.api, hostname, start_date,
                              end_date)
    process_output(output, outfile)
Пример #6
0
def device(program_state, action, tag, did, outfile):
    """
    Manage tags of a device

    \b
    Arguments:
        add             Add tag to device
        delete          Delete tag from device
    """
    process_output(modify_device_tags(program_state.api, action, tag, did), outfile)
Пример #7
0
def device_info(program_state, did, full_device_details, outfile):
    """
    Returns graphable connectivity information for a device

    \b
    Arguments:
        DID                     A Device Identifier
    """
    output = get_device_info(program_state.api, did, full_device_details)
    process_output(output, outfile)
Пример #8
0
def instances(program_state, show_probes, outfile):
    """
    View Darktrace instances, their labels, id numbers and potential locations.

    \b
    Note that:
        - Master id numbers are prepended to breach ids.
        - Location is determined by the Master's label. The part before a "-" is
          considered to be the device's location or region.
    """
    process_output(get_instances(program_state.api, show_probes), outfile)
Пример #9
0
def endpoint_details(program_state, host, infile, outfile):
    """Returns details for external IP addresses and hostnames."""
    if not host and not infile:
        raise click.UsageError(
            'Missing option "--host" / "-h" or "--infile" / "-i".')

    if host and not (is_valid_hostname(host) or is_valid_ipv4_address(host)):
        raise click.UsageError('Invalid hostname or IP address')

    output = get_endpoint_details(program_state.api, host, infile)
    process_output(output, outfile)
Пример #10
0
def connection_details(program_state, uid, days, start_date, end_date,
                       outfile):
    """
    Time sorted list of events for a connection

    \b
        Example: CcdXo43n8B75cdYyI5
    """
    end_date, start_date = determine_date_range(days, end_date, start_date)
    output = get_connection_details(program_state.api, uid, start_date,
                                    end_date)
    process_output(output, outfile)
Пример #11
0
def search_model(program_state, name, outfile):
    """
    Case-insensitive search for models

    \b
    Examples:
        dtctl models search --name *SMB*
        dtctl models search --name Device*
        dtctl models search --name ?evice*
    """
    output = search_models(program_state.api, name)
    process_output(output, outfile)
Пример #12
0
def ip_info(program_state, ip_address, days, outfile):
    """
    Return device data for this IP address

    \b
    Arguments:
        IP_ADDRESS          IP address to search
    """
    if not is_valid_ipv4_address(ip_address):
        raise click.UsageError('not a valid IP address')

    output = get_device_info_by_ip(program_state.api, ip_address, days)
    process_output(output, outfile)
Пример #13
0
def test_process_output_to_log(capsys):
    output = [
        "[2019-01-01T00:00:01] 1.1.1.1 key=\"value\"",
        "[2019-01-01T00:00:02] 1.1.1.2 key=\"value\"",
        "[2019-01-01T00:00:03] 1.1.1.3 key=\"value\"",
        "[2019-01-01T00:00:04] 1.1.1.4 key=\"value\""
    ]
    append = False
    to_json = False

    process_output(output, None, to_json, append)

    captured = capsys.readouterr()
    assert '[2019-01-01T00:00:03] 1.1.1.3 key="value"' in captured.out
Пример #14
0
def usage(program_state, outfile, log, cef):
    """Short usage information of all instances and probes"""
    output = get_usage(program_state.api)
    append = False
    to_json = True

    if log or cef:
        append = True
        to_json = False

    if log:
        output = convert_json_to_log_lines(output)

    if cef:
        cef_object = Cef(device_event_class_id=100, name='System Usage')
        output = cef_object.generate_logs(output)

    process_output(output, outfile, append, to_json)
Пример #15
0
def dhcp(program_state, outfile, log, cef):
    """Metrics for DHCP tracking"""
    output = get_dhcp_stats(program_state.api)
    append = False
    to_json = True

    if log or cef:
        append = True
        to_json = False

    if log:
        output = convert_json_to_log_lines(output)

    if cef:
        cef_object = Cef(device_event_class_id=120, name='DHCP Quality')
        output = cef_object.generate_logs(output)

    process_output(output, outfile, append, to_json)
Пример #16
0
def list_breaches(program_state, acknowledged_only, include_acknowledged, tags,
                  minimal, minscore, pid, days, start_date, end_date, outfile):
    """List Darktrace model breaches"""
    end_date, start_date = determine_date_range(days, end_date, start_date)

    if minscore > 1.0:
        minscore = 1.0
    if minscore < 0.0:
        minscore = 0.0
    minscore = round(minscore, 1)

    if acknowledged_only:
        include_acknowledged = True

    output = get_breaches(program_state.api, acknowledged_only,
                          include_acknowledged, tags, minimal, minscore, pid,
                          start_date, end_date)

    process_output(output, outfile)
Пример #17
0
def test_process_output_to_cef(capsys):
    output = [
        "CEF:0|DCIP|System Monitoring|1.0|100|system usage|5|start=1234567890 end=1234567890 src=10.10.10.1 "
        "cs1Label=type cs1=probe cs2Label=label cs2=Appliance label1 cn1Label=bandwidth cn1=1000 cn2Label=cpu cn2=50",
        "CEF:0|DCIP|System Monitoring|1.0|100|system usage|5|start=1234567890 end=1234567890 src=10.10.10.2 "
        "cs1Label=type cs1=master cs2Label=label cs2=Appliance label2 cn1Label=bandwidth cn1=1000 cn2Label=cpu cn2=50",
    ]
    append = False
    to_json = False

    process_output(output, None, to_json, append)

    captured = capsys.readouterr()
    print(captured.out)
    assert 'CEF:0|DCIP|System Monitoring|1.0|100|system usage|5|' \
           'start=1234567890 end=1234567890 src=10.10.10.1 cs1Label=type cs1=probe ' \
           'cs2Label=label cs2=Appliance label1 cn1Label=bandwidth cn1=1000 cn2Label=cpu cn2=50' in captured.out
    assert 'CEF:0|DCIP|System Monitoring|1.0|100|system usage|5|' \
           'start=1234567890 end=1234567890 src=10.10.10.2 cs1Label=type cs1=master ' \
           'cs2Label=label cs2=Appliance label2 cn1Label=bandwidth cn1=1000 cn2Label=cpu cn2=50' in captured.out
Пример #18
0
def packet_loss(program_state, days, start_date, end_date, outfile, log, cef):
    """Information about reported packet loss per system"""
    end_date, start_date = determine_date_range(days, end_date, start_date)

    output = get_packet_loss(program_state.api, start_date, end_date)
    append = False
    to_json = True

    if log or cef:
        append = True
        to_json = False

    if log:
        output = convert_json_to_log_lines(output)

    if cef:
        cef_object = Cef(device_event_class_id=110, name='Packet Loss')
        output = cef_object.generate_logs(output)

    process_output(output, outfile, append, to_json)
Пример #19
0
def issues(program_state, days, start_date, end_date, outfile, log, cef):
    """Information about Darktrace system issues"""
    end_date, start_date = determine_date_range(days, end_date, start_date)

    output = get_system_issues(program_state.api, start_date, end_date)
    append = False
    to_json = True

    if log or cef:
        append = True
        to_json = False

    if log:
        output = convert_json_to_log_lines(output)

    if cef:
        cef_object = Cef(device_event_class_id=130, name='System Issue')
        output = cef_object.generate_logs(output)

    process_output(output, outfile, append, to_json)
Пример #20
0
def get(program_state, endpoint, outfile):
    """
    Send a GET request to Darktrace

    \b
    Arguments:
        ENDPOINT        The Darktrace API endpoint including URL parameters

    \b
    Examples:
        dtctl query get "/status"
        dtctl query get "/breaches?starttime=1558303200000&endtime=1558475999000"
    """
    if not endpoint.startswith('/'):
        endpoint = '/' + endpoint

    parsed_endpoint = urlparse(endpoint)

    output_json = program_state.api.get('{path}?{query}'.format(path=parsed_endpoint.path,
                                                                query=parsed_endpoint.query))
    process_output(output_json, outfile)
Пример #21
0
def select_model(program_state, selectors, outfile):
    """
    Select models based on top-level key value pairs. Nesting is not possible.

    \b
    Arguments:
        SELECTORS       One or multiple key-value paris

    \b
    Examples:
        dtctl models select active=true
        dtctl models select autoupdate=true version=13
    """
    key_values = {}
    for arg in selectors:
        if '=' not in arg:
            raise click.UsageError(
                'Invalid format for "{0}"\nSELECTORS must be in format "key=value"'
                .format(arg))
        key, value = arg.split('=')
        key_values[key] = value

    output = select_models_by_key_values(program_state.api, key_values)
    process_output(output, outfile)
Пример #22
0
def test_process_output(tmpdir, capsys):
    tmpfile = '{0}/pytest.tmp.json'.format(tmpdir)

    output = {
        'key1': [1, 2, 3],
        'key2': 'data',
        'key3': {
            'subkey1': ['value1', 'value2'],
            'subkey2': True
        }
    }
    process_output(output, tmpfile)

    assert os.path.isfile(tmpfile)

    with open(tmpfile) as infile:
        loaded_output_file = json.load(infile)

    assert loaded_output_file['key1'][0] == 1
    assert loaded_output_file['key1'][1] == 2
    assert loaded_output_file['key1'][2] == 3
    assert loaded_output_file['key2'] == 'data'
    assert loaded_output_file['key3']['subkey1'][0] == 'value1'
    assert loaded_output_file['key3']['subkey1'][1] == 'value2'
    assert loaded_output_file['key3']['subkey2']

    process_output(output, None)

    captured = capsys.readouterr()
    assert '{\n    "key1": [\n        1,\n' in captured.out
    assert '"key2": "data",\n' in captured.out
    assert '"key3": {\n' in captured.out
    assert '"subkey2": true\n    }' in captured.out

    if os.path.isfile(tmpfile):
        os.remove(tmpfile)
Пример #23
0
def list_filters(program_state, outfile):
    """List Darktrace component filters"""
    output = get_filters(program_state.api)
    process_output(output, outfile)
Пример #24
0
def device_details(program_state, did, days, start_date, end_date, outfile):
    """Time sorted list of connections and events for a device"""
    end_date, start_date = determine_date_range(days, end_date, start_date)
    output = get_device_details(program_state.api, did, start_date, end_date)
    process_output(output, outfile)
Пример #25
0
def breach_details(program_state, pbid, outfile):
    """Time sorted list of connections and events for a breach"""
    output = get_breach_details(program_state.api, pbid)
    process_output(output, outfile)
Пример #26
0
def list_devices(program_state, days, seconds, outfile):
    """Returns the list of device identified by Darktrace"""
    output = get_devices(program_state.api, days, seconds)
    process_output(output, outfile)
Пример #27
0
def list_intelfeed(program_state, outfile):
    """List entries in Darktrace's intelligence feed (Watchlist)"""
    process_output(get_intelfeed(program_state.api), outfile)
Пример #28
0
def add_entry(program_state, value, infile, outfile):
    """Add entries to Darktrace's intelligence feed (Watchlist)"""
    if not (value or infile):
        raise click.UsageError('Missing option "--value" / "-v" or "--infile" / "-i".')
    process_output(add_entry_to_intelfeed(program_state.api, value, infile), outfile)
Пример #29
0
def del_entry(program_state, value, infile, outfile):
    """Delete entries from Darktrace's intelligence feed (Watchlist)"""
    if not (value or infile):
        raise click.UsageError('Missing option "--value" / "-v" or "--infile" / "-i".')
    process_output(delete_entry_from_intelfeed(program_state.api, value, infile), outfile)
Пример #30
0
def list_metrics(program_state, outfile):
    """List Darktrace metrics"""
    output = get_metrics(program_state.api)
    process_output(output, outfile)