This is a follow up to my last post in which I described how to setup suricata as a IPS which bridges traffic between two interfaces using af-packet (and all that in a virtual machine). Here I’m showing how to work with suricata in general – or rather – how I work with suricata.
Setup / Configuration additions
tcmalloc
There seem to be some performance and memory usage improvements when you use libtcmalloc. You can install it by issuing:
apt-get install libtcmalloc-minimal4
Then edit the systemd script for example using systemctl edit suricata and write the following Service-Definition into it so that suricata uses libtcmalloc_minimal.so.4:
~# cat /etc/systemd/system/suricata.service.d/override.conf
[Service]
Environment="LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc_minimal.so.4"
suricata-update
To be honest I was a little bit confused about the way the files and folders were available after installation in Debian 12 (Bookworm). According to the documentation there should have been an update.yaml. Then if you issue suricata-update it will place it’s rules to /var/lib/suricata/rules – But in debian they’re loaded from /etc/suricata/rules. Now some guides show to use suricata-update -o /etc/suricata/rules… So you download all the rules once and never update them because the update location is in /var/lib/suricata/rules if you don’t change this…
Shall we fix this?
First let’s get the update.yaml:
cp /usr/lib/python3/dist-packages/suricata/update/configs/update.yaml update.yaml
As explained before, suricata-update, unless you tell it differently loads its rules from /var/lib/suricata/rules. However. In Debian it loads them from /etc/suricata/rules. Hence modify suricata.yaml:
default-rule-path: /var/lib/suricata/rules
Now edit the following part in your update.yaml:
# A list of local rule sources. Each entry can be a rule file, a
# directory or a wild card specification.
local:
# A directory of rules.
- /etc/suricata/rules
# A single rule file.
#- /etc/suricata/rules/app-layer-events.rules
# A wildcard.
# - /etc/suricata/rules/*.rules
Also add the rules you like using suricata-update enable-source (do a update-sources and list-source first) and comment the sources in update.yaml:
# Remote rule sources. Simply a list of URLs.
sources:
# Emerging Threats Open with the Suricata version dynamically replaced.
# - https://rules.emergingthreats.net/open/suricata-%(__version__)s/emerging.rules.tar.gz
# The SSL blacklist, which is just a standalone rule file.
# - https://sslbl.abuse.ch/blacklist/sslblacklist.rules
You may also want to remove all rules from /etc/suricata/rules to not get duplicate-rules messages when updating the rules.
Suricata not blocking anything
Indeed, by default Suricata does not block anything. This is not a bug. Check the rules:
# grep "^reject" *
# grep "^drop" *
stream-events.rules:drop tcp any any -> any any (msg:"SURICATA STREAM 3way handshake toclient data injection suspected"; flow:to_client; stream-event:3whs_ack_data_inject; classtype:protocol-command-decode; sid:2210057; rev:1;)
suricata.rules:drop tcp any any -> any any (msg:"SURICATA STREAM 3way handshake toclient data injection suspected"; flow:to_client; stream-event:3whs_ack_data_inject; classtype:protocol-command-decode; sid:2210057; rev:1;)
There is only one rule which would in fact block (Drop). All the other rules will just alert. Pretty much like an IDS should work. Let’s take a look at what I get:
# awk '{$1=""; $2=""; $3=""}1' fast.log | sed 's_\[\*\*\].*__g' | sed 's_ group [0-9]*__g' | sort | uniq -c | sort -h
[..]
100 GPL RPC portmap listing UDP 111
103 SURICATA STREAM 3way handshake excessive different SYN/ACKs
176 ET SCAN Suspicious inbound to PostgreSQL port 5432
216 ET SCAN Suspicious inbound to mySQL port 3306
223 SURICATA UDPv4 invalid checksum
236 SURICATA STREAM Last ACK with wrong seq
241 GPL ICMP_INFO PING speedera
325 ET SCAN Suspicious inbound to MSSQL port 1433
333 SURICATA SMTP no server welcome message
431 ET SCAN LibSSH Based Frequent SSH Connections Likely BruteForce Attack
488 SURICATA STREAM excessive retransmissions
520 ET COMPROMISED Known Compromised or Hostile Host Traffic
1094 ET INFO SSH-2.0-Go version string Observed in Network Traffic - Inbound
1115 SURICATA Applayer Detect protocol only one direction
1413 ET SCAN Potential SSH Scan
1470 ET 3CORESec Poor Reputation IP
4933 SURICATA TCPv4 invalid checksum
5576 ET CINS Active Threat Intelligence Poor Reputation IP
10309 ET DROP Dshield Block Listed Source
12872 GPL ICMP_INFO PING *NIX
I am pretty sure you’ll find a more nice command (Scroll down – I wrote another better one) to put together this list. I used awk to remove the first three columns of the log, sed to remove everything after [**] and sed to remove the group XX part. This allows sorting, which allows uniq -c to count the occurences and that can be sorted in a way that we get the above list. However. For a quick look the above should be fine.
Also, depending on the size of your logfiles you might not be able to use the above for parsing. If you have lots of log entries (high traffic) I would suggest to use something like an ELK stack for analysis.
Let us take a look at some of these rules now.
12872 GPL ICMP_INFO PING *NIX
This list (ICMP_INFO) gives you information about e.g. pings. So whenever someone is pinging your system(s) you’ll see this message. To be honest, I don’t want ping probes to fill my logs. And I also don’t want to block ping probes because I want to use ping probes for debug purposes (can I reach my system?). So this is not a useful rule for me.
So I create /etc/suricata/disable.conf using the contents of the documentation https://suricata-update.readthedocs.io/en/latest/update.html and I add the SIDs which contains the ping-rules. Don’t mind my grep commands – you’ll likely find a better way to achieve this :^) Also I’m not saying you should disable logging of pings. I’m just demonstrating how you COULD work with suricata.
~# cat /etc/suricata/disable.conf
# suricata-update - disable.conf
# Example of disabling a rule by signature ID (gid is optional).
# 1:2019401
# 2019401
# Disabled ping logging
# grep -i icmp_info /var/lib/suricata/rules/suricata.rules | grep -v "^#"
# grep -i icmp_info /var/lib/suricata/rules/suricata.rules | grep -v "^#" | sed 's_.*sid:__g' | sed 's_; rev.*__g'
2100366
2100368
2100369
2100370
2100371
2100373
2100374
2100376
2100377
2100378
2100379
2100380
2100482
2100480
# Example of disabling a rule by regular expression.
# - All regular expression matches are case insensitive.
# re:heartbleed
# re:MS(0[7-9]|10)-\d+
# Examples of disabling a group of rules.
# group:emerging-icmp.rules
# group:emerging-dos
# group:emerging*
# Disable all rules with a metadata of "deployment perimeter". Note that metadata
# matches are case insensitive.
# metadata: deployment perimeter
Did you run an update with suricata-update yet? If not you should do. It will also show you that disabling works:
~# suricata-update
<Info> -- Loading /etc/suricata/update.yaml
<Info> -- Using data-directory /var/lib/suricata.
<Info> -- Using Suricata configuration /etc/suricata/suricata.yaml
<Info> -- Using /etc/suricata/rules for Suricata provided rules.
<Info> -- Found Suricata version 6.0.10 at /usr/bin/suricata.
<Info> -- Loading /etc/suricata/disable.conf.
<Info> -- Loading /etc/suricata/suricata.yaml
<Info> -- Disabling rules for protocol http2
<Info> -- Disabling rules for protocol modbus
<Info> -- Disabling rules for protocol dnp3
<Info> -- Disabling rules for protocol enip
<Info> -- Fetching https://sslbl.abuse.ch/blacklist/sslblacklist.rules.
100% - 1697921/1697921
<Info> -- Done.
<Info> -- Fetching https://sslbl.abuse.ch/blacklist/ja3_fingerprints.rules.
100% - 25718/25718
<Info> -- Done.
<Info> -- Fetching https://openinfosecfoundation.org/rules/trafficid/trafficid.rules.
100% - 9855/9855
<Info> -- Done.
<Info> -- Fetching https://raw.githubusercontent.com/travisbgreen/hunting-rules/master/hunting.rules.
100% - 76304/76304
<Info> -- Done.
<Info> -- Checking https://rules.emergingthreats.net/open/suricata-6.0.10/emerging.rules.tar.gz.md5.
<Info> -- Remote checksum has not changed. Not fetching.
<Info> -- Ignoring file rules/emerging-deleted.rules
<Info> -- Loaded 51400 rules.
<Info> -- Disabled 14 rules.
<Info> -- Enabled 0 rules.
<Info> -- Modified 0 rules.
<Info> -- Dropped 0 rules.
<Info> -- Enabled 131 rules for flowbit dependencies.
<Info> -- Backing up current rules.
<Info> -- Writing rules to /var/lib/suricata/rules/suricata.rules: total: 51400; enabled: 41170; added: 0; removed 0; modified: 14
<Info> -- Writing /var/lib/suricata/rules/classification.config
<Info> -- Testing with suricata -T.
<Info> -- Done.
And how does all this help you to make Suricata block / drop packets now? If you configured suricata as an IPS like – then you need to modify the rules in a way that Suricata uses them to do blocking. Similarly to the above you would find the rules you want to block packets. Add them to drop.conf in /etc/suricata (taken from the documentation: https://suricata-update.readthedocs.io/en/latest/update.html#example-drop-conf)
# suricata-update - drop.conf
#
# Rules matching specifiers in this file will be converted to drop rules.
#
# Examples:
#
# 1:2019401
# 2019401
#
# re:heartbleed
# re:MS(0[7-9]|10)-\d+
The next entry in my logs (10309 ET DROP Dshield Block Listed Source) is one I would indeed use for blocking. If you grep for this one you will see it’s only one rule. The current SID is: 2402000. So I add the following to my drop.conf:
# 10309 hits ET DROP Dshield Block Listed Source
2402000
After running suricata-update I see:
-- Loaded 51400 rules.
-- Disabled 14 rules.
-- Enabled 0 rules.
-- Modified 0 rules.
-- Dropped 1 rules.
-- Enabled 131 rules for flowbit dependencies.
Now let’s get back to my initial command to get a list of the log entries. I modified that command a bit and worked a little bit more with awk. Now here’s a list of dropped packets:
~# awk '/Drop/{$1="";$2="";$3="";$4="";sub(/\[.*/,"");gsub(/^[ \t]+|[ \t]+$/,"");sub(/group.*/,"");print}' fast.log | sort | uniq -c | sort -hr
6505 IP dropped due to fail2ban detection
638 ET DROP Dshield Block Listed Source
You can also use this modified command to get a list of what’s going on (not just Drop / excluding drop):
~# awk '!/Drop/{$1="";$2="";$3="";$4="";sub(/\[.*/,"");gsub(/^[ \t]+|[ \t]+$/,"");sub(/group.*/,"");print}' fast.log | sort | uniq -c | sort -hr
14691 ICMP_INFO PING *NIX
11578 DROP Dshield Block Listed Source
6851 CINS Active Threat Intelligence Poor Reputation IP
5558 TCPv4 invalid checksum
1724 3CORESec Poor Reputation IP
1716 SCAN Potential SSH Scan
1413 INFO SSH-2.0-Go version string Observed in Network Traffic - Inbound
1156 Applayer Detect protocol only one direction
646 COMPROMISED Known Compromised or Hostile Host Traffic
517 SCAN LibSSH Based Frequent SSH Connections Likely BruteForce Attack
513 STREAM excessive retransmissions
388 SCAN Suspicious inbound to MSSQL port 1433
333 SMTP no server welcome message
262 ICMP_INFO PING speedera
237 STREAM Last ACK with wrong seq
235 SCAN Suspicious inbound to mySQL port 3306
230 SCAN Suspicious inbound to PostgreSQL port 5432
223 UDPv4 invalid checksum
104 RPC portmap listing UDP 111
103 STREAM 3way handshake excessive different SYN/ACKs
101 DROP Spamhaus DROP Listed Traffic Inbound
[..]
Of course this result will still contain the previously not dropped entries. So every now and then you should probably just start with a fresh log for this sort of analysis.
Use the variables, Luke!
Did you see in suricata.yaml that there are the following variables?
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"
If you grep for them in the rules you will see that these variables are used. Look at sid 2102259 for example. The rule’s message is: GPL SMTP EXPN overflow attempt and it references CVE-2002-1337 which itself might have been used to cause a buffer overflow in sendmail.
Now is there any good reason to check HTTP Traffic against this rule? No. That’s why the rule looks like this:
alert tcp $EXTERNAL_NET any -> $SMTP_SERVERS 25 (msg:"GPL SMTP EXPN overflow attempt"; [..]
My advise is: use the variables whenever possible. Because some, not all rules make use of them. And if you write your own rules you should try to use these variables as well.