The built-in rule management on the OPNSense is not only quite fast, it allows for pattern based enable/disable of rules via Policies. Truly, it is a good system and quite efficient! While this speed and control is useful, if you want to modify rules and resolve FPs in sometimes very needful and useful ways you generally will be after suricata-update and its disable/enable/drop/modify pattern matched and/or specific SIDs after download updated rule features.

Currently, and I want to see if I can help ‘enable’ this feature as a natural option (especially when an update happens to suricata-update allowing it to operate much faster), you must:

  • Create a script for ensuring conf files are maintained (only needed for now, once this reaches a higher maturity we should resolve use of the ‘custom.yaml’ Suricata config file)
  • Create a script for running suricata-update with flags and restarting Suricata if necessary
  • Disable the default IDS Rule Update Web GUI Cron entry
  • Create a new configd file for new Web GUI Cron entries (Suricata State, Suricata Update)
  • Maintain a small group of files (yaml/rules/conf) to attain a complete OPNSense + Suricata-Update expression

If you haven’t heard about “suricata-update”, but you might be familiar with “oinkmaster” or “pulled-pork” of what IDS gurus used to use with Snort, it of course works with Suricata and updates the rules ecosystem. It is also already installed in your OPNSense, so there’s really no new software/plug-in to install, you’ve already got the binaries/python bits.

This guide expects the user to be familiar with the OPNSense/FreeBSD/Linux to a point, and certainly able to get into the OPNSense Shell via SSH and to know how to create folders and files (you can get vim by pkg install vim). The scripts you will be creating do some logging to log file in the /root/ folder but attempts have been made to minimize the outputs.

This blog post will get updated and eventually will have a Github git repo with a default file set, possibly some updates to help setup and re-align the OPNSense – as of yet, I’m merely sharing how to get started.

That said, let’s go!

Disable Cron for OPNSense Policy based updates

Un-check the “enabled” box for the “IDS Rule Updates”, hit Save, then hit Apply

Create new actions configd Cron list file

This file will be located at:
/usr/local/opnsense/service/conf/actions.d/actions_homelab.conf

This does refer to two files we will be creating later. We need this file to list Cron entries on the OPNSense Web GUI.

actions_homelab.conf

[cfidsreload]
command: /root/suricatamod.sh; exit 0
parameters:
type:script
message:copy over and reload intrusion detection custom conf
description:Copy over and reload intrusion detection custom conf

[cfgidsupdate]
command: /root/suricataupdate.sh; exit 0
parameters:
type:script
message:download and update and mod suricata rules
description:Download and update and mod Suricata Rules

Update the configd service

To have the new Cron entries show up in the OPNSense Web GUI, you must restart the configd service, we will enable them later

service configd restart

Create custom file modification script

This file will be located at:
/root/suricatamod.sh

This does some work to keep the “custom.yaml” file and a few other file that enable the natural state of Suricata to work as expected. In short, the custom.yaml file gets over-wrote in some restart/rule update py script from OPNSense – so this would revert the file if it gets overwrote (such as it would by an update).

suricatamod.sh

#!/bin/sh

# Get current date and time
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")

# Define file paths
# Suricata config custom
ROOT_CUSTOM1="/root/suricata/custom.yaml"
SURICATA_CUSTOM1="/usr/local/etc/suricata/custom.yaml"
# Installed Rules File
ROOT_CUSTOM2="/root/suricata/installed_rules.yaml"
SURICATA_CUSTOM2="/usr/local/etc/suricata/installed_rules.yaml"
# Rules File
ROOT_RULES1="/root/suricata/novalabs.rules"
SURICATA_RULES1="/usr/local/etc/suricata/novalabs.yaml"
SURICATARULES_RULES1="/usr/local/etc/suricata/opnsense.rules/novalabs.yaml"
# Classification File
ROOT_CLASSIFICATION="/root/suricata/classification.config"
SURICATA_CLASSIFICATION1="/usr/local/share/suricata/rules/classification.config"
SURICATA_CLASSIFICATION2="/usr/local/share/suricata/classification.config"
SURICATA_CLASSIFICATION3="/usr/local/etc/suricata/classification.config"
SURICATA_CLASSIFICATION4="/usr/local/etc/suricata/opnsense.rules/classification.config"
# Extra - cannot use this file currently
SURICATA_TEMPLATE="/usr/local/opnsense/service/templates/OPNsense/IDS/custom.yaml"

