Implement Zeek on FreeBSD
Introduction
Today it is not enough to have protective measures only to secure your network, infrastructure and data. Detective measures are even more import now, as the best approach to security is to implement a strategy that is based on the rule that you will get breached someday. So you better detect an event when it has passed your protective measures and detect is soon!
Only Argus is implemented in the SoCruel.NU network currently (see also my blog post How to capture session data with Argus on FreeBSD. So the logical next step is to get more visibility on the application and services side. An example of a current missing insight on my network is e.g. which domains are queried by the systems on my network?
And no other tool than Zeek can answer this question the best! Zeek is a network security monitoring platform which generates rich network metadata that is very valuable for general network troubleshooting, getting insight in what happens on your network, and even for incident response and forensics! Every network should run Zeek! So find below the instructions to implement it on our favorite Operating System FreeBSD!
This blog post is the first blog post of a series of posts about Zeek on FreeBSD! So more to come after this one.
Technical prerequisites
The following technical prerequisites have to be in place to be able to implement what is described in this post:
- an up to date and supported FreeBSD system version 12.x
- the FreeBSD system must have at least 2 Network Interface Cards (NICs)
- 1 NIC is used for managing and using the system. This NIC has an IP address configured. This is interface
em0
in this blog post. - (at least) 1 NIC is used to to capture packets from a network. This NIC is connected to a SPAN port or network TAP. This NIC does NOT have an IP address configured. This is interface
em1
in this blog post.
Requirements
No software can be implemented in the right way without defining the requirements for its intended use. So I’ve also defined requirements for the Zeek implementation discussed in this post:
- implement Zeek on 1 host (you can implement Zeek in a distributed fashion on more hosts!)
- use JSON based logging (1)
- netmap is not used (not that much of network traffic is processed to be needing this!)
- the host needs access to the internet (DNS, HTTP and HTTPS) to be able to fetch and install software
(1) : the main reason why we want to log in JSON format is that in the future we want to ship the Zeek logs to a log management system.
The configuration of the interfaces
The FreeBSD host which runs Zeek has 2 NICs per the requirements above. Assuming that these 2 NICs are called em0
and em1
, these can be setup like this:
$ sudo sysrc ifconfig_em0="inet 10.1.2.99 netmask 255.255.255.0" (2) $ sudo sysrc ifconfig_em1="monitor up"
(2): it is assumed here that the host running zeek
is connected to the 10.1.2.0/24
subnet or network with the em0
interface. The em1
interface is connected to a SPAN port or network TAP.
Install required packages
Before Zeek is installed and configured, some other software and packages are needed for this implementation:
We need jq because we log in JSON format. And we want to be able to query these logs! And the best way to query JSON is using jq
!
With datamash we can do calculations and stuff on the output of the queries we perform.
The commands to install these packages are:
$ sudo pkg install -y jq $ sudo pkg install -y datamash
Install and configure Zeek
The base
Now it is time to install the Zeek software. We do this using the following command:
$ sudo pkg install -y zeek
We need to edit 3 files to configure Zeek. These files are:
/usr/local/etc/zeekctl.cfg
/usr/local/etc/node.cfg
/usr/local/etc/networks.cfg
The networks.cfg
file defines the local private networks of the environment zeek
is installed in. The format of this file is like:
# Address range Description 10.1.2.0/24 LAN 172.16.99.0/24 DMZ 192.168.1.0/24 WiFi
The node.cfg
file defines the nodes of our zeek
implementation. As per the requirement defined above we run zeek
on 1 node and we have 1 interface which captures the network traffic (change the interface for your own configuration):
[zeek] type=standalone host=localhost interface=em1
It is possible to monitor more than 1 interface with Zeek running on a single host. This is discussed later in this series.
The last configuration file is called zeekctl.cfg
and configures the zeekctl
utility. The following contents have been chosen for our implementation:
# Mail options MailTo = admin@domain.tld MailConnectionSummary = 1 MinDiskSpace = 5 MailHostUpDown = 1 # Logging options LogRotationInterval = 86400 LogExpireInterval = 35day StatsLogEnable = 1 StatsLogExpireInterval = 35 # Other options StatusCmdShowAll = 0 CrashExpireInterval = 0 SitePolicyScripts = local.zeek LogDir = /var/zeek/logs SpoolDir = /var/zeek/spool CfgDir = /usr/local/etc
The mail options speak for themselves. If you have a MTA running on your host (like e.g. the DMA, you can get a summary send to the address specified in the MailTo
item when you have set the MailConnectionSummary
setting to 1. With these logging options, the logs are roteted each day (86400 seconds) and the logs are kept for 35 days. The site policy script (a file called local.zeek
) is in the /usr/local/share/zeek/site
folder. The SpoolDir
entry defines the directory of th ecurrent log files. The archived log files are in the directory /var/zeek/logs
(LogDir
configuration entry).
Enable JSON logging
So we have done the base setup of zeek
. Now we can add the logging in JSON format as we want. We do this by using the following command:
$ sudo tee -a /usr/local/share/zeek/site/local.zeek > /dev/null <<EOT ? # Enable JSON logging ? @load policy/tuning/json-logs ? EOT
Add a cron entry
To enable Zeek maintenance we need to add an entry to the cron
daemon:
$ sudo echo "*/5 * * * * root /usr/local/bin/zeekctl cron" >> /etc/crontab
Start Zeek
To finish the base setup of Zeek we have to do one more step. And that is enable Zeek in the startup script rc.conf
. We can do this using:
$ sudo sysrc zeek_enable="YES"
The base setup is ready now. So we can start Zeek and capture some network traffci with it. To start Zeek we issue the command:
$ sudo service zeek deploy
We need this command as we have a new configuration. Every time the Zeek configuration changes you have to use the above command sudo service zeek deploy
! In between you can start en stop Zeek by using the sudo service zeek start
and sudo service zeek stop
commands.
Now we check if traffic is actually logged by Zeek by looking at the contents of the connections log file conn.log
:
$ cd /var/zeek/logs/current $ head -1 conn.log | jq
With the last command you should see the contents of the first logged connection in JSON format. It should look like the below:
{ "ts": 1611708585.385558, "uid": "CWttSl429dBU80Tip6", "id.orig_h": "10.1.2.103", "id.orig_p": 45341, "id.resp_h": "192.168.1.51", "id.resp_p": 53, "proto": "udp", "service": "dns", "duration": 0.0005099773406982422, "orig_bytes": 86, "resp_bytes": 163, "conn_state": "SF", "local_orig": true, "local_resp": true, "missed_bytes": 0, "history": "Dd", "orig_pkts": 2, "orig_ip_bytes": 142, "resp_pkts": 2, "resp_ip_bytes": 219 }
Wrap up
This blog post covered the base setup of Zeek on FreeBSD. Zeek logs in its own text based format by default. This format can be queried with the zeek-cut
tool. But here Zeek is configured to log in JSON format. These logs can still be queried using the jq
tool.
This is the first blog post in a series of posts about Zeek on FreeBSD. The next blog post is about configuring Zeek to run as a normal user zeek
instead of root
.
Resources
Some (other) resources about this subject: