Layered protection. Fortinet & Flowmon Networks
Recently, more and more companies are ripening to echeloned protection, when one solution protects the network perimeter, the other – end stations, the third constantly monitors the network, detecting anomalies, the fourth scans the network for unpatched vulnerabilities, and so on. At the same time, the need for various integrations is growing and it’s good when they are out of the box, that is, you don’t need to write complex scripts.
We recently wrote about the new TS Solution service – CheckFlow… This is a free audit of network traffic (both internal and external). Flowmon – a telemetry analysis and network monitoring solution that provides valuable information for both network administrators and security guards: anomalies, scans, illegitimate servers, loops, illegitimate interactions, network intrusions, zero-day attacks and much more.
I also recommend referring to article 9 common network problems that can be detected using analysis with Flowmon.
Integration Flowmon & FortiGate
Integration was mentioned in our blog… In general, it consists in the fact that the Next-Generation Firewall (such as FortiGate) protects the perimeter, and Flowmon monitors the network infrastructure, thereby giving the customer full network visibility. However, Flowmon can only detect, but not prevent attacks and anomalies, because it works on telemetry, which is obtained using Netflow / IPFIX. An NGFW or NAC (Network Access Control) solution can be used to quarantine a suspicious or infected host.
So, the vendor Flowmon released a shell script that, in response to security incidents, can perform the following actions on FortiGate:
- Block the infected host by IP address (IP Ban);
- Quarantine the host using FortiClient at MAC address (Quarantine with FortiClient);
- Dynamic quarantine for all infected hosts by MAC addresses (Access Layer Quarantine);
Setting up
1. I will not go into the details of the script itself, I will only say that there are two versions: one for FortiGate above version 6.4.0, the other for earlier versions. The code is shown below.
#!/bin/bash # Author: Jiri Knapek # Description: This script is to quarantine IP on Fortigate Firewalls for FortiOS before 6.4. # Version: 1.3 # Date: 8/3/2020 # Debug 1 = yes, 0 = no DEBUG=0 [ $DEBUG -ne 0 ] && echo `date` "Starting mitigation script" >> /tmp/fg-mitigation.log # Management IP/hostname of Firewall/ Core device IP='10.10.30.210' API_KEY='fp8114zdNpjp8Qf8zN4Hdp57dhgjjf' # Default timeout for action is # value in seconds or never TIMEOUT='300' # FortiGate API URL BAN="https://$IP/api/v2/monitor/user/banned/add_users?access_token=$API_KEY" function usage { cat << EOF >&2 usage: mitigation_script.shOptional: --fw IP / hostname of Fortigate firewall --timeout Timeout in seconds --key FortiGate API key EOF exit } params="$(getopt -o f:t:k:h -l fw:,timeout:,key:,help --name "mitigation_script.sh" -- "$@")" [ $DEBUG -ne 0 ] && echo `date` "Params $params" >> /tmp/fg-mitigation.log if [ $? -ne 0 ] then usage [ $DEBUG -ne 0 ] && echo `date` "Got to usage." >> /tmp/fg-mitigation.log fi eval set -- "$params" unset params while true do case $1 in -f|--fw) IP=("${2-}") shift 2 ;; -k|--key) API_KEY=("${2-}") shift 2 ;; -t|--timeout) TIMEOUT=("${2-}") shift 2 ;; -h|--help) usage ;; --) shift break ;; *) usage ;; esac done # we dont support any other args [ $# -gt 0 ] && { usage [ $DEBUG -ne 0 ] && echo `date` "INFO: Too many arguments. Got to usage." >> /tmp/fg-mitigation.log 2>&1 } cat << EOF >&2 ----- My params are ------------------ FW = $IP API KEY = $API_KEY TIMEOUT = $TIMEOUT TOKEN = $TOKEN --------------------------------------- EOF [ $DEBUG -ne 0 ] && cat >> /tmp/fg-mitigation.log << EOF >&2 ----- My params are ------------------ FW = $IP API KEY = $API_KEY TIMEOUT = $TIMEOUT TOKEN = $TOKEN --------------------------------------- EOF echo "Stdin read started..." >&2 LINE_NUM=1 array=() while read line do IFS=$'t' array=($line) echo "$LINE_NUM - ID ${array[0]} - type ${array[4]} - source ${array[10]}" [ $DEBUG -ne 0 ] && echo "$LINE_NUM - ID ${array[0]} - type ${array[4]} - source ${array[10]}" >> /tmp/fg-mitigation.log 2>&1 LINE_NUM=$((LINE_NUM+1)) # BAN the source IP of the event if [ $DEBUG -ne 0 ]; then /usr/bin/curl -k -X POST -H "Content-Type": "application/json" --data "{ "ip_addresses": ["${array[10]}"], "expiry": $TIMEOUT}" $BAN >> /tmp/fg-mitigation.log 2>&1 else /usr/bin/curl -k -X POST -H "Content-Type": "application/json" --data "{ "ip_addresses": ["${array[10]}"], "expiry": $TIMEOUT}" $BAN fi done < /dev/stdin echo "---- Everything completed ----" [ $DEBUG -ne 0 ] && echo `date` "---- Everything completed ----" >> /tmp/fg-mitigation.log
#!/bin/bash # Author: Jiri Knapek # Description: This script is to quarantine IP or MAC on Fortigate Firewalls and Security Fabric # Version: 2.0 # Date: 7/8/2020 # Debug 1 = yes, 0 = no DEBUG=0 [ $DEBUG -ne 0 ] && echo `date` "Starting mitigation script" >> /tmp/fg-mitigation.log # Flowmon API access USER='admin' PASS='admin' # Management IP/hostname of Firewall/ Core device IP='10.10.30.210' WEBHOOK='FlowmonADS' API_KEY='fp8114zdNpjp8Qf8zN4Hdp57dhgjjf' MAC=0 URL="https://$IP/api/v2/monitor/system/automation-stitch/webhook/$WEBHOOK" function usage { cat << EOF >&2 usage: mitigation_script.shOptional: --fw IP / hostname of Fortigate firewall --user Username to be used for Flowmon API authentication --pass Password for the user --key FortiGate API key --mac Add this parameter to enable MAC mitigation EOF exit } params="$(getopt -o f:u:p:k:h:m: -l fw:,key:,pass:,user:,help,mac: --name "mitigation_script.sh" -- "$@")" [ $DEBUG -ne 0 ] && echo `date` "Params $params" >> /tmp/fg-mitigation.log if [ $? -ne 0 ] then usage [ $DEBUG -ne 0 ] && echo `date` "Got to usage." >> /tmp/fg-mitigation.log fi eval set -- "$params" unset params while true do case $1 in -f|--fw) IP=("${2-}") shift 2 ;; -k|--key) API_KEY=("${2-}") shift 2 ;; -p|--pass) PASS=("${2-}") shift 2 ;; -u|--user) USER=("${2-}") shift 2 ;; -m|--mac) MAC=1 shift 2 ;; -h|--help) usage ;; --) shift break ;; *) usage ;; esac done # we dont support any other args [ $# -gt 0 ] && { usage [ $DEBUG -ne 0 ] && echo `date` "INFO: Got to usage." >> /tmp/fg-mitigation.log 2>&1 } if [ $MAC -ne 0 ]; then # authenticate to localhost OUTPUT="$(/usr/bin/curl "https://localhost/resources/oauth/token" -k -d 'grant_type=password' -d 'client_id=invea-tech' -d "username=$USER" -d "password=$PASS")" TOKEN="" echo "${OUTPUT}" > /tmp/access_token.json if [[ $OUTPUT == *"access_token"* ]]; then [ $DEBUG -ne 0 ] && echo `date` "Successfully authenticated to Flowmon Collector!" >> /tmp/fg-mitigation.log TOKEN="$(cat /tmp/access_token.json | jq '.access_token')" TOKEN="${TOKEN//"}" TOKEN="Authorization: bearer "$TOKEN fi fi cat << EOF >&2 ----- My params are ------------------ FW = $IP API KEE = $API_KEY URL = $URL MAC = $MAC TOKEN = $TOKEN --------------------------------------- EOF [ $DEBUG -ne 0 ] && /tmp/fg-mitigation.log << EOF >&2 ----- My params are ------------------ FW = $IP API KEE = $API_KEY URL = $URL MAC = $MAC TOKEN = $TOKEN --------------------------------------- EOF echo "Stdin read started..." >&2 LINE_NUM=1 array=() while read line do IFS=$'t' array=($line) echo "$LINE_NUM - ID ${array[0]} - type ${array[4]} - source ${array[10]}" [ $DEBUG -ne 0 ] && echo "$LINE_NUM - ID ${array[0]} - type ${array[4]} - source ${array[10]}" >> /tmp/fg-mitigation.log 2>&1 # Call a webhook if [ $MAC -ne 0 ]; then MAC_ADDR="$(/usr/bin/curl "https://localhost/rest/ads/event/${array[0]}" -G -k -H "$TOKEN" | jq '.macAddress')" if [ $DEBUG -ne 0 ]; then /usr/bin/curl -k -X POST -H "Authorization: Bearer $API_KEY" --data "{ "srcip": "${array[10]}", "mac": $MAC_ADDR, "fctuid": "A8BA0B12DA694E47BA4ADF24F8358E2F"}" $URL >> /tmp/fg-mitigation.log 2>&1 else /usr/bin/curl -k -X POST -H "Authorization: Bearer $API_KEY" --data "{ "srcip": "${array[10]}", "mac": $MAC_ADDR, "fctuid": "A8BA0B12DA694E47BA4ADF24F8358E2F"}" $URL fi else if [ $DEBUG -ne 0 ]; then /usr/bin/curl -k -X POST -H "Authorization: Bearer $API_KEY" --data "{ "srcip": "${array[10]}", "fctuid": "A8BA0B12DA694E47BA4ADF24F8358E2F"}" $URL >> /tmp/fg-mitigation.log 2>&1 else /usr/bin/curl -k -X POST -H "Authorization: Bearer $API_KEY" --data "{ "srcip": "${array[10]}", "fctuid": "A8BA0B12DA694E47BA4ADF24F8358E2F"}" $URL fi fi LINE_NUM=$((LINE_NUM+1)) done < /dev/stdin echo "---- Everything completed ----" [ $DEBUG -ne 0 ] && echo `date` "---- Everything completed ----" >> /tmp/fg-mitigation.log
2. I am using ForiGate version 6.4.3. In the script itself, on lines 13 and 14, you should add your username and password for Flowmonand also add API key from clause 5, FortiGate IP Address and Webhook name (the name of the automation engine).
3. In the FortiGate web interface, add in the tab Security Fabric> Automation> New Automation Stitch… Name – FlowmonADS, Status – Enabled, Trigger – Incoming Webhook, Action – IP BAN, Access Layer Quarantine, Quarantine with FortiCLient (if using).
4. Then you will see a window as in the screenshot below with the FortiGate URL for this Webhook, a field for the admin token API (we will create it later) and an example request.
5. Next, you need to create an administrator profile, which will have rights. Tab System> Admin Profiles> Create New…
6. Assign rights Security Fabric – Read, Firewall – Read / Write, System – Read / Write, Security Profile – Read / Write…
7. After in the tab System> Administrators create a new administrator with a profile api_admin… Optional in the field Trusted Hosts you can specify trusted networks or the IP address of the Flowmon.
Note: parameter Trusted Hosts allows you to hardcode segments of IP addresses from which api_admin will be able to send API requests to FortiGate, thus this is the recommended setting.
8. After this step, a API key, which must be added to the original script along with the other data specified in point 1 and in the webhook in point 4.
9. Next, go to Flowmon in the ADS (Anomaly Detection System) module in the tab System> System Settings> Custom Scripts> New Custom Script> Select file with extension .sh… Next, you need to set the parameters –fw (FortiGate IP address), –key (API token), –mac (nothing), –pass (password from REST API Flowmon), –user (REST API user Flowmon). Then press the button Save…
Note: –pass and –user by default admin / admin…
10. The final step is to establish the events to which the given program code will be triggered. In the tab Settings> Processing> Custom Scripts> New Custom Script Action the parameter should be changed Perspective on the Security Issues, set the threshold (Minimal priority to be reported) and check the parameters from the previous step.
Check
In case of triggering an event from the category Security Issues on Flowmon, FortiGate will block the given host. Further, in the convenient Quarantine widget, you can view potentially infected hosts by falling inside. Or through a command in the CLI diagnose user quarantine list…
After information security, the administrator can start investigating the incident using Flowmon ADS, identifying the initially infected host, through which ports the malware spreads and its behavior. With the help of solutions to protect workstations, for example, FortiEDR you can cure the car and conduct a security incident investigation.
In order to move a host out of quarantine, select it and click the button Remove…
Conclusion
The ubiquitous approach to defense in depth is pushing many vendors to integrate with other solutions out of the box. This article covered how to integrate, configure and demonstrate how Flowmon and FortiGate work together.
In the near future, we are planning a webinar, where we will tell in more detail how Flowmon and Fortinet complement each other, their integration with each other, and also answer your questions. Registration is available by link…
If you are interested in this topic, then stay tuned in our channels (Telegram, Facebook, VK, TS Solution Blog)!