Using Zeek, Ossec and PF to Fight Network Scans

Hi !

In the previous post, we saw how to use Zeek to detect port scans. The next logical step is therefore to try to block them.

The method detailed below involves using the Host Intrusion Detection System named “OSSEC” and having it interact with a firewall (in this case, the one OpenBSD uses).

We saw that the Zeek’s script mentioned in the previous post wrote a message to the file named “notice.log”. It becomes quite obvious to ask “OSSEC” to read this file and trigger an alert with a criticality level sufficient for the relevant blocking option to be invoked.

  1. The first step will be to detect the message related to the port scan in the “notice.log” file. Let’s instruct “OSSEC” to monitor it. There is, however, a little subtlety to be aware of. You must define the “notice.log” file as being of type “syslog”. The reason is that with this configuration, OSSEC will detect the file and therefore inode change made by Zeek every hour. As a result, it will be able to continue monitoring the file.
<localfile>
    <log_format>syslog</log_format>
    <location>/var/log/zeek/current/notice.log</location>
</localfile>
  1. Next, you need to tell “OSSEC” how to find the string of characters you are looking for.

This method involves creating a new decoder.

/etc/ossec/local_decoder.xml

<decoder name="zeek_portscan_detection">
  <prematch>Port_Scan_S0_Detected</prematch>
</decoder>

<decoder name="zeek_portscan_detection_ip">
  <parent>zeek_portscan_detection</parent>
  <regex>IP (\d+.\d+.\d+.\d+)</regex>
  <order>srcip</order>
</decoder>

We also need to create a new local rule. Note that a sufficient level is required to enable the “firewall-drop” command.

/usr/local/ossec-hids/rules/local_rules.xml

<group name="zeek,scan,">
  <rule id="100500" level="6">
    <decoded_as>zeek_portscan_detection</decoded_as>
    <regex>Port_Scan_S0_Detected</regex>
    <description>Zeek a detecte un scan furtif (5 ports en etat S0).</description>
  </rule>
</group>       
  1. Now let’s check some log files

/var/log/zeek/current/notice.log

1781175852.749782      -       -       -       -       -       -       -       -       -       Port_Scan_S0_Detected   IP 66.132.172.191 suspectee de scan : 5 ports distincts en etat S0 (pas de reponse) en moins d'une minute  -       66.132.172.191  -       -       -       -       Notice::ACTION_LOG      (empty) 3600.000000     -       -       -       -       -

/var/log/ossec/alerts/alerts.log

** Alert 1781175887.223844: - zeek,scan,
2026 Jun 11 11:04:47 sunset->/var/log/zeek/current/notice.log
Rule: 100500 (level 6) -> 'Zeek a detecte un scan furtif (5 ports en etat S0).'
Src IP: 66.132.172.191
1781175852.749782       -       -       -       -       -       -       -       -       -       Port_Scan_S0_Detected   IP 66.132.172.191 suspectee de scan : 5 ports distincts en etat S0 (pas de reponse) en moins d'une minute       -       66.132.172.191  -       -       -       -       Notice::ACTION_LOG      (empty) 3600.000000     -       -       -       -       -

/var/log/ossec/active-responses.log

Thu Jun 11 06:04:47 CDT 2026 /usr/local/ossec-hids/active-response/bin/firewall-drop.sh add - 66.132.172.191 1781175887.223844 100500

/var/log/pflog.txt

Jun 11 06:05:02 sunset pf: Jun 11 06:04:05.620479 rule 26/(match) block in on em0: 66.132.172.191.41676 > 162.212.157.188.444: S 4000157755:4000157755(0) win 21900 <mss 1460,sackOK,timestamp 1669927748 0,nop,wscale 10> (DF)

Conclusion:

The combination of three excellent tools, Zeek (for detection), Ossec (for analysis), and PF (for blocking) allowed us to target network port scans. We won’t pretend there aren’t ways to make the configuration shown less effective, but conversely, we can also make it much more aggressive.

PS: In the next few posts, I will alternate between the “schwerpunkt” already mentioned by Clausewitz, new ways of looking at the entropy of DNS queries and a very interesting cybersecurity concept.

Cheers.