# Start Logging
echo "$TIMESTAMP: File mod - Checking for configuration updates..." > /root/suricatamod.log

# Check for OPNSense running updates
script_name="rule-updater.py"
# Check if the script is running using ps
ps aux | grep "$script_name" | grep -v grep > /dev/null
if [ $? -eq 0 ]; then
  echo "$TIMESTAMP: File mod - Script '$script_name' is already running... exiting." >> /root/suricatamod.log
  exit 0 # Exit with a 0
else
  echo "$TIMESTAMP: File mod - Script '$script_name' is not running. Proceeding..." >> /root/suricatamod.log
fi
script_name="installRules.py"
# Check if the script is running using ps
ps aux | grep "$script_name" | grep -v grep > /dev/null
if [ $? -eq 0 ]; then
  echo "$TIMESTAMP: File mod - Script '$script_name' is already running... exiting." >> /root/suricatamod.log
  exit 0 # Exit with a 0
else
  echo "$TIMESTAMP: File mod - Script '$script_name' is not running. Proceeding..." >> /root/suricatamod.log
fi

# Check our files and fix them if necessary
RESTART_NEEDED="NO"
# Check if files are identical
if cmp -s "$ROOT_CUSTOM1" "$SURICATA_CUSTOM1"; then
  echo "$TIMESTAMP: File mod - $ROOT_CUSTOM1 / $SURICATA_CUSTOM1 Files are identical." >> /root/suricatamod.log
else
  echo "$TIMESTAMP: File mod - Different, copying $ROOT_CUSTOM1 to $SURICATA_CUSTOM1" >> /root/suricatamod.log
  cp "$ROOT_CUSTOM1" "$SURICATA_CUSTOM1"
  RESTART_NEEDED="YES"
fi
# Check if files are identical
if cmp -s "$ROOT_CUSTOM2" "$SURICATA_CUSTOM2"; then
  echo "$TIMESTAMP: File mod - $ROOT_CUSTOM2 / $SURICATA_CUSTOM2 Files are identical." >> /root/suricatamod.log
else
  echo "$TIMESTAMP: File mod - Different, copying $ROOT_CUSTOM2 to $SURICATA_CUSTOM2" >> /root/suricatamod.log
  cp "$ROOT_CUSTOM2" "$SURICATA_CUSTOM2"
  RESTART_NEEDED="YES"
fi
# Check if files are identical
if cmp -s "$ROOT_RULES1" "$SURICATA_RULES1"; then
  echo "$TIMESTAMP: File mod - $ROOT_RULES1 / $SURICATA_RULES1 Files are identical." >> /root/suricatamod.log
else
  echo "$TIMESTAMP: File mod - Different, copying $ROOT_RULES1 to $SURICATA_RULES1" >> /root/suricatamod.log
  cp "$ROOT_RULES1" "$SURICATA_RULES1"
  RESTART_NEEDED="YES"
fi
# Check if files are identical
if cmp -s "$ROOT_RULES1" "$SURICATARULES_RULES1"; then
  echo "$TIMESTAMP: File mod - $ROOT_RULES1 / $SURICATARULES_RULES1 Files are identical." >> /root/suricatamod.log
else
  echo "$TIMESTAMP: File mod - Different, copying $ROOT_RULES1 to $SURICATARULES_RULES1" >> /root/suricatamod.log
  cp "$ROOT_RULES1" "$SURICATARULES_RULES1"
  RESTART_NEEDED="YES"
fi
# Check if files are identical
if cmp -s "$ROOT_CLASSIFICATION" "$SURICATA_CLASSIFICATION1"; then
  echo "$TIMESTAMP: File mod - $ROOT_CLASSIFICATION / $SURICATA_CLASSIFICATION1 Files are identical." >> /root/suricatamod.log
else
  echo "$TIMESTAMP: File mod - Different, copying $ROOT_CLASSIFICATION to $SURICATA_CLASSIFICATION1" >> /root/suricatamod.log
  cp "$ROOT_CLASSIFICATION" "$SURICATA_CLASSIFICATION1"
  RESTART_NEEDED="YES"
