Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor verbose analyzer output #2885

Merged
merged 9 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions timesketch/lib/analyzers/account_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,7 @@ def run(self):
continue

# Add the account tags to the output data
if "created_tags" in self.output.platform_meta_data:
existing_created_tags = self.output.platform_meta_data[
"created_tags"
]
self.output.platform_meta_data["created_tags"] = list(
set().union(existing_created_tags, [account_tag])
)
else:
self.output.platform_meta_data["created_tags"] = [account_tag]
self.output.add_created_tags([account_tag])

found_account = event.source.get("found_account")

Expand Down
10 changes: 8 additions & 2 deletions timesketch/lib/analyzers/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ def run(self):

# Exit early if there are no domains in the data set to analyze.
if not domain_counter:
return "No domains to analyze."
self.output.result_status = "SUCCESS"
self.output.result_priority = "NOTE"
self.output.result_summary = "No domains to analyze."
return str(self.output)

domain_count_array = numpy.array(list(domain_counter.values()))
try:
Expand Down Expand Up @@ -118,10 +121,13 @@ def run(self):
# Commit the event to the datastore.
event.commit()

return (
self.output.result_status = "SUCCESS"
self.output.result_priority = "NOTE"
self.output.result_summary = (
"{0:d} domains discovered ({1:d} TLDs) and {2:d} known "
"CDN networks found."
).format(len(domains), len(tld_counter), len(cdn_counter))
return str(self.output)


manager.AnalysisManager.register_analyzer(DomainSketchPlugin)
2 changes: 2 additions & 0 deletions timesketch/lib/analyzers/hashr_lookup_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,7 @@ def test_run_tags_and_sources(
"sketch_id": 1,
"timeline_id": 1,
"created_tags": ["zerobyte-file", "known-hash"],
"created_attributes": ["hashR_sample_sources"],
},
"result_markdown": "Found a total of 13 events that contain a sha256 hash value\n* 5 / 11 unique hashes known in hashR\n* 5 events tagged\n* 1 entries were tagged as zerobyte files\n* 2 events raised an error",
}
Expand All @@ -661,6 +662,7 @@ def test_run_tags_and_sources(
"sketch_id": 1,
"timeline_id": 1,
"created_tags": ["known-hash", "zerobyte-file"],
"created_attributes": ["hashR_sample_sources"],
},
"result_markdown": "Found a total of 13 events that contain a sha256 hash value\n* 5 / 11 unique hashes known in hashR\n* 5 events tagged\n* 1 entries were tagged as zerobyte files\n* 2 events raised an error",
}
Expand Down
146 changes: 119 additions & 27 deletions timesketch/lib/analyzers/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ def add_attributes(self, attributes):
Args:
attributes: Dictionary with new or updated values to add.
"""
# TODO: add attributes to the analyzer output object!
if self._analyzer:
self._analyzer.output.add_created_attributes(list(attributes.keys()))

self._update(attributes)

def add_label(self, label, toggle=False):
Expand Down Expand Up @@ -253,15 +257,7 @@ def add_tags(self, tags):

# Add new tags to the analyzer output object
if self._analyzer:
if "created_tags" in self._analyzer.output.platform_meta_data:
existing_created_tags = self._analyzer.output.platform_meta_data[
"created_tags"
]
self._analyzer.output.platform_meta_data["created_tags"] = list(
set().union(existing_created_tags, tags)
)
else:
self._analyzer.output.platform_meta_data["created_tags"] = [tags]
self._analyzer.output.add_created_tags(new_tags)

def add_emojis(self, emojis):
"""Add emojis to the Event.
Expand Down Expand Up @@ -527,15 +523,7 @@ def add_view(

# Add new view to the list of saved_views in the analyzer output object
if self._analyzer:
if "saved_views" in self._analyzer.output.platform_meta_data:
existing_saved_views = self._analyzer.output.platform_meta_data[
"saved_views"
]
self._analyzer.output.platform_meta_data["saved_views"] = list(
set().union(existing_saved_views, [view.id])
)
else:
self._analyzer.output.platform_meta_data["saved_views"] = [view.id]
self._analyzer.output.add_saved_view(view.id)

return view

Expand Down Expand Up @@ -616,15 +604,7 @@ def add_story(self, title):

# Add new story to the analyzer output object.
if self._analyzer:
if "saved_stories" in self._analyzer.output.platform_meta_data:
existing_saved_stories = self._analyzer.output.platform_meta_data[
"saved_stories"
]
self._analyzer.output.platform_meta_data["saved_stories"] = list(
set().union(existing_saved_stories, [story.id])
)
else:
self._analyzer.output.platform_meta_data["saved_stories"] = [story.id]
self._analyzer.output.add_saved_story(story.id)

return Story(story)

Expand Down Expand Up @@ -1240,6 +1220,8 @@ class AnalyzerOutput:
saved_aggregations (List[int]): [Optional] Aggregations generated
by the analyzer.
created_tags (List[str]): [Optional] Tags created by the analyzer.
created_attributes (List[str]): [Optional] Attributes created by
the analyzer.
"""

def __init__(
Expand Down Expand Up @@ -1269,6 +1251,7 @@ def __init__(
"saved_graphs": [],
"saved_aggregations": [],
"created_tags": [],
"created_attributes": [],
}

def validate(self):
Expand Down Expand Up @@ -1330,6 +1313,12 @@ def validate(self):
{"type": "string"},
],
},
"created_attributes": {
"type": "array",
"items": [
{"type": "string"},
],
},
},
"required": [
"timesketch_instance",
Expand All @@ -1355,6 +1344,104 @@ def validate(self):
except (ValidationError, SchemaError) as e:
raise AnalyzerOutputException(f"json schema error: {e}") from e

def add_reference(self, reference):
jkppr marked this conversation as resolved.
Show resolved Hide resolved
"""Adds a reference to the list of references.

Args:
reference: A reference e.g. URL to add to the list of references.
"""
if not isinstance(reference, list):
reference = [reference]
self.references = list(set().union(self.references, reference))

def set_meta_timesketch_instance(self, timesketch_instance):
"""Sets the timesketch instance URL.

Args:
timesketch_instance: The timesketch instance URL.
"""
self.platform_meta_data["timesketch_instance"] = timesketch_instance

def set_meta_sketch_id(self, sketch_id):
"""Sets the sketch ID.

Args:
sketch_id: The sketch ID.
"""
self.platform_meta_data["sketch_id"] = sketch_id

def set_meta_timeline_id(self, timeline_id):
"""Sets the timeline ID.

Args:
timeline_id: The timeline ID.
"""
self.platform_meta_data["timeline_id"] = timeline_id

def add_meta_item(self, key, item):
"""Handles the addition of platform_meta_data items.

Args:
key: The key to add to the platform_meta_data dict.
item: The value to add to the platform_meta_data dict.
"""
if not isinstance(item, list):
item = [item]
if key in self.platform_meta_data:
self.platform_meta_data[key] = list(
set().union(self.platform_meta_data[key], item)
)
else:
self.platform_meta_data[key] = item

def add_saved_view(self, view_id):
"""Adds a view ID to the list of saved_views.

Args:
view_id: The view ID to add to the list of saved_views.
"""
self.add_meta_item("saved_views", view_id)

def add_saved_story(self, story_id):
"""Adds a story ID to the list of saved_stories.

Args:
story_id: The story ID to add to the list of saved_stories.
"""
self.add_meta_item("saved_stories", story_id)

def add_saved_graph(self, graph_id):
"""Adds a graph ID to the list of saved_graphs.

Args:
graph_id: The graph ID to add to the list of saved_graphs.
"""
self.add_meta_item("saved_graphs", graph_id)

def add_saved_aggregation(self, aggregation_id):
"""Adds an aggregation ID to the list of saved_aggregations.

Args:
aggregation_id: The aggregation ID to add to the list of saved_aggregations.
"""
self.add_meta_item("saved_aggregations", aggregation_id)

def add_created_tags(self, tags):
"""Adds a tags to the list of created_tags.

Args:
tags: The tags to add to the list of created_tags.
"""
self.add_meta_item("created_tags", tags)

def add_created_attributes(self, attributes):
"""Adds a attributes to the list of created_attributes.

Args:
attributes: The attributes to add to the list of created_attributes.
"""
self.add_meta_item("created_attributes", attributes)

def to_json(self) -> dict:
"""Returns JSON output of AnalyzerOutput. Filters out empty values."""
# add required fields
Expand Down Expand Up @@ -1407,6 +1494,11 @@ def to_json(self) -> dict:
"created_tags"
]

if self.platform_meta_data["created_attributes"]:
output["platform_meta_data"][
"created_attributes"
] = self.platform_meta_data["created_attributes"]

return output

def __str__(self) -> str:
Expand Down