Writing FortiSIEM Compatible FortiSOAR Playbooks

Introduction

Starting with 6.4.0, FortiSIEM provides the capability to adhoc execute FortiSOAR Playbooks and Connectors from the INCIDENTS page for individual incidents, or from the ANALYTICS page for individual events.

When FortiSIEM executes a Playbook, it provides the entire set of incident or raw event data , depending on execution from the INCIDENTS or ANALYTICS page respectively, as an argument to the Playbook in JSON format. The Playbook operates on that data, execute some actions, and returns the result to FortiSIEM.

For additional information on the FortiSOAR for FortiSIEM Integration solution, see here.

Sample playbooks are available here. This contains:

  • Playbook for getting IP address reputation via VirusTotal

  • Playbook for getting Domain reputation via VirusTotal, Anomali, FortiGuard, MX Toolbox, URLVoid, Alienvault OTX

  • Playbook for getting URL reputation via VirusTotal, Anomali, FortiGuard, MX Toolbox, URLVoid

  • Playbook for getting file hash reputation via VirusTotal

Prerequisites

In order to better understand the information here, it is recommended that you read the latest reference FortiSOAR Playbooks Guide under Reference Manuals first located here.

FortiSOAR Playbooks heavily use Jinja Templates. It is imperative that the Jinja template syntax is understood to design useful Playbooks. Jinja template designer documentation can be referenced here: https://jinja.palletsprojects.com/en/3.0.x/templates/

Playbooks and Connectors

A Playbook in FortiSOAR is a workflow that can be executed manually or automatically to complete some action within FortiSOAR itself, or to systems and applications in your environment. Playbooks can do entire chains of actions, while Connectors complete just one action at a time.

A Connector in FortiSOAR is an individual component integration to various FortiSOAR supported products. Playbooks can call multiple Connectors to create complex tasks. Every Connector can support one or more actions.

For example the Fortinet – FortiOS Connector can do the following actions on a FortiGate firewall, and return the response data to you:

  • Get Policy
  • Get Address Group
  • Get Blocked IP Addresses
  • Get Blocked URLs
  • Get Web Filter Profiles
  • Block IP Address
  • Block URL
  • Unblock URL
  • Unblock IP Address
  • Purge IP Block List
  • Execute Command

You can adhoc execute a Connector from FortiSIEM, supplying the necessary arguments for any given action. The arguments required vary based on the action being completed.

Some examples of a Playbook with respect to FortiSIEM:

  • An incident triggers in FortiSIEM, and you would like FortiSOAR to take that incident data, and do a reputation lookup of all the public IPs found in that incident.

  • An incident triggers in FortiSIEM, and you would like FortiSOAR to generate an Alert on FortiSOAR, and block the source IP found in the incident on a specific firewall in your network for 24 hours.

  • A raw event is observed in FortiSIEM on the ANALYTICS page by a security analyst, who decides to execute a Playbook that takes the following actions:

    • Disables the user observed in the event in Active Directory.

      and

    • Sends an email to the security team.

Some examples of a Connector execution from FortiSIEM:

  • A security analyst observes a malicious IP in an incident, and executes a connector to block the IP on a firewall as a singular action.

  • A security analyst observes suspicious behavior from a given user account in Active Directory, and executes the Active Directory > Disable User Account action on the account until further inspection can be completed.

Jinja and its Use in Playbooks

Jinja is a templating engine that can be used to build complex documents dynamically. FortiSOAR uses this in their Playbook design interface so you can process variable data sent to or from various functions, utilities, or connectors.

There are a few kinds of delimiters. The default Jinja delimiters are configured as follows:

For example, in a FortiSOAR Playbook, the Set Variable Action can use the {{…}} expression to assign the FortiSIEM JSON data into a list variable called data.

 

For another example, using the step function Utility -> Format as RichText (Markdown), you can format a variable as a string of text, but use statements to only display text if certain conditions match.

The example here will only display the string “There were no valid ip addresses available to gather reputation data” if the following variables do not exist:

If the 4 variables named above do not exist, a single line of text explains no result data was found, otherwise the rest of the data after the {% else %} statement is processed.

Building Custom Playbooks

With Playbooks you can build anything you like to complete any action.

As FortiSIEM incidents are generated, or raw events are parsed from various products, they each provide concrete sets of data to act on, either completing enrichment (looking up reputations), or taking some action such as disabling a user.

FortiSIEM sends this data over to a given Playbook in JSON format.

The FortiSIEM incident is in the following JSON format when supplied to a Playbook. The playbook can access argument data from FortiSIEM in the JSON variable {{vars.input.params['api_body']}}

Sample Incident JSON