fi
# Check if files are identical
if cmp -s "$ROOT_CLASSIFICATION" "$SURICATA_CLASSIFICATION2"; then
  echo "$TIMESTAMP: File mod - $ROOT_CLASSIFICATION / $SURICATA_CLASSIFICATION2 Files are identical." >> /root/suricatamod.log
else
  echo "$TIMESTAMP: File mod - Different, copying $ROOT_CLASSIFICATION to $SURICATA_CLASSIFICATION2" >> /root/suricatamod.log
  cp "$ROOT_CLASSIFICATION" "$SURICATA_CLASSIFICATION2"
  RESTART_NEEDED="YES"
fi
# Check if files are identical
if cmp -s "$ROOT_CLASSIFICATION" "$SURICATA_CLASSIFICATION3"; then
  echo "$TIMESTAMP: File mod - $ROOT_CLASSIFICATION / $SURICATA_CLASSIFICATION3 Files are identical." >> /root/suricatamod.log
else
  echo "$TIMESTAMP: File mod - Different, copying $ROOT_CLASSIFICATION to $SURICATA_CLASSIFICATION3" >> /root/suricatamod.log
  cp "$ROOT_CLASSIFICATION" "$SURICATA_CLASSIFICATION3"
  RESTART_NEEDED="YES"
fi
# Check if files are identical
if cmp -s "$ROOT_CLASSIFICATION" "$SURICATA_CLASSIFICATION4"; then
  echo "$TIMESTAMP: File mod - $ROOT_CLASSIFICATION / $SURICATA_CLASSIFICATION4 Files are identical." >> /root/suricatamod.log
else
  echo "$TIMESTAMP: File mod - Different, copying $ROOT_CLASSIFICATION to $SURICATA_CLASSIFICATION4" >> /root/suricatamod.log
  cp "$ROOT_CLASSIFICATION" "$SURICATA_CLASSIFICATION4"
  RESTART_NEEDED="YES"
fi

# Check if rule update in process
if [ -e /root/suricata/inRunSuricataUpdate ]; then
  echo "$TIMESTAMP: File mod - Rule update in progress, not restarting... exiting." > /root/suricataxtramod.log
  exit 0 # Exit with a 0
fi

# We are not updating rules, so let us restart Suricata
if [ "$RESTART_NEEDED" == "YES" ]; then
  #service suricata restart
  pkill -USR2 suricata
  echo "$TIMESTAMP: File mod - Suricata service restarted." >> /root/suricatarestart.log
fi  

exit 0

Be sure to “chmod +x /root/suricatamod.sh

Create suricata-update runner

This file will be located at:
/root/suricataupdate.sh

This runs the “suricata-update” python script with flags set for our OPNSense environment, it does a few checks to make sure it should run and if to restart Suricata or not.

suricataupdate.sh

#!/bin/sh

# Get current date and time
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")

# Check if I am already running
if [ ! -e /root/suricata/inRunSuricataUpdate ]; then
  touch /root/suricata/inRunSuricataUpdate
else
  echo "$TIMESTAMP: Rule update - I am already running... exiting." > /root/suricataxtrarules.log
  exit 0 # Exit with a 0
fi

# Define file paths
ROOT_CUSTOM1="/root/suricata/suricata.rules"
SURICATA_CUSTOM1="/usr/local/etc/suricata/opnsense.rules/suricata.rules"
echo "$TIMESTAMP: Rule update - Checking for rule updates..." > /root/suricatarules.log

script_name="rule-updater.py"
# Check if the script is running using ps
ps aux | grep "$script_name" | grep -v grep > /dev/null
if [ $? -eq 0 ]; then
  echo "$TIMESTAMP: Rule update - Script '$script_name' is already running... exiting." >> /root/suricatarules.log
  exit 0 # Exit with a 0
else
  echo "$TIMESTAMP: Rule update - Script '$script_name' is not running. Proceeding..." >> /root/suricatarules.log
fi

script_name="installRules.py"
# Check if the script is running using ps
ps aux | grep "$script_name" | grep -v grep > /dev/null
if [ $? -eq 0 ]; then
  echo "$TIMESTAMP: Rule update - Script '$script_name' is already running... exiting." >> /root/suricatarules.log
  exit 0 # Exit with a 0
