Case
A minimalistic case
The most minimalistic case requires at least the below fields to be defined:
title
: The title of the case.description
: The description of the case.
Here's an example that demonstrates how to create the most minimalistic case possible using the case.create method:
from thehive4py import TheHiveApi
hive = TheHiveApi(url="http://localhost:9000", apikey="h1v3b33")
minimalistic_case = hive.case.create(
case={
"title": "a minimalistic case",
"description": "a bit too minimal",
}
)
An advanced case
The previous example demonstrated how to create the simplest case ever.
In the next example let's create a more advanced case by using the combination of the InputCase type hint and the case.create method.
from thehive4py import TheHiveApi
from thehive4py.types.case import InputCase
hive = TheHiveApi(url="http://localhost:9000", apikey="h1v3b33")
input_case: InputCase = {
"title": "an advanced case",
"description": "a bit more advanced case...",
"caseTemplate": "my-template",
"severity": 1,
"status": "New",
"tags": ["advanced", "example"],
}
output_case = hive.case.create(case=input_case)
In the above snippet input_case
is created before the create call and later passed to the case
argument.
Finally after the creation of the case we saved the response in the output_case
to be able to use it later.
Note
While the above case is a bit more advanced it's still far from the most complex example that is possible. Should you be interested of what the Case API offers please check out the official docs.
Get and find
There are multiple ways to retrieve already existing cases:
Get a single case
To get a single case one can use the case.get method with the case's id as follows:
from thehive4py import TheHiveApi
hive = TheHiveApi(url="http://localhost:9000", apikey="h1v3b33")
case_to_get = hive.case.create(
case={
"title": "case to get",
"description": "a single case to fetch",
}
)
fetched_case = hive.case.get(case_id=case_to_get["_id"])
Find multiple cases
To fetch multiple cases based on arbitrary conditions one can use the case.find method which is an abstraction on top of TheHive's Query API.
In the next example we will create two cases with different tags. The first case will get the antivirus
tag while the second one will get the phishing
tag.
Then we will construct a query filter that will look for cases with these tags on them:
from thehive4py import TheHiveApi
from thehive4py.query.filters import Eq
hive = TheHiveApi(url="http://localhost:9000", apikey="h1v3b33")
antivirus_case = hive.case.create(
case={
"title": "case #1 to find",
"description": "a case to find with others",
"tags": ["antivirus"],
}
)
phishing_case = hive.case.create(
case={
"title": "case #2 to find",
"description": "a case to find with others",
"tags": ["phishing"],
}
)
filters = Eq(field="tags", value="antivirus") | Eq(field="tags", value="phishing")
fetched_cases = hive.case.find(filters=filters)
The above example demonstrates how to construct query filters.
These filter expressions can be chained together with different operators, just like we did with the |
(or
) operator in the example.
Currently, the filter classes support the following operators:
&
: Used for the Query API's_and
construct.|
: Used for the Query API's_or
construct.~
: Used for the Query API's_not
construct.
The full list of the filter builders can be found in the query.filters module.
Update single and bulk
Sometimes an existing case needs to be updated. TheHive offers multiple ways to accomplish this task either with a single case or multiple ones.
Update single
A single case can be updated using case.update method. The method requires the case_id
of the case to be updated and the fields
to update.
from thehive4py import TheHiveApi
hive = TheHiveApi(url="http://localhost:9000", apikey="h1v3b33")
original_case = hive.case.create(
case={
"title": "original case",
"description": "a single case to update",
}
)
hive.case.update(
case_id=original_case["_id"],
fields={
"title": "updated case",
"tags": ["update-single"],
},
)
updated_case = hive.case.get(case_id=original_case["_id"])
In the above example we've updated the title
and the tags
fields.
Be mindful though, thehive4py
is a lightweight wrapper around TheHive API and offers no object relationship mapping functionalities, meaning that the original original_case
won't reflect the changes of the update.
To work with the updated case we fetched the latest version using the case.get method and stored it in the updated_case
variable.
Now the content of updated_case
should reflect the changes we made with our update request.
Tip
To see the full list of supported update fields please consult the official docs.
Update bulk
To update the same fields with the same values on multiple cases at the same time, one can use case.bulk_update method.
The method accepts the same fields
dictionary with an additional ids
field on it, which should contain the list of ids of the cases to be bulk updated.
from thehive4py import TheHiveApi
hive = TheHiveApi(url="http://localhost:9000", apikey="h1v3b33")
original_case_ids = []
for i in range(2):
original_case = hive.case.create(
case={
"title": f"original case #{i}",
"description": "a case to update in bulk",
}
)
original_case_ids.append(original_case["_id"])
hive.case.bulk_update(
fields={
"ids": original_case_ids,
"title": "bulk updated case",
"tags": ["update-bulk"],
},
)
In the example we prepare two cases for the bulk update, and collect their ids in the original_case_ids
list.
Then we update the fields title
and tags
on both cases using the bulk update method.
Merge cases
Many times during case triaging it occurs that individual cases turn out to be closely related. For this use case TheHive provides an option to merge individual cases using the case.merge method.
In the following example we will create two cases and will merge them into one new case:
from thehive4py import TheHiveApi
hive = TheHiveApi(url="http://localhost:9000", apikey="h1v3b33")
case_ids_to_merge: list[str] = []
for i in range(2):
case_to_merge = hive.case.create(
case={
"title": f"original case #{i}",
"description": "a case to merge with another",
}
)
case_ids_to_merge.append(case_to_merge["_id"])
merge_case = hive.case.merge(case_ids=case_ids_to_merge)
As you can see the merged cases will end up in one single case which is represented by the merge_case
variable in our example.
Important
In case you wonder what will happen to the original cases, during the merge they will be deleted and their legacy will live on in the final merge case.
Note
In the example we merged two cases, but it's worth to mention that the merge endpoint lets us merge as many cases as we need into one final case.
Delete
It's possible to delete a case using the case.delete method. Here's a simple example to demonstrate:
from thehive4py import TheHiveApi
hive = TheHiveApi(url="http://localhost:9000", apikey="h1v3b33")
case_to_delete = hive.case.create(
case={
"title": "delete case",
"description": "an case to delete",
}
)
hive.case.delete(case_id=case_to_delete["_id"])
Note
In contrast to the alert endpoint the case endpoint doesn't support bulk deletion of cases, so should you need to delete multiple cases the easiest options is to collect the case ids and iterate over them using the single delete endpoint.
Case observables
TheHive API provides multiple ways to add observables to cases, let them be textual or file based observables.
Add observables to an existing case
Unlike the Alert API, the Case API doesn't support adding observables to cases during their creation, this means that we can only add case observables retroactively.
In the next example we're gonna create a case to add two observables to it using the case.create_observable method:
from thehive4py import TheHiveApi
from thehive4py.types.observable import InputObservable
hive = TheHiveApi(url="thehive.example", apikey="h1v3b33")
case_to_enrich = hive.case.create(
case={
"title": "case to enrich",
"description": "a case to enrich with simple observables",
}
)
observables: list[InputObservable] = [
{"dataType": "ip", "data": "1.2.3.4"},
{"dataType": "domain", "data": "example.com"},
]
for observable in observables:
hive.case.create_observable(case_id=case_to_enrich["_id"], observable=observable)
Add file based observables
In the previous example we've seen how to handle simple observables without attachments. Next we will create a temporary directory with a dummy file and some dummy content that will represent our file based observable and add it to a case:
import os.path
import tempfile
from thehive4py import TheHiveApi
hive = TheHiveApi(url="http://localhost:9000", apikey="h1v3b33")
case_to_enrich = hive.case.create(
case={
"title": "case to enrich",
"description": "a case to enrich with a file observable",
}
)
with tempfile.TemporaryDirectory() as tmpdir:
observable_filepath = os.path.join(tmpdir, "my-observable.txt")
with open(observable_filepath) as observable_file:
observable_file.write("some observable content")
hive.case.create_observable(
case_id=case_to_enrich["_id"],
observable={"dataType": "file", "message": "a file based observable"},
observable_path=observable_filepath,
)
As we can see from the above example a file based observable needs an actual file and its filepath, in our example these are represented by observable_filepath
and observable_file
Finally the observable
metadata needs to be defined with its dataType
as file
and then the data
field should be omitted. Finally the observable_path
argument must be defined with the value of the actual observable_filepath
.
This way TheHive will pair the observable metadata with the file as its attachment behind the scenes.
Case tasks
For more advanced case handling we can specify tasks which will serve as steps during the evaluation of the case.
Fortunately TheHive API provides different options to add tasks to cases and we will check them out in the next sections.
Add tasks during case creation
We can specify tasks already during case creation. This is a great way to combine case and task creation in an atomic way.
Let's do an example to create a case with a Triage
and Respond
tasks:
from thehive4py import TheHiveApi
from thehive4py.types.task import InputTask
hive = TheHiveApi(url="thehive.example", apikey="h1v3b33")
case_tasks: list[InputTask] = [
{"title": "Triage", "description": "Conduct the initial investigation"},
{"title": "Respond", "description": "Execute the required actions"},
]
case_with_tasks = hive.case.create(
case={
"title": "case with tasks",
"description": "a case enriched with tasks",
"tasks": case_tasks,
}
)
This snippet will create a case with the required tasks in one go.
Add tasks to an existing case
In the previous section we could see that it's possible to specify tasks during case creation, however sometimes we want to add tasks after a case has been created.
For this purpose we can use the case.create_task method.
Now let's do an example by adding tasks retroactively to a case:
from thehive4py import TheHiveApi
from thehive4py.types.task import InputTask
hive = TheHiveApi(url="thehive.example", apikey="h1v3b33")
case_to_enrich = hive.case.create(
case={
"title": "case to enrich",
"description": "a case to enrich with tasks",
}
)
case_tasks: list[InputTask] = [
{"title": "Summarize", "description": "Summarize the investigation"},
{"title": "Report", "description": "Create a report for the CISO"},
]
for case_task in case_tasks:
hive.case.create_task(case_id=case_to_enrich["_id"], task=case_task)
In the above example we created an empty case as case_to_enrich
, and then defined a list of two tasks in the case_tasks
variable.
Finally using a for loop and the case.create_task
method we added them to our dummy case one by one.
Case pages
In order to give more context to a case we can add pages to it, which could serve as additional notes or documentation during investigation.
Like usual TheHive API provides different possibilities to add such pages to cases that we will see in the next sections.
Add pages during case creation
We can add pages already during case creation. This is a great way to combine case and page creation in a single go.
Let's create a case with two pages, one to take notes and another one to summarize the case:
from thehive4py import TheHiveApi
from thehive4py.types.page import InputCasePage
hive = TheHiveApi(url="thehive.example", apikey="h1v3b33")
case_pages: list[InputCasePage] = [
{
"title": "Notes",
"category": "default",
"content": "Some notes to take during case triage.",
},
{
"title": "Summary",
"category": "default",
"content": "Some summary to wrap up the case triage.",
},
]
case_with_tasks = hive.case.create(
case={
"title": "case with tasks",
"description": "a case enriched with tasks",
"pages": case_pages,
}
)
As you can see we had to specify the title
, category
and content
fields which are all mandatory for the page objects.
On the other hand each of these fields are freetext fields so we have the freedom to specify any value for them.
Add pages to an existing case
In the previous section we could see that it's possible to add pages during case creation, however sometimes we want to add pages after a case has been created.
For this purpose we can use the case.create_page method.
Now let's do an example by adding pages retroactively to a case:
from thehive4py import TheHiveApi
from thehive4py.types.page import InputCasePage
hive = TheHiveApi(url="thehive.example", apikey="h1v3b33")
case_to_enrich = hive.case.create(
case={
"title": "case to enrich",
"description": "a case to enrich with pages",
}
)
case_pages: list[InputCasePage] = [
{
"title": "Playbooks",
"category": "general",
"content": "Some playbook content",
},
{
"title": "Resources",
"category": "general",
"content": "Some useful resources",
},
]
for case_page in case_pages:
hive.case.create_page(case_id=case_to_enrich["_id"], page=case_page)
In the above example we created an empty case as case_to_enrich
, and then defined a list of pages in the page_tasks
variable.
Finally using a for loop and the case.create_page
method we added them to our dummy case one by one.
Case procedures
TheHive considers the MITRE ATT&CK framework as a first class citizen and fully supports its tactics, techniques and procedures (TTPs for short), therefore it's possible to enrich cases with procedures from their catalog.
TheHive simply refers to the MITRE ATT&CK TTPs as procedures, and next we will see how can these procedures be applied to cases.
Add procedures to an existing case
In this example we will create an empty case and using the case.create_task method we will enrich it with the technique of [T1566] Phishing and the subtechnique of [T1566.001] Phishing - Spearphishing Attachment:
from thehive4py import TheHiveApi
from thehive4py.helpers import now_to_ts
from thehive4py.types.procedure import InputProcedure
hive = TheHiveApi(url="thehive.example", apikey="h1v3b33")
case_to_enrich = hive.case.create(
case={
"title": "case to enrich",
"description": "a case to enrich with procedures",
}
)
case_procedures: list[InputProcedure] = [
{
"occurDate": now_to_ts(),
"patternId": "T1566",
"tactic": "initial-access",
"description": "Phishing",
},
{
"occurDate": now_to_ts(),
"patternId": "T1566.001",
"tactic": "initial-access",
"description": "Spearphishing Attachment",
},
]
for procedure in case_procedures:
hive.case.create_procedure(case_id=case_to_enrich["_id"], procedure=procedure)
The procedure entity requires occurDate
and patternId
as they are mandatory fields while tactic
and description
are optional.
To simplify the example we also used the helpers.now_to_ts function to generate a dummy timestamp for the procedures.