{
      "user": null,
      "count": 30,
      "srcName": null,
      "tagName": null,
      "customer": null,
      "destName": null,
      "hostName": null,
      "phCustId": 1,
      "procName": null,
      "resource": null,
      "eventName": null,
      "eventType": "PH_RULE_DNS_THREATSTREAM_MALWARE_DOMAIN",
      "srcGeoOrg": null,
      "srcIpAddr": "192.0.2.0",
      "bizService": null,
      "destGeoOrg": null,
      "destIpAddr": null,
      "hostGeoOrg": null,
      "hostIpAddr": null,
      "incidentId": 993,
      "phRecvTime": 1634249820000,
      "reptGeoOrg": null,
      "srcGeoCity": null,
      "destGeoCity": null,
      "hostGeoCity": null,
      "incidentSrc": "srcIpAddr:192.0.2.0,",
      "rawEventMsg": null,
      "reptGeoCity": null,
      "srcGeoState": null,
      "activityName": null,
      "attackTactic": "Exfiltration",
      "destGeoState": null,
      "hostGeoState": null,
      "incidentReso": 1,
      "reptGeoState": null,
      "eventSeverity": 9,
      "incidentCount": 30,
      "incidentRptIp": "198.51.100.0",
      "incidentTitle": "DNS Traffic from 192.0.2.0 to Threat Stream Malware Domain example.net",
      "srcGeoCountry": null,
      "destGeoCountry": null,
      "hostGeoCountry": null,
      "incidentDetail": "",
      "incidentStatus": 0,
      "incidentTarget": "destName:example.net,",
      "reptGeoCountry": null,
      "srcGeoLatitude": null,
      "attackTechnique": "[{\"name\":\"Exfiltration Over Alternative Protocol: Exfiltration Over Symmetric Encrypted Non-C2 Protocol\",\"techniqueid\":\"T1048.001\"}]",
      "destGeoLatitude": null,
      "hostGeoLatitude": null,
      "incidentExtUser": null,
      "incidentTagName": null,
      "phEventCategory": 1,
      "reptGeoLatitude": null,
      "srcGeoLongitude": null,
      "destGeoLongitude": null,
      "eventSeverityCat": "HIGH",
      "hostGeoLongitude": null,
      "incidentComments": "test comment\n\n",
      "incidentLastSeen": 1634249820000,
      "incidentTicketId": null,
      "reptGeoLongitude": null,
      "attackTechniqueId": "T1048.001",
      "incidentFirstSeen": 1627508130000,
      "incidentNotiStatus": null,
      "incidentRptDevName": "HOST-198.51.100.0",
      "incidentTicketUser": null,
      "incidentViewStatus": 1,
      "phIncidentCategory": null,
      "incidentClearedTime": 0,
      "incidentClearedUser": null,
      "incidentExtTicketId": null,
      "incidentRptDevStatus": 1,
      "incidentTicketStatus": 6,
      "incidentClearedReason": null,
      "incidentExtTicketType": null,
      "phSubIncidentCategory": null,
      "incidentExtClearedTime": null,
      "incidentExtTicketState": null,
      "incidentNotiRecipients": ""
    }

 

Please note that depending on the type of FortiSIEM incident that fired, and the data used to populate that incident, the fields will contain various values. Your playbook must properly handle situations such as a field you need is blank, or properly extract data from a field that contains multiple values.

Similar to FortiSIEM Incidents, when executing a playbook on a FortiSIEM raw event, an entire copy of the parsed event attributes for that event is sent in JSON format, which looks like the following.

Sample Event JSON

{
   "count": "1", "opName": "New-InboxRule", "status": "True", "userId": "test.user@example.com", "eventId": "8263823841277690829", "srcName": "HOST-192.0.2.22", "customer": "Super", "phCustId": 1, "ruleName": "For all messages from test@email.com", "eventName": "create Inbox rules in mailboxes. Inbox rules process messages in the Inbox based on conditions and take actions such as moving a message to a specified folder or deleting a message", "eventType": "MS_OFFICE365_Exchange_New-InboxRule", "reptModel": "Office365", "srcIpAddr": "203.0.113.0", "srcIpPort": 11022, "deviceTime": 1624869759000, "parserName": "Office365Parser", "phRecvTime": 1635195584000, "reptVendor": "Microsoft", "srcGeoCity": "Cheshunt", "collectorId": "1", "eventSource": "Exchange", "reptDevName": "HOST-198.51.100.24", "srcGeoState": "England", "timeSkewSec": "10325825", "eventParsedOk": 1, "eventSeverity": 7, "reptDevIpAddr": "198.51.100.24", "srcGeoCountry": "United Kingdom of Great Britain and Northern Ireland", "relayDevIpAddr": "198.51.100.24", "senderMailAddr": "nobody@example.com", "srcGeoLatitude": "51.69989", "phEventCategory": "0 (External)", "srcGeoLongitude": "-0.02849", "eventRuleTrigger": 1, "eventSeverityCat": "MEDIUM", "extEventRecvProto": "Syslog", "office365UserType": "2 (An administrator)", "office365RecordType": "1 (ExchangeAdmin - Events from the Exchange admin audit log)", "stopProcessingRules": "True", "srcGeoCountryCodeStr": "GB" }

 

Please also note that the contents in the event will vary based on the source. The fields present in a Firewall session log are not the same as a Windows login event, and certain attributes are not guaranteed to always be present, which is vendor dependent. Your Playbooks should properly handle edge cases where expected values are not present when the Playbook is called.