else
  echo "$TIMESTAMP: Rule update - Script '$script_name' is not running. Proceeding..." >> /root/suricatarules.log
fi

# Backup existing rules
cp "$SURICATA_CUSTOM1" "$ROOT_CUSTOM1"

# Run suricata-update
suricata-update update --config /root/suricata/update.yaml --suricata-conf /usr/local/etc/suricata/suricata.yaml --suricata /usr/local/bin/suricata --data-dir /usr/local/etc/suricata --threshold-in=/root/suricata/threshold.in --threshold-out=/usr/local/etc/suricata/threshold.config --output /usr/local/etc/suricata/opnsense.rules -v --no-test --no-reload 2>&1 | tee /root/suricataupdate.log

# Make some check files to track the classtype to classification definitions
grep -Eo 'classtype:([^\;]+)' /usr/local/etc/suricata/opnsense.rules/suricata.rules | sed 's/classtype: /classtype:/g' | sort | uniq | cut -d':' -f2 > /root/suricata/classtype.list 
grep -Eo 'classification: ([^\,]+)' /root/suricata/classification.config | cut -d' ' -f2 | sort > /root/suricata/classification.list
echo "$TIMESTAMP: Rule update - ==New classtype needing classification==" >> /root/suricatarules.log
diff /root/suricata/classtype.list /root/suricata/classification.list | grep '<' >> /root/suricatarules.log
echo "$TIMESTAMP: Rule update - ========================================" >> /root/suricatarules.log

# Check for Suricata restart / reload condition
RESTART_NEEDED="NO"

# Check if files are identical
if cmp -s "$ROOT_CUSTOM1" "$SURICATA_CUSTOM1"; then
  echo "$TIMESTAMP: Rule update - $ROOT_CUSTOM1 Files are identical." >> /root/suricatarules.log
else
  echo "$TIMESTAMP: Rule update - Rules file is different, restarting Suricata" >> /root/suricatarules.log
  RESTART_NEEDED="YES"
fi

if [ "$RESTART_NEEDED" == "YES" ]; then
  #service suricata restart
  pkill -USR2 suricata
  echo "$TIMESTAMP: Rule update - Suricata service restarted." >> /root/suricatarestart.log
fi  

# Removing run check
rm /root/suricata/inRunSuricataUpdate

exit 0

Be sure to “chmod +x /root/suricataupdate.sh

Create Suricata-Update Folder for Yaml/Conf Files

Let’s create the folder and run a command to create our default Suricata-Update conf files.

mkdir /root/suricata
cd /root/suricata

Create suricata-update update.yaml file

This file will be located at:
/root/suricata/update.yaml

This configures suricata-update, and we specify our ‘snortrules’ grab here because I haven’t figured out how to get the suricata-upate for the “oinkcode” to work and this works.

update.yaml

# Configuration with disable filters.
disable-conf: /root/suricata/disable.conf

# Configuration with enable filters.
enable-conf: /root/suricata/enable.conf

# Configuration with drop filters.
drop-conf: /root/suricata/drop.conf

# Configuration with modify filters.
modify-conf: /root/suricata/modify.conf

# List of files to ignore. Overrided by the --ignore command line option.
ignore:
  - "*deleted.rules"

# Override the user-agent string.
#user-agent: "Suricata-Update"

# Provide an alternate command to the default test command.
#test-command: ${SURICATA_PATH} -T -S ${OUTPUT_FILENAME} -l /tmp

# Provide a command to reload the Suricata rules.
#reload-command: sudo systemctl reload suricata

# Remote rule sources. Simply a list of URLs.
sources:
  - "https://www.snort.org/rules/snortrules-snapshot-29111.tar.gz?oinkcode=aaaaaaaaaaaaaaaaaaredactedaaaaaaaaaaaaaa"

# A list of local rule sources. Each entry can be a rule file, a
# directory or a wild card specification.
local:
  - "/root/suricata/homelab.rules"

Create your homelab.rules file to bypass / home rule

This will be located at:
/root/suricata/homelab.rules

This is a great place to get your IDS to focus on the important by NOT focusing on the unimportant, a pass+bypass rule on host paths that you do not want inspected will lower CPU utilization and cost!

homelab.rules

