Skip to content

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.