When a Playbook is executed, the FortiSIEM argument data is accessible in the following variable:

{{vars.input.params['api_body']}}

You are then free to parse that JSON data into its individual attributes to complete an action. These attribute names in the JSON match the programmatic attribute names in FortiSIEM. These can be observed in the FortiSIEM UI by navigating to ADMIN > Device Support > Event Attributes.

Below are some common attributes.

Sample Attribute Names

{
    "eventType": "PH_RULE_DNS_THREATSTREAM_MALWARE_DOMAIN",
    "srcIpAddr": "192.0.2.0",
    "destIpAddr": "203.0.113.0",
    "incidentSrc": "srcIpAddr:192.0.2.0,",
    "attackTactic": "Exfiltration",
    "eventSeverity": 9,
    "incidentCount": 30,
    "incidentRptIp": "198.51.100.0",
    "incidentTitle": "DNS Traffic from 192.0.2.0 to Threat Stream Malware Domain westlady.net",
    "incidentTarget": "destName:westlady.net,",
    "attackTechnique": "[{\"name\":\"Exfiltration Over Alternative Protocol: Exfiltration Over Symmetric Encrypted Non-C2 Protocol\",\"techniqueid\":\"T1048.001\"}]",
    "eventSeverityCat": "HIGH",
    "incidentRptDevName": "HOST-198.51.100.0"
}

Custom Playbook Requirements – API Endpoint Specification

FortiSIEM compatible Playbooks all start with a Step type called “Custom API Endpoint”. FortiSOAR then creates a URI for that specific Playbook that can be called.

Example:

The get domain reputation Playbook creates a route called “/api/triggers/1/fsiem_api_get_domain_reputation”.

Authentication Method: Token-Based

FortiSIEM can then make API calls to this endpoint in the format

https://<fortisoar-hostname>/api/triggers/1/fsiem_api_get_domain_reputation

FortiSIEM Prebuilt Playbooks

FortiSIEM and FortiSOAR teams have provided a content pack installable in your FortiSOAR system with the following Playbooks, which are commonly used, but can also be a building block for your own custom Playbooks.

Content Pack Playbooks

  • fortisiem-get-domain-reputation
  • fortisiem-get-hash-reputation
  • fortisiem-get-url-reputation
  • fortisiem-get-ip-reputation-summary

Reference Playbooks

To support complex tasks completed by the above Playbooks, the following Playbooks are not called directly, and are only used by the above Playbooks (nested Playbooks) – Do not delete them, but do not call them directly.

  • fortisiem-reference-get-domain-rep
  • fortisiem-reference-get-hash-reputation
  • fortisiem-reference-get-url-rep
  • fortisiem-reference-validate-ip
  • fortisiem-reference-virustotal-summary

The naming convention of the playbooks are as follows:

<system>-<call method>-<purpose>

fortisiem – Indicates this is a Playbook for use by FortiSIEM only. Within the FortiSIEM UI, you can execute these Playbooks.

get or reference – get indicates this Playbook can be called by FortiSIEM. Reference indicates it is a reference Playbook and not called directly. **Never call a “reference” Playbook from FortiSIEM, these reference Playbooks are only called automatically from other Playbooks.

Playbook Tagging

It is required that every FortiSOAR Playbook that is designed to work with, and be called by FortiSIEM, should have a Playbook tag called “FortiSIEM” in case sensitive format. FortiSIEM may filter for Playbooks tagged in this way to avoid polling a list of all possible Playbooks.

Formatting Playbook Result Data back to FortiSIEM

Once FortiSIEM has successfully executed a FortiSOAR Playbook, and supplied either Incident or Raw event JSON data for the Playbook to operate on, it will wait for a JSON response.

This response data is dynamically configured within your Playbook. You can return any variables you’d like, but there are a few special variables that you should standardize in your Playbooks that FortiSIEM will display in the results screen.

FortiSIEM Special Playbook Response Variables

  • Summary – A string variable that shows high level result data from the execution of your Playbook. Short and high level.

  • Details – A string variable that shows detailed result data that may be more verbose.

For a demonstration, take a look at the Playbook: fortisiem-get-ip-reputation

We have a final Set Variable step called “AggregateOutput” where we format resulting variables.

We have a string formatting step result that is stored in a variable called “Summary”. FortiSIEM simply takes this particular variable and displays it prominently in the response UI for display and saving.

We also have a string formatting step result that is stored in a variable called “Detailed Summary”. As the name suggests, it is meant for more verbose data.

Only “Summary” should be considered a mandatory set variable, the others are optional and can be viewed in the GUI.

References

Playbooks Guide:  https://docs.fortinet.com/document/fortisoar/7.0.2/playbooks-guide

Connector Guide: https://docs.fortinet.com/document/fortisoar/7.0.2/connectors-guide

Jinja Template Designer Documentation: https://jinja.palletsprojects.com/en/3.0.x/templates/