pass ip $GAMING_HOSTS any -> any any (msg:"Gaming Hosts"; bypass; sid:1000001; rev:1;)
pass ip any any -> $GAMING_HOSTS any (msg:"Gaming Hosts"; bypass; sid:1100001; rev:1;)

Create your custom.yaml file to customize suricata further

This file will be located at:
/root/suricata/custom.yaml

We have talked about this file before on this site, here we mention it because this is how you will get your “address-groups” to us in your rules. In our example scripts here, we have setup a “Gaming Hosts” group to be bypassed in our “homelab.rules” and/or your could use “modify.conf” and change the text of “$HOME_NET” in rules to “[$HOME_NET, !$GAMING_HOSTS]” and thus ignore those hosts. No more False Positives on from those hosts!

custom.yaml

%YAML 1.1
---
vars:
  address-groups:
    HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]"
    EXTERNAL_NET: "!$HOME_NET"
    HTTP_SERVERS: "$HOME_NET"
    SMTP_SERVERS: "$HOME_NET"
    SQL_SERVERS: "$HOME_NET"
    DNS_SERVERS: "$HOME_NET"
    TELNET_SERVERS: "$HOME_NET"
    AIM_SERVERS: "$EXTERNAL_NET"
    DC_SERVERS: "$HOME_NET"
    DNP3_SERVER: "$HOME_NET"
    DNP3_CLIENT: "$HOME_NET"
    MODBUS_CLIENT: "$HOME_NET"
    MODBUS_SERVER: "$HOME_NET"
    ENIP_CLIENT: "$HOME_NET"
    ENIP_SERVER: "$HOME_NET"
    SIP_SERVERS: "$HOME_NET"
    INTERNAL_DEVICELIST: "[10.30.16.41,10.30.16.42,10.30.16.43]"
    GAMING_HOSTS: "[10.40.1.2,10.40.1.3]"
  port-groups:
    HTTP_PORTS: "[80,8080]"
    SHELLCODE_PORTS: "!80"
    ORACLE_PORTS: 1521
    SSH_PORTS: 22
    DNP3_PORTS: 20000
    MODBUS_PORTS: 502
    FILE_DATA_PORTS: "[$HTTP_PORTS,110,143]"
    FTP_PORTS: 21
    GENEVE_PORTS: 6081
    VXLAN_PORTS: 4789
    TEREDO_PORTS: 3544
    SIP_PORTS: "[5060,5061]"
outputs:
  - eve-log:
      enabled: yes
      filetype: regular #regular|syslog|unix_dgram|unix_stream|redis
      filename: evexff.json
      xff:
        enabled: yes
        mode: overwrite
        deployment: reverse
        header: X-Forwarded-For
      types:
        - alert:
            payload: no
            payload-buffer-size: 100kb
            payload-printable: no
            metadata: yes             # enable inclusion of app layer metadata with alert. Default yes
            tagged-packets: yes
  - eve-log:
      enabled: yes
      filetype: regular #regular|syslog|unix_dgram|unix_stream|redis
      filename: eve.json
      pcap-file: false
      community-id: true
      community-id-seed: 0
      xff:
        enabled: yes
        mode: extra-data
        deployment: reverse
        header: X-Forwarded-For
      types:
        - alert:
            payload: no
            payload-buffer-size: 100kb
            payload-printable: yes
            metadata:
              app-layer: true
              flow: true
              rule:
                metadata: true
                raw: true
            tagged-packets: yes
        - alert:
            payload: yes
            payload-buffer-size: 100kb
            payload-printable: yes
            metadata: yes             # enable inclusion of app layer metadata with alert. Default yes
            metadata:
              app-layer: true
              rule:
                metadata: true
                raw: true
            tagged-packets: yes
        - frame:
            enabled: no
        - anomaly:
            enabled: no
  - eve-log:
      enabled: yes
      type: syslog
      identity: "suricata"
      facility: local5
      level: Info
      community-id: true
      community-id-seed: 0
      xff:
        enabled: yes
        mode: extra-data
        deployment: reverse
        header: X-Forwarded-For
      types:
        - alert:
            payload: no
            payload-buffer-size: 100kb
            payload-printable: yes
            metadata:
              app-layer: true
              flow: true
              rule:
                metadata: true
                raw: true
            tagged-packets: yes
        - frame:
            enabled: no
        - anomaly:
            enabled: no
            types:
              applayer: no
  - unified2-alert:
      enabled: no
  - http-log:
      enabled: no
      filename: http.log
      append: yes
  - tls-log:
      enabled: no  # Log TLS connections.
      filename: tls.log # File to store TLS logs.
      append: yes
  - tls-store:
      enabled: no
  - pcap-log:
      enabled: no
      filename: log.pcap
      limit: 1000mb
      max-files: 2000
      compression: none
      mode: normal # normal, multi or sguil.
      use-stream-depth: no #If set to "yes" packets seen after reaching stream inspection depth are ignored. "no" logs all packets
      honor-pass-rules: no # If set to "yes", flows in which a pass rule matched will stop being logged.
  - alert-debug:
      enabled: no
      filename: alert-debug.log
      append: yes
  - alert-prelude:
      enabled: no
      profile: suricata
      log-packet-content: no
      log-packet-header: yes
  - stats:
      enabled: yes
      filename: stats.log
      append: yes       # append to file (yes) or overwrite it (no)
      totals: yes       # stats for all threads merged together
      threads: no       # per thread stats
  - file-store:
      version: 2
      enabled: no
      xff:
        enabled: no
        mode: extra-data
        deployment: reverse
        header: X-Forwarded-For
  - file-store:
      enabled: no
  - tcp-data:
      enabled: no
      type: file
      filename: tcp-data.log
  - http-body-data:
      enabled: no
      type: file
      filename: http-data.log
  - lua:
      enabled: no
      scripts:
