# NDR stack — shaula (Debian 13 trixie) Network detection & response tooling for the `shaula` VM. Interface: `eth0`. All scripts re-exec themselves with `sudo -E` when not run as root, so the interface override is passed as a plain-user env var: `IFACE=eth1 ./script.sh add`. Do NOT use `IFACE=... sudo ./script.sh` — sudo's env_reset strips it. ## Scripts | Script | Commands | What it does | |-----------------|----------------------|------------------------------------------------| | `ntopng.sh` | `add remove status` | ntopng from the ntop apt repo, web UI port 3000 | | `suricata.sh` | `add remove status` | Suricata + ET/open rules via suricata-update, eve.json | | `zeek.sh` | `add remove status` | Zeek (OBS repo), standalone af_packet node, zeekctl deploy | | `rita.sh` | `add remove status` | RITA v5.1.2 binary to /usr/local/bin | | `crowdsec.sh` | `add remove status` | CrowdSec from Debian main, linux + sshd collections; detection-only by default (`BLOCK=1` opts into the firewall bouncer: the upstream binary in iptables(ipset) mode — the trixie Debian package's 0.0.25 binary is broken on trixie) | | `atomic-red-team.sh` | `add remove status` | ART: adversary emulation framework install — pwsh + invoke-atomicredteam module + index clone; executes nothing by itself | ## Integrations (`integrations/`) | Script | Commands | What it does | |----------------------------|------------------------|-------------------------------------------------| | `suricata-ntopng.sh` | `enable disable status`| Second ntopng instance reading eve.json, port 3002 | | `zeek-rita.sh` | `enable disable status`| rita-import.timer: imports /opt/zeek/logs every 15 min | | `crowdsec-suricata.sh` | `enable disable status`| CrowdSec parses /var/log/suricata/eve.json | | `crowdsec-ntopng.sh` | `enable disable status`| Mirror CrowdSec decisions into ntopng Active Monitor (visibility only) | ## Usage ```sh sudo ./suricata.sh add # each script: add | remove | status sudo ./ntopng.sh status IFACE=eth1 ./zeek.sh add # override capture interface (the sudo -E re-exec honors it) ``` `add`/`remove`/`enable`/`disable` are idempotent — safe to re-run. `remove` purges only the packages/files each script installed and then runs `apt-get autoremove --purge`. ## Suggested install order 1. `suricata.sh add` — capture + rules first 2. `ntopng.sh add` — traffic analysis 3. `crowdsec.sh add` — log-based detection (nftables bans only with `BLOCK=1`) 4. `zeek.sh add` — Zeek logs 5. `rita.sh add` — needs Zeek logs to be useful 6. Integrations last: - `integrations/suricata-ntopng.sh enable` (needs ntopng + suricata) - `integrations/crowdsec-suricata.sh enable` (needs crowdsec + suricata) - `integrations/zeek-rita.sh enable` (needs zeek + rita) Removal: reverse the order, then remove base components. ## Ports / paths - ntopng web UI: **3000**; ntopng-suricata integration instance: **3002** (3001 is the main instance's package-default HTTPS port — ntopng.sh strips `-W=3001` from /etc/ntopng/ntopng.conf, but keep 3001 reserved) - Suricata: `/etc/suricata/suricata.yaml`, logs `/var/log/suricata/`, rules `/var/lib/suricata/rules` - Zeek: `/opt/zeek` (config `etc/node.cfg`, logs `logs/`) - RITA: `/usr/local/bin/rita`, imports Zeek logs from `/opt/zeek/logs` - Atomic Red Team: `/opt/atomic-red-team` (index clone); `atomic-red-team.sh` is for **detection validation against the installed stack** — it installs the pwsh + invoke-atomicredteam tooling only and never runs tests itself. - CrowdSec → ntopng (`integrations/crowdsec-ntopng.sh`): CrowdSec decisions are mirrored into ntopng's Active Monitor list every 5 minutes (visibility only — enforcement is the nftables bouncer). The ntopng admin password must be set and copied to `/etc/crowdsec-ntopng.conf` before enabling. - CrowdSec: `/etc/crowdsec/`, acquisitions in `acquis.yaml`, inspect with `cscli`; firewall bouncer config at `/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml` ## Deployment notes (2026-09-28, live-tested on shaula) - RITA v5 ships containers only (no native build exists), so rita.sh installs the vendor stack under **podman + podman-compose** (owner rule: native first, podman never docker). The CLI wrapper /usr/local/bin/rita runs one-off containers; `rita import ` maps to `import --database --logs=/tmp/zeek_logs`. - Debian's podman ships no unqualified-search registries; rita.sh writes /etc/containers/registries.conf.d/ndr-rita.conf (docker.io) for the short clickhouse image name. - Caveat: if container-to-container dials time out (dial tcp ...:9000 i/o timeout), stale docker firewall chains are the usual cause. Flush them: ```sh iptables -P FORWARD ACCEPT for c in $(iptables -S | awk '/^-N DOCKER/{print $2}'); do iptables -F "$c"; done ``` A reboot clears the DOCKER chains, the jumps into them and br_netfilter entirely; `FORWARD ACCEPT` is only the pre-reboot state. Docker must not be reinstalled on this VM. - The VM has user:user (sudo) and the root password is locked; the `debian` cloud user remains for key-based automation. - Ports: ntopng web 3000, ntopng-suricata web 3002 (3001 stays reserved for the main instance's package-default HTTPS); suricata eve.json at /var/log/suricata/; zeek logs /opt/zeek/logs; rita imports every 15 min via rita-import.timer into the `shaula` dataset. - CrowdSec runs detection-only by default: no bouncer is installed and no decisions are enforced. `BLOCK=1 ./crowdsec.sh add` opts into installing crowdsec-firewall-bouncer in nftables mode (registered via cscli as ndr-firewall-bouncer) — an owner decision, since it bans IPs at the firewall.