Today we're looking at the new FortiSIEM JSON Incident API. Need to extract some incident data from your FortiSIEM? This API's for you!
Let's explore one of the API functions by building a simple Bash script that pulls recent incidents and summarizes the target IP.
Disclaimer
This is a basic, stripped back 'Proof of Concept' script. It's provided as is and for informational purposes only. Some features, such as hard-coded credentials, are not considered best practice and you probably have a better approach. Be sure to check, fix, validate data, handle errors, improve, customize and secure to meet your own requirements before use.
Formatting
Some of the longer commands may be word-wrapped on your screen, which could prevent them working if you copy/ paste the script without fixing this.
Preparation
Assuming you are using a CentOS based distribution run the following command to check and install required packages if needed:
yum -y install curl jq sed grep
API Endpoint
The API details are published here:
https://docs.fortinet.com/document/fortisiem/6.3.0/integration-api-guide/895612/json-api-incident-in...We are using the following API endpoint for this exercise: /phoenix/rest/pub/incident
We're only using one of the API functions. The API also supports pulling triggering events and updating incidents for integration work. Check out the documentation for more information.
cURL Request
The basic cURL format to request all incidents for a specific time window from this API is:
curl -k -s --user 'super/<user>:<password>' "https://<super-ip>/phoenix/rest/pub/incident?timeFrom=<time-in-epoch-ms>&timeTo=<time-in-epoch-ms>"
The time is in Unix epoch format
including milliseconds! Let's look at how to get this in Bash:
The current epoch time is given by
date +%s
Assign this to a variable and append '000' to convert to milliseconds:
timeTo=`date +%s`000
The other side of the time window, timeFrom, is given by subtracting the number of milliseconds in the time period from the timeTo value. For example to get the incidents for the past 1 day subtract 1*24*60*60*1000 = 86400000 from timeTo:
timeFrom=`expr $timeTo - 86400000`
Let's put this together into a bash script that grabs the incident information for the past day into a variable called 'incidents'. Populate the IP, user and password variables for your environment:
#! /bin/bash
# Populate these variables with your systems values
superIp="192.168.1.20"
user="enterUsernameHere"
pass="enterPasswordHere"
timeTo=`date +%s`000
timeFrom=`expr $timeTo - 86400000`
#Make sure the next command is on a single line in your script
incidents=`curl -k -s --user "super/$user:$pass" "https://$superIp/phoenix/rest/pub/incident?timeFrom=$timeFrom&timeTo=$timeTo"`
Tip - as we are processing this on the Bash command line, don’t use any characters that may be interpreted by Bash (e.g. $ " or ') in your username or password.
Processing the Response
Now $incidents contains a JSON formatted string of our incident data. Let's process it using jq, which is a powerful tool for processing JSON.
First, check the data structure. Add this line to the script and run it to print the entire data structure:
echo $incidents | jq .
The response is in this format:
{
"total": 5,
"size": 5,
"data": [
{
"incidentTitle": "High Severity IPS Exploit FortiGate-ips-signature-39417 from 10.100.88.2 to 96.45.33.79",
"eventSeverity": 9,
"incidentFirstSeen": 1629973590000,
"incidentReso": 1,
"incidentRptIp": "10.100.88.1",
"incidentLastSeen": 1629973620000,
"incidentSrc": "srcIpAddr:10.100.88.2,",
"count": 2,
- Snip -
Meaning each incident is in the 'data' object. We can use the jq inbuilt 'length' function to count the number of returned incidents:
count=`echo $incidents | jq '.data | length'`
And use this value in a for loop to extract data and build an array
# create an array to store the results
declare -A targets
# count through incidents using the count variable populated in the last step
for ((i=0; i < count; i++))
do
# send the incidentTarget string from each incidents to grep to extract an IP address
targetIp=`echo $incidents | jq .data[$i].incidentTarget | grep -o -P '(\d{1,3}\.){3}(\d{1,3})'`
# if an IP is found then add it to the array targets. Increment if already present.
if [[ $targetIp ]]
then
targets[$targetIp]=`expr ${targets[$targetIp]} + 1`
fi
done
Finally, lets print the output:
# print title line
echo "Target IP [Count]"
echo "-----------------"
#for each key in the array targets, print the key and value
for i in ${!targets[@]}
do
echo "$i [${targets[$i]}]"
done
Here's what the output looks like. Not all incidents have an associated IP, so the total number of IP's might be less than the total number of incidents.
The Full Script
#! /bin/bashsuperIp="192.168.1.20"user="enterUsernameHere"pass="enterPasswordHere"timeTo=`date +%s`000timeFrom=`expr $timeTo - 86400000`incidents=`curl -k -s --user "super/$user:$pass" "https://$superIp/phoenix/rest/pub/incident?timeFrom=$timeFrom&timeTo=$timeTo"`# Uncomment the next line to see the JSON data# echo $incidents | jq .count=`echo $incidents | jq '.data | length'`echo ""echo "== FortiSIEM Incident API Demo =="echo ""echo "Total Incidents Retrieved: $count"echo ""declare -A targetsfor ((i=0; i < count; i++))dotargetIp=`echo $incidents | jq .data[$i].incidentTarget | grep -o -P '(\d{1,3}\.){3}(\d{1,3})'`if [[ $targetIp ]]thentargets[$targetIp]=`expr ${targets[$targetIp]} + 1`fidoneecho "Target IP [Count]"echo "-----------------"for i in ${!targets[@]}doecho "$i [${targets[$i]}]"done
References
JSON API Incident Integration. Available at
https://docs.fortinet.com/document/fortisiem/6.3.0/integration-api-guide/895612/json-api-incident-in... (Accessed 26 Aug 2021)
The Linux Documentation Project. Available at
https://tldp.org/ (Accessed 26 August 2021)
Bash Reference Manual. Available at
https://www.gnu.org/software/bash/manual/bash.pdf (Accessed 26 August 2021)
How to Parse JSON Files on the Linux Command Line with jq. Available at
https://www.howtogeek.com/529219/how-to-parse-json-files-on-the-linux-command-line-with-jq/ (Accessed 26 August 2021)