app-layer:
  protocols:
    telnet:
      enabled: yes
    rfb:
      enabled: yes
      detection-ports:
        dp: 5900, 5901, 5902, 5903, 5904, 5905, 5906, 5907, 5908, 5909
    mqtt:
      enabled: yes
    krb5:
      enabled: yes
    bittorrent-dht:
      enabled: yes
    snmp:
      enabled: yes
    ike:
      enabled: yes
    tls:
      enabled: yes
      detection-ports:
        dp: 443
      ja3-fingerprints: auto
    pgsql:
      enabled: yes
      stream-depth: 0
      max-tx: 1024
    dcerpc:
      enabled: yes
    ftp:
      enabled: yes
    rdp:
    ssh:
      enabled: yes
    http2:
      enabled: yes
    smtp:
      enabled: yes
      raw-extraction: no
      mime:
        decode-mime: yes
        decode-base64: yes
        decode-quoted-printable: yes
        header-value-depth: 2000
        extract-urls: yes
        body-md5: no
      inspected-tracker:
        content-limit: 100000
        content-inspect-min-size: 32768
        content-inspect-window: 4096
    imap:
      enabled: detection-only
    smb:
      enabled: yes
      detection-ports:
        dp: 139, 445
    nfs:
      enabled: yes
    tftp:
      enabled: yes
    dns:
      tcp:
        enabled: yes
        detection-ports:
          dp: 53
      udp:
        enabled: yes
        detection-ports:
          dp: 53
    http:
      enabled: yes
      libhtp:
         default-config:
           personality: IDS
           request-body-limit: 100kb
           response-body-limit: 100kb
           request-body-minimal-inspect-size: 32kb
           request-body-inspect-window: 4kb
           response-body-minimal-inspect-size: 40kb
           response-body-inspect-window: 16kb
           response-body-decompress-layer-limit: 2
           http-body-inline: auto
           swf-decompression:
             enabled: no
             type: both
             compress-depth: 100kb
             decompress-depth: 100kb
           double-decode-path: no
           double-decode-query: no
         server-config:
    modbus:
      enabled: yes
      detection-ports:
        dp: 502
      stream-depth: 0
    dnp3:
      enabled: yes
      detection-ports:
        dp: 20000
    enip:
      enabled: yes
      detection-ports:
        dp: 44818
        sp: 44818
    ntp:
      enabled: yes
    quic:
      enabled: yes
    dhcp:
      enabled: yes
    sip:
      enabled: yes
asn1-max-frames: 256
datasets:
  defaults:
  rules:
