Skip to content

Classic Alerts

Introduction

The ClassicAlertMgr class of the classic_alerts module allows to fetch, search and update alerts coming from your Recorded Future enterprise.

With classic alerts we mean:

  • alerts related to the Recorded Future intelligence goal library
  • custom alerts created by you from the advanced query builder

See the API Reference for internal details of the module.

Notes

  1. The search, fetch and fetch_bulk methods all return a ClassicAlert object, or a list of them. If you want to look for new alerts you can use the search endpoint, while if you alert IDs and you need to lookup the alerts related to them, you will need to use the fetch (for very small number of IDs to lookup) or fetch_bulk (for bigger lookups).
  2. All the methods mentioned on point 1 accept a field parameter to increase or reduce the information retrieved for each alert. The following fields are always requested: id, log, title, rule no matter which field you specify.
    • search uses only the required fields by default if the fields parameter is not specified.
    • fetch and fetch_bulk use all the fields if the fields parameter is not specified. The more fields are requested the slower the action will be, make sure to balance the number of fields and the amount of alerts to search or fetch. A full list of fields can be found in the ALL_CA_FIELDS in the constants file for this module. Link

Examples

Warning

Below are some examples of usage of the module. Consider adding error handling as necessary. All the errors that can be raised by each method or function are specified in the API Reference page.

Also, you need to configure the RF_TOKEN environment variable before starting. See Learn.

Example 1: Search the latest new alerts and save them as markdown.

In order to search for newer alerts you can use the search method, with a -1d trigger time lookback. To further filter them out you can use the value of New for the status.

To build the markdown for alerts we need all the fields, so you can use the ALL_CA_FIELDS list to get them all. In the markdown method we can specify all some options to define a

from pathlib import Path

from psengine.classic_alerts import ClassicAlertMgr
from psengine.classic_alerts.constants import ALL_CA_FIELDS

OUTPUT_DIR = Path(__file__).parent / 'alerts'
OUTPUT_DIR.mkdir(exist_ok=True)

mgr = ClassicAlertMgr()
alerts = mgr.search(triggered='-1d', status='New', fields=ALL_CA_FIELDS)

for alert in alerts:
    markdown = alert.markdown(ai_insights=False, triggered_by=False, defang_iocs=True)
    (OUTPUT_DIR / f'{alert.id_}.md').write_text(markdown)

Tip

To replicate this example you will need to change the ALERT_IDS list with one or more ID of alerts that triggered in your enterprise. Either hardcode them, or use the search method shown above. For each alert found, the id_ attribute can be used to return the ID of that alert.

This example starts with the assumption that you have a list of alert IDs retrieved by a search, or a colleague or another integration/security tool. We will use only two alert IDs for demonstration.

In this example we use the fetch_bulk method to download the alerts. We use the max_workers=2 to split the task to two threads for faster performances.

The alerts might have an image ID in its payload, which will be collected by the fetch_all_images method. This method does not return the images but save them in a images property of the alert. If you need to access these images programmatically you can do that with alert.images.

save_images will save in OUTPUT_DIR a file .png for each image called: img:<image_id>.png

from pathlib import Path

from psengine.classic_alerts import ClassicAlertMgr
from psengine.classic_alerts.helpers import save_images

OUTPUT_DIR = Path(__file__).parent / 'alerts'
OUTPUT_DIR.mkdir(exist_ok=True)

ALERT_IDS = ['9Z0ts8', '9Z0ttT']

mgr = ClassicAlertMgr()
alerts = mgr.fetch_bulk(ALERT_IDS, max_workers=2)

for alert in alerts:
    mgr.fetch_all_images(alert)
    save_images(alert, OUTPUT_DIR)

Example 3: Fetch all the hits of an alert, and save the result as JSON file.

Tip

To replicate this example you will need to change the ALERT_IDS list with one or more ID of alerts that triggered in your enterprise. Either hardcode them, or use the search method shown above. For each alert found, the id_ attribute can be used to return the ID of that alert.

This example starts with the assumption that you have an alert ID retrieved by a search, or a colleague or another integration/security tool. We will use only two alert IDs for demonstration.

The fetch_hits method allows to download all the "Hits" of an alert, meaning the entities that triggered to alert to fire. The list of ClassicAlertHit objects returned by the fetch_hits is based on how many hits have triggered the alert. If more than one, you will see more than one object that have the same alert_id field. For this reason we are creating first a dictionary data where we group all the hits by alert_id. The usage of defaultdict is mainly to avoid if/else statements in the for loop.

Note that of each hit object we are using the json method. This method is available on any PSEngine created object and allows to dump it as JSON compatible dictionary.

Once the new data dictionary is populated we can save the content on file after transforming it to string with json.dumps.

import json
from collections import defaultdict
from pathlib import Path

from psengine.classic_alerts import ClassicAlertMgr

OUTPUT_DIR = Path(__file__).parent / 'alerts'
OUTPUT_DIR.mkdir(exist_ok=True)

ALERT_IDS = ['9Z0ts8', '9Z0ttT']

data = defaultdict(list)
mgr = ClassicAlertMgr()
hits = mgr.fetch_hits(ALERT_IDS)

for hit in hits:
    data[hit.alert_id].append(hit.json())

for alert_id, hits in data.items():
    (OUTPUT_DIR / f'{alert_id}.json').write_text(json.dumps(hits, indent=4))