Ein Beitrag aus der Serie, pimp my pi, der eine konkrete Installationsanleitung für ein Network Intrusion Detection System (vgl.: NDIS) beinhaltet. Die Installationsanleitung bezieht sich auf einen Raspberry Pi 4B mit 4GB RAM, Ubuntu 18.04LTS 64bit, Maltrail und Zeek.
Die Installation von Ubuntu bietet sich an, weil es sich hierbei um eine vollwertige 64 Bit Umgebung handelt. Raspbian bietet zwar auch einen 64 Bit Kernel an, aber das „Userland“ bleibt im 32 Bit Modus – vor allem aus Kompatibilitätsgründen. Die Entscheidung zu Gunsten 64 Bit ist nicht nur alleine wegen des möglichen Perfomancegewinns, sondern auch, da es viele Anwendungen aktuell nur mehr in einer 64 Bit Version gibt. (Anm.: ungeachtet der Rechnerarchitektur natürlich, die schränkt zusätzlich noch ein) Als konkretes Beispiel kann man hier MongoDB anführen.
Die Installation von Ubuntu auf einem Raspberry Pi führe ich hier nicht auf. Die verfügbare Anleitung von Ubuntu selber ist mehr als ausführlich.
Legende: Der Netzwerkverkehr von und zur Firewall wird am Switch kopiert. Eine Kopie aller Pakete wird an einem zweiten Anschluss ausgegeben. Auf dem zweiten Anschluss nimmt das NIDS alle Pakte entgegen. Die Netzwerkkarte des NIDS hat keine IP Adresse und ist im Monitor Modus. Das heisst die Netzwerkkarte nimmt alle Pakte, auch die, die nicht für sie bestimmt sind, entgegen. Weitere Optimierungen gehen über den eigentlichen Rahmen hinaus, sind aber möglich. Der eigentliche Verkehr wird dadurch nicht beeinträchtigt, da von Seiten des NIDS keine Bestätigung erwartet wird, dass der Datenstrom erfasst, verarbeitet usw. wurde. Verlorengegangene Pakete werden in der Statistik ausgewiesen.
Vor der Aktivierung des NIDS und vor allem des Port Mirroring empfiehlt es sich alles via Ethernetschnittstelle zu machen – stabile und schnelle Verbindung. Eine weitere Empfehlung ist einen Terminal Multiplexer, wie tumx, einzusetzen. Tumx ist bereits im Basis Image von Ubuntu Server dabei.
Netzwerkkonfiguration:
stefan@baby:~$ cat /etc/netplan/50-cloud-init.yaml
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
ethernets:
eth0:
dhcp4: false
optional: true
version: 2
wifis:
wlan0:
access-points:
ssid: #Mit dem Namen des WLAN Netzwerks - ssid
password: 'abcdefgh' #Netzwerkpasswort einsetzen
dhcp4: true
optional: true
Monitor Modus Ethernetschnittstelle:
stefan@baby:~$ cat /etc/systemd/system/promisc.service
[Unit]
Description=Bring up an interface in promiscuous mode during boot
After=network.target
[Service]
Type=oneshot
ExecStartPre=/sbin/ip addr flush dev eth0
ExecStart=/sbin/ip link set dev eth0 promisc on
TimeoutStartSec=0
RemainAfterExit=yes
[Install]
WantedBy=default.target
Die Datei muss zu diesem Grund erst erstellt werden. Verzeichnis und Namen stehen in der ersten Zeile. Die Anweisung ExecStartPre löscht jede vorhanden IP Adresse zu der Schnittstelle eth0. Die Anweisung ExecStart versetzt die Schnittstelle eth0 in den Monitor Modus.
stefan@baby:/opt/zeek/logs/current$ ll /etc/systemd/system
total 68
drwxr-xr-x 16 root root 4096 Apr 13 15:44 ./
drwxr-xr-x 5 root root 4096 Apr 12 11:11 ../
<snip>
-rwxr-xr-x 1 root root 239 Apr 13 15:44 promisc.service*
<snip>
Monitor Modus aktivieren
stefan@baby:~$ sudo systemctl daemon-reload
stefan@baby:~$ sudo systemctl enable promisc.service
stefan@baby:~$ sudo systemctl start promisc.service
Damit sollte der Monitor Modus der Schnittstelle eth0 vorhanden sein und auch nach einem Neustart automatisch aktiviert sein. Die Schnittstelle sollte keine IP Adresse zugewiesen bekommen haben.
Kontrolle Monitor Modus
stefan@baby:~$ sudo systemctl status promisc.service
● promisc.service - Bring up an interface in promiscuous mode during boot
Loaded: loaded (/etc/systemd/system/promisc.service; enabled; vendor preset: enabled)
Active: active (exited) since Mon 2020-04-13 11:08:14 CEST; 3h 43min ago
Process: 1340 ExecStart=/sbin/ip link set dev eth0 promisc on (code=exited, status=0/SUCCESS)
Main PID: 1340 (code=exited, status=0/SUCCESS)
Apr 13 11:08:14 baby systemd[1]: Starting Bring up an interface in promiscuous mode during boot...
Apr 13 11:08:14 baby systemd[1]: Started Bring up an interface in promiscuous mode during boot.
Der Dienst ist erfolgreich geladen und läuft.
stefan@baby:~$ ip a
<snip>
2: eth0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether dc:a6:32:87:04:03 brd ff:ff:ff:ff:ff:ff
inet 192.168.000.000/24 brd 192.168.000.255 scope global eth0
valid_lft forever preferred_lft forever
<snip>
Hier sieht man, dass das Interface eth0 keine IP Adresse hat und auch der Monitor Modus, PROMISC, aktiviert ist.
Damit ist der Ausgangszustand für das NIDS erreicht. Es folgt die Installation von Maltrail.
Installation Maltrail
Maltrail erkennt bösartigen Netzwerkverkehr. Hierzu werden vor allem Listen verwendet, die verschiedene Informationen haben. Genaueres über den Inhalt und den Aufbau dieser Listen ist auf der Entwicklerseite nachzulesen. Es kommt zusätzlich zu den Listen auch ein heuristisches Verfahren zum Einsatz, um unbekannte Bedrohungen zu erkennen.
Bei der Installation empfiehlt es sich nach der Best Practice Anleitung vorzugehen. Danach sollte Maltrail angepasst werden. Das erfolgt über die Konfigurationsdatei (/etc/maltrail/maltrail.conf)
# [Server]
# Listen address of (reporting) HTTP server
HTTP_ADDRESS 192.168.XXX.XXX # IP Adresse WLAN Interface
# User entries (username:sha256(password):UID:filter_netmask(s))
# Note(s): sha256(password) can be generated on Linux with: echo -n 'password' | sha256sum | cut -d " " -f 1
# UID >= 1000 have only rights to display results (Note: this moment only functionality implemented at the client side)
# filter_netmask(s) is/are used to filter results
USERS
admin:9ab3cd9d67bf49d01f6a2e33d0bd9bc804ddbe6ce1ff5d219c42624851db5dbc:0: # changeme!
local:9ab3cd9d67bf49d01f6a2e33d0bd9bc804ddbe6ce1ff5d219c42624851db5dbc:1000:192.168.0.0/16 # changeme!
# Interface used for monitoring (e.g. eth0, eth1)
MONITOR_INTERFACE eth0
# Network capture filter (e.g. ip)
# Note(s): more info about filters can be found at: https://danielmiessler.com/study/tcpdump/
CAPTURE_FILTER ip or ip6
# Sensor name to appear in produced logs
SENSOR_NAME DMZ iMatrix
# Use heuristic methods
USE_HEURISTICS true
Das ist ein Auszug der maltrail.conf wichtig ist darauf hinzuweisen, dass die Passwörter für die Benutzer „admin“ und „local“ auf alle Fälle geändert werden sollten. Eine Anleitung dazu steht in der Konfigurationsdatei.
Installationstätigkeiten Zeek
Da es kein fertiges Paket für den Raspberry gibt muss Zeek selbst übersetzt werden. Dazu sind folgende Pakete zu installieren.
sudo apt-get install cmake make gcc g++ flex bison libpcap-dev libssl-dev python-dev swig zlib1g-dev
Wenn jetzt Python in Version 2.7 installiert ist, dann ist es notwendig auch noch das Paket python-ipaddress zu installieren. Zusätzlich sind noch einige Pakte empfehlenswert für eine Zeek Installation.
stefan@baby:~$ sudo apt install libmaxminddb0 postfix curl google-perftools libjemalloc1 libjemalloc-dev
GeoIP DB einrichten
root@baby:/home/stefan# wget https://www.maxmind.com/en/accounts/265120/geoip/downloads
root@baby:/home/stefan# tar xvzf GeoLite2-City_20200407.tar.gz
root@baby:/home/stefan# mv GeoLite2-City_20200407/GeoLite2-City.mmdb /usr/share/GeoIP/GeoLite2-City.mmdb
Installation vorbereiten
stefan@baby:~$ sudo mkdir /opt/zeek
stefan@baby:~$ sudo chown -R stefan:zeek /opt/zeek
stefan@baby:~$ sudo chmod 740 /opt/zeek
Zeek wird im Verzeichnis /opt/zeek installiert. Der Besitzer ist der reguläre Benutzer. Die Gruppe Zeek sollte natürlich existieren. In diese Gruppe können dann alle Benutzer, die Zeek verwenden sollen und vielleicht auch Auswertungen machen.
Installation Zeek
stefan@baby:~$ cd
stefan@baby:~$ wget https://old.zeek.org/downloads/zeek-3.1.1.tar.gz
stefan@baby:~$ tar -xzvf zeek-3.1.1.tar.gz
stefan@baby:~$ cd zeek-3.1.1
stefan@baby:~$ ./configure --prefix=/opt/zeek --enable-jemalloc
stefan@baby:~$ make
stefan@baby:~$ make install
Hier werden als normaler Benutzer die Quelldateien heruntergeladen und entpackt. Für die Übersetzung werden zwei Parameter übergeben. Prefix legt fest in welchem Verzeichnis Zeek installiert wird und JeMalloc ist eine Optimierung. Die Make Befehle können auch kombiniert werden. Eine Ausführung unter tmux ist ratsam, da es relativ lange dauert und die Wahrscheinlichkeit eines Verbindungsabbruchs besteht.
Alternative:
stefan@baby:~$ cd
stefan@baby:~$ tmux
stefan@baby:~$ cd zeek-3.1.1
stefan@baby:~$ ./configure --prefix=/opt/zeek --enable-jemalloc
stefan@baby:~$ make && make install
Sobald der Kompilierlauf gestartet ist kann man sich von der Konsole abhängen. (Crtl-B, D). Danach ist man wieder auf der ursprünglichen Konsole.
Umgebungsvariable setzen
stefan@baby:~$ sudo vi /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/opt/zeek/bin"
Damit ist sicher gestellt, dass die ausführbaren Dateien von Zeek auch für alle Systembenutzer verfügbar sind. Um die Änderungen ohne Neustart, Log-out etc. zu übernehmen reicht.
stefan@baby:~$ source /etc/environment
Ausführungsberechtigung für Erfassen von Netzwerkpaketen setzen
stefan@baby:~$ sudo setcap cap_net_raw=eip /opt/zeek/bin/zeek
stefan@baby:~$ sudo setcap cap_net_raw=eip /opt/zeek/bin/capstats
Das setzen der Berechtigungen kann während der Kompilierung erfolgen. Nachdem die Kompilierung ohne Fehlermeldung abgeschlossen ist geht es weiter.
Zeek konfigurieren (Basis – alles auf einem Host)
stefan@baby:~$ vi /opt/zeek/etc/node.cfg
[zeek]
type=standalone
host=localhost
interface=eth0
Zeek hört nur auf dem Interface eth0 – deswegen wurde dieses auch vorher in den Monitor Modus versetzt. Der Switch spiegelt alle Pakete zu diesen Anschluss. Wie schon weiter oben erwähnt kann es von Seiten des NIDS zu keiner Beeinträchtigung kommen. Der Switch muss den entsprechenden Durchsatz auf der Backplane aber gewährleisten können.
Zeek Konfiguration
stefan@baby:/opt/zeek/etc$ vi zeekctl.cfg
MailTo = EMPFAENGER@localhost
Der Empfänger bekommt die Zusammenfassung der Protokolle per Mail zugestellt. Deswegen wurde weiter oben Postfix als Alternative zu Sendmail installiert. Postfix ist hier als reiner lokaler MTA im Einsatz.
Aktivieren der verwendeten Scripts für die Erfassung durch Zeek
stefan@baby:/opt/zeek/share/zeek/site$ vi local.zeek
Nach belieben Scripts aktivieren, oder auch deaktivieren. Meist steht auch dabei welche Leistungseinbussen am System selber hervorrufen können.
Zeek starten
Konfiguration testen und ausrollen
stefan@baby:~$ zeekctl deploy
checking configurations …
installing …
removing old policies in /opt/zeek/spool/installed-scripts-do-not-touch/site …
removing old policies in /opt/zeek/spool/installed-scripts-do-not-touch/auto …
creating policy directories …
installing site policies …
generating standalone-layout.zeek …
generating local-networks.zeek …
generating zeekctl-config.zeek …
generating zeekctl-config.sh …
stopping …
stopping zeek …
starting …
starting zeek …
Status überprüfen
stefan@baby:~$ zeekctl status
Name Type Host Status Pid Started
zeek standalone localhost running 30340 14 Apr 12:39:42
Status generell
Wurden die entsprechenden Protokolldateien angelegt? Für jedes aktivierte Script wird in der Regel eine eigene Protokolldatei angelegt. Das ist mitunter einer der großen Unterschiede zu anderen NIDS.
stefan@baby:~$ cd /opt/zeek/logs/current
stefan@baby:/opt/zeek/logs/current$ ls -als
total 156
drwxr-xr-x 2 stefan zeek 4096 Apr 14 12:40 ./
drwxr-xr-x 5 stefan stefan 4096 Apr 14 12:40 ../
-rw-r--r-- 1 stefan zeek 128 Apr 14 12:39 .cmdline
-rw-r--r-- 1 stefan zeek 357 Apr 14 12:39 .env_vars
-rw-r--r-- 1 stefan zeek 6 Apr 14 12:39 .pid
-rw-r--r-- 1 stefan zeek 59 Apr 14 12:39 .startup
-rwx------ 1 stefan zeek 18 Apr 14 12:39 .status*
-rw-r--r-- 1 stefan zeek 13507 Apr 14 12:41 conn.log
-rw-r--r-- 1 stefan zeek 6496 Apr 14 12:41 dns.log
-rw-r--r-- 1 stefan zeek 9365 Apr 14 12:41 files.log
-rw-r--r-- 1 stefan zeek 907 Apr 14 12:40 http.log
-rw-r--r-- 1 stefan zeek 353 Apr 14 12:40 known_certs.log
-rw-r--r-- 1 stefan zeek 238 Apr 14 12:39 known_hosts.log
-rw-r--r-- 1 stefan zeek 242 Apr 14 12:40 known_services.log
-rw-r--r-- 1 stefan zeek 26471 Apr 14 12:39 loaded_scripts.log
-rw-r--r-- 1 stefan zeek 1694 Apr 14 12:41 ntp.log
-rw-r--r-- 1 stefan zeek 227 Apr 14 12:39 packet_filter.log
-rw-r--r-- 1 stefan zeek 457 Apr 14 12:40 software.log
-rw-r--r-- 1 stefan zeek 9794 Apr 14 12:41 ssl.log
-rw-r--r-- 1 stefan zeek 690 Apr 14 12:39 stats.log
-rw-r--r-- 1 stefan zeek 19 Apr 14 12:39 stderr.log
-rw-r--r-- 1 stefan zeek 188 Apr 14 12:39 stdout.log
-rw-r--r-- 1 stefan zeek 1341 Apr 14 12:40 weird.log
-rw-r--r-- 1 stefan zeek 4673 Apr 14 12:41 x509.log
stefan@baby:/opt/zeek/logs/current$ zeekctl diag
Mit zeekctl diag wird eine ausführliche Diagnose durchgeführt und auch auf der Konsole ausgegeben. Das würde hier dann doch etwas zu weit führen.
Automatisierter Check
Über eine Cron Task, hier alle fünf Minuten, wird überprüft, ob alle Jobs einwandfrei laufen.
stefan@baby:/opt/zeek/logs/current$ crontab -e
*/5 * * * * /opt/zeek/bin/zeekctl cron
Up and Running
Wer es bis hierher geschafft hat und auch alles mit seinem Raspberry Pi gemacht hat. Hat eine gute Ausgangsbasis für ein effizientes NIDS. Nächste Schritte gibt es viele. Das können zum Beispiel erste Schritte mit Zeek sein.
Aktuell werden Zeek Protokolldateien im JSON Format in eine MongoDB transformiert. Auf Basis von verschiedenen Merkmalen werden verschieden „Basisaggregate“ erstellt. Zum Beispiel zu einer Quelladresse werden in einem Dataframe die jeweiligen Zeitabstände zwischen zwei Verbindungsaufnahmen gemessen etc. Dazu gibt es natürlich auch schon was fertiges -> RITA zum Beispiel.