host-os-policy:
  windows: []
  bsd: []
  bsd-right: []
  old-linux: []
  linux: []
  old-solaris: []
  solaris: []
  hpux10: []
  hpux11: []
  irix: []
  macos: []
  vista: []
  windows2k3: []
netmap:                                                                         
 - interface: default                                                           
   threads: auto                                                                
   copy-mode: ips                                                               
   disable-promisc: no #  promiscuous mode                                      
   checksum-checks: auto                                                        
   bpf-filter: not (( host 10.30.1.6 or 10.30.1.3 ) or ( net 10.30.14.0/24 or 10.30.21.0/24 ))
 - interface: vlan0.1.10
   copy-iface: vlan0.1.10^
 - interface: vlan0.1.10^
   copy-iface: vlan0.1.10
 - interface: vlan0.1.50
   copy-iface: vlan0.1.50^
 - interface: vlan0.1.50^
   copy-iface: vlan0.1.50
 - interface: igb0
   copy-iface: igb0^
 - interface: igb0^
   copy-iface: igb0
 - interface: ix1
   copy-iface: ix1^
 - interface: ix1^
   copy-iface: ix1
default-rule-path: /usr/local/etc/suricata/opnsense.rules
rule-files:
  - suricata.rules
classification-file: /usr/local/etc/suricata/classification.config
reference-config-file: /usr/local/etc/suricata/reference.config
threshold-file: /usr/local/etc/suricata/threshold.config

Create a new “installed_rules.yaml” and

This file will be located at:
/root/suricata/installed_rules.yaml

This insures that our “suricata.rules” file is used as expected and our “homelab.rules” is referenced, this step might not be as necessary as it was initially for me, but I leave it here to ensure success.

installed_rules.yaml

%YAML 1.1
---
rule-files:
  - suricata.rules
  - builtin.rules
  - homelab.rules

Copy “installed_rules.yaml” to Suricata’s directory

cp /root/suricata/installed_rules.yaml /usr/local/etc/suricata/installed_rules.yaml

Create disable/enable/drop/modify default conf files

cd /root/suricata
suricata-update --dump-sample-configs

Enable Suricata Update Sources

Update your Suricata sources:

suricata-update update-sources --config /root/suricata/update.yaml --suricata-conf /usr/local/etc/suricata/suricata.yaml --suricata /usr/local/bin/suricata --data-dir /usr/local/etc/suricata

List the available rule update sources:

suricata-update list-sources --config /root/suricata/update.yaml --suricata-conf /usr/local/etc/suricata/suricata.yaml --suricata /usr/local/bin/suricata --data-dir /usr/local/etc/suricata

Enable a source, in this example “et/open”:

suricata-update enable-source et/open --config /root/suricata/update.yaml --suricata-conf /usr/local/etc/suricata/suricata.yaml --suricata /usr/local/bin/suricata --data-dir /usr/local/etc/suricata

List all enabled sources:

suricata-update list-sources --enabled --config /root/suricata/update.yaml --suricata-conf /usr/local/etc/suricata/suricata.yaml --suricata /usr/local/bin/suricata --data-dir /usr/local/etc/suricata

Create new Web GUI Cron Entries

Go to System > Settings > Cron and create the following entries:

In Edit job, check-mark “enabled”, set minutes to a high frequency (*/5 or */10), the rest of time fields at “*“, and select “Copy over and reload intrusion detection custom…” as the Command, enter your own Description, hit “Save”

In Edit job, check-mark “enabled”, set to multiple times a day (*/6 for 4 times a day) putting a minute in and “*” for the rest of the time fields, and set Command to “Download and update and mod Suricata Rules”, enter your own Description, hit “Save”, then hit “Apply”

Create the classification.conf file

If you are using CrowdSec and watching your Suricata logs/evelogs, I suggest this file to update the priority/classification of your rules, this is a bit more open but can be locked down by setting 2->1, and 3->2 and so on.

This file will be located at:
/root/suricata/classification.conf

classification.conf

# config classification:shortname,short description,priority
config classification: not-suspicious,Not Suspicious Traffic,3
config classification: unknown,Unknown Traffic,3
config classification: bad-unknown,Potentially Bad Traffic, 2
config classification: attempted-recon,Attempted Information Leak,2
config classification: successful-recon-limited,Information Leak,2
config classification: successful-recon-largescale,Large Scale Information Leak,2
config classification: attempted-dos,Attempted Denial of Service,2
config classification: successful-dos,Denial of Service,2
config classification: attempted-user,Attempted User Privilege Gain,1
config classification: unsuccessful-user,Unsuccessful User Privilege Gain,1
config classification: successful-user,Successful User Privilege Gain,1
config classification: attempted-admin,Attempted Administrator Privilege Gain,1
config classification: successful-admin,Successful Administrator Privilege Gain,1

# NEW CLASSIFICATIONS
config classification: rpc-portmap-decode,Decode of an RPC Query,2
config classification: shellcode-detect,Executable code was detected,3
config classification: string-detect,A suspicious string was detected,3
config classification: suspicious-filename-detect,A suspicious filename was detected,2
config classification: suspicious-login,An attempted login using a suspicious username was detected,2
config classification: system-call-detect,A system call was detected,2
config classification: tcp-connection,A TCP connection was detected,4
config classification: trojan-activity,A Network Trojan was detected,2
config classification: unusual-client-port-connection,A client was using an unusual port,3
config classification: network-scan,Detection of a Network Scan,2
config classification: denial-of-service,Detection of a Denial of Service Attack,2
config classification: non-standard-protocol,Detection of a non-standard protocol or event,3
config classification: protocol-command-decode,Generic Protocol Command Decode,3
config classification: web-application-activity,access to a potentially vulnerable web application,2
config classification: web-application-attack,Web Application Attack,1
config classification: misc-activity,Misc activity,3
config classification: misc-attack,Misc Attack,3
config classification: icmp-event,Generic ICMP event,3
config classification: inappropriate-content,Inappropriate Content was Detected,3
config classification: policy-violation,Potential Corporate Privacy Violation,3
config classification: default-login-attempt,Attempt to login by a default username and password,2

# Update
config classification: targeted-activity,Targeted Malicious Activity was Detected,1
config classification: exploit-kit,Exploit Kit Activity Detected,1
config classification: external-ip-check,Device Retrieving External IP Address Detected,3
config classification: domain-c2,Domain Observed Used for C2 Detected,1
config classification: pup-activity,Possibly Unwanted Program Detected,2
config classification: credential-theft,Successful Credential Theft Detected,1
config classification: social-engineering,Possible Social Engineering Attempted,3
config classification: coin-mining,Crypto Currency Mining Activity Detected,3
config classification: command-and-control,Malware Command and Control Activity Detected,1
config classification: sdf,Sensitive Data File Content Detected,3

# OPNsense rules
config classification: file-transfer,File-Transfer app detection by OPNsense,3
config classification: mail,Mailprovider app detection by OPNsense,3
config classification: media-streaming,Media-Streaming app detection by OPNsense,3
config classification: messaging,Messenger app detection by OPNsense,3
config classification: social-media,Social-Media app detection by OPNsense,3
config classification: test,OPNsense Test Rules,3
config classification: uncategorized,Uncategorized app detection by OPNsense,3

Copy this file to Suricata folder

cp /root/suricata/classification.config /usr/local/etc/suricata/classification.config

Get faster Suricata-Update Processing

Get a “python” executable as ‘suricata-update’ looks for Python not Python3:
ln -s /usr/local/bin/python3 /usr/local/bin/python

Then clone the Git repo:
git clone https://github.com/OISF/suricata-update.git

Then update the ‘suricata-update update’ command from the ‘suricataupdate.sh’ script to be using the Python Module from the Git Repo (this is the new line):
/root/suricata-update/bin/suricata-update update --config /root/suricata/update.yaml --suricata-conf /usr/local/etc/suricata/suricata.yaml --suricata /usr/local/bin/suricata --data-dir /usr/local/etc/suricata --threshold-in=/root/suricata/threshold.in --threshold-out=/usr/local/etc/suricata/threshold.config --output /usr/local/etc/suricata/opnsense.rules -v --no-test --no-reload | tee /root/suricataupdate.log

Soon I will share some suggested disable/enable/drop/modify configs, but at this time I am still changing my too often to want to publish here. Further, I don’t expect to be checking out the drop element until a later day – focusing on disable, enable, and modify for now.

Best of luck, please comment and suggest updates/fixes if necessary!

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.