示例#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)