Skip to content

Commit

Permalink
Add timesketch analyze results to the CLI client (#2846)
Browse files Browse the repository at this point in the history
* [CLI] add timesketch analyze results

* make unsupported types nicer

* make lint happy

* Update docs/guides/user/cli-client.md

* Update docs/guides/user/cli-client.md

* Update docs/guides/user/cli-client.md

---------

Co-authored-by: Johan Berggren <[email protected]>
  • Loading branch information
jaegeral and berggren authored Jul 21, 2023
1 parent 4d623d2 commit df3c0db
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 1 deletion.
102 changes: 102 additions & 0 deletions cli_client/python/timesketch_cli_client/commands/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import sys
import time

import json
import click

from timesketch_api_client import error
Expand Down Expand Up @@ -114,3 +115,104 @@ def list_analyzers(ctx):
)
continue
click.echo(analyzer.get("name"))


@analysis_group.command(
"results",
help="Show the results of an analyzer run on a specific timeline.",
)
@click.option(
"--analyzer",
"analyzer_name",
required=True,
help="The name of the analyzer that was run.",
)
@click.option(
"--timeline",
"timeline_id",
required=True,
help="The id of the timeline that was analyzed.",
)
# boolean flag show_dependent
@click.option(
"--show-dependent",
"show_dependent",
required=False,
default=False,
is_flag=True,
help="Show the results of an analyzer run dependent from the original one.",
)
@click.pass_context
def analyzer_results(ctx, analyzer_name, timeline_id, show_dependent):
"""Show the results of an analyzer run on one or more timelines.
Args:
ctx: Click CLI context object.
analyzer_name: Name of the analyzer that was run.
timeline_id: Timeline ID of the timeline to analyze.
show_dependent: Show dependent analyzers. (default: False)
using output_format json will always include the dependent analyzers
"""
sketch = ctx.obj.sketch
output = ctx.obj.output_format

if output not in ("json", "text"):
click.echo(f"Unsupported output format: [{output}] use [json / text]")
sys.exit(1)

timelines = []
if timeline_id == "all":
timelines = sketch.list_timelines()
else:
timeline = sketch.get_timeline(timeline_id=int(timeline_id))
timelines.append(timeline)

for timeline in timelines:
try:
sketch_analyzer_results = sketch.get_analyzer_status()
if output == "json":
click.echo(
json.dumps(
sketch_analyzer_results,
indent=4,
sort_keys=True,
default=str,
)
)
else:
click.echo(
f"Results for analyzer [{analyzer_name}] on [{timeline.name}]:"
)
for analyzer in sketch_analyzer_results:
if analyzer.get("timeline_id") == int(timeline_id):
# find analyzer results using the verbose schema
try:
# the following will only work for verbose schema
analyzer_json = json.loads(analyzer.get("results"))
status = analyzer_json.get("result_status")
result_priority = analyzer_json.get("result_priority")
result_summary = analyzer_json.get("result_summary")
except json.decoder.JSONDecodeError:
# set values for non verbose
status = analyzer.get("status")
result_priority = analyzer.get("result_priority")
result_summary = analyzer.get("results")

if analyzer.get("analyzer") == analyzer_name:
click.echo(
f"{status} - {result_priority} - {result_summary}"
)
else:
# TODO(jaegeral) consider sorting to show the root
# analyzer first
if show_dependent:
click.echo(
f"Dependent: {status} - {result_priority} \
- {result_summary}"
)
except Exception as e: # pylint: disable=broad-except
click.echo(
f"Unable to get results for analyzer [{analyzer_name}] \
on [{timeline.name}]: {e}"
)
sys.exit(1)
84 changes: 83 additions & 1 deletion docs/guides/user/cli-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ This example returns the field name `domain` and then do a simple sort and uniq.
timesketch search -q "foobar" --return-fields domain | sort | uniq
```

## Run analyzers
## Analyzers

### List

List all available analyzers:

Expand Down Expand Up @@ -180,6 +182,8 @@ browser_search Browser search terms False
windowsbruteforceanalyser Windows Login Brute Force Analyzer False
```

### Run

Run a specific analyzer. In this example the `domain` analyzer on timeline 1:

```
Expand All @@ -191,6 +195,84 @@ Results
```

### List analyzer results

It might be useful to see the results of an analyzer for a specific timeline.
That can be done with `timesketch analyzer results`.

It can show only the analyzer results directly:

```
timesketch --output-format text analyze results --analyzer account_finder --timeline 3
Results for analyzer [account_finder] on [sigma_events]:
SUCCESS - NOTE - Account finder was unable to extract any accounts.
```

Some analyzers might start dependent analyzers, to also show those results use
the flag `--show-dependent`. This will look similar to:

```bash
timesketch --output-format text analyze results --analyzer account_finder --timeline 3 --show-dependent
Results for analyzer [account_finder] on [sigma_events]:
Dependent: DONE - None - Feature extraction [gmail_accounts] extracted 0 features.
Dependent: DONE - None - Feature extraction [github_accounts] extracted 0 features.
Dependent: DONE - None - Feature extraction [linkedin_accounts] extracted 0 features.
Dependent: DONE - None - Feature extraction [rdp_ts_ipv4_addresses] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_client_ipv4_addresses] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_client_ipv4_addresses_2] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_host_ipv4_addresses] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_client_password_ipv4_addresses] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_disconnected_username] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_disconnected_ip_address] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_disconnected_port] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_failed_ip_address] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_failed_port] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_failed_method] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_subject_username] extracted 0 features.
Dependent: DONE - None - Feature extraction [email_addresses] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_domain] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_logon_id] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_logon_type] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_logon_process_name] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_workstation_name] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_process_id] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_process_name] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_ip_address] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_port] extracted 0 features.
SUCCESS - NOTE - Account finder was unable to extract any accounts.
Dependent: DONE - None - Feature extraction [rdp_rds_ipv4_addresses] extracted 0 features.
Dependent: DONE - None - Feature extraction [ssh_failed_username] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_subject_domain] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_subject_logon_id] extracted 0 features.
Dependent: DONE - None - Feature extraction [win_login_username] extracted 0 features.

```

To get a result in `json` that can be piped into other CLI tools run something
like:

```json
timesketch --output-format json analyze results --analyzer account_finder --timeline 3 --show-dependent
[
{
"analyzer": "feature_extraction",
"index": "<timesketch_api_client.index.SearchIndex object at 0x7ff9079a7a60>",
"results": "Feature extraction [gmail_accounts] extracted 0 features.",
"session_id": 1,
"status": "DONE",
"timeline_id": 3
},
{
"analyzer": "feature_extraction",
"index": "<timesketch_api_client.index.SearchIndex object at 0x7ff9079a7910>",
"results": "Feature extraction [github_accounts] extracted 0 features.",
"session_id": 1,
"status": "DONE",
"timeline_id": 3
}
]
```

## Events

### Add manual events
Expand Down

0 comments on commit df3c0db

Please sign in to comment.