Vulnerability Management for People Who Enjoy Finding Their Own Problems
Running Greenbone/GVM and daily Nmap discovery on KaliLinux. Because knowing what's on your network is better than finding out via a breach notification.
If you run a home lab long enough, you hit a very specific problem - you have 62 hosts across six VLANs and you can’t remember what half of them are.
The fix is automated network discovery and vulnerability scanning. The side effect is finding three services you forgot you turned on, two devices you don’t recognise, and an NTP misconfiguration that has apparently been sitting there since 2023.
KaliLinux as the Security VM
The KaliLinux VM at 172.16.50.4 exists for one reason: it came with all the security tooling pre-installed, and spending an afternoon setting up scanners on a vanilla Debian VM felt like building a workbench before you could start woodworking. Kali is the workbench.
The VM runs:
- Greenbone Vulnerability Manager (GVM) - full enterprise vulnerability scanner, web UI at
https://172.16.50.4:9392 - Nmap - network discovery and port scanning
- Cron automation - scheduled pipelines that run both without me touching them
Greenbone GVM: The Heavy Scanner
GVM (the open-source community edition of Greenbone’s commercial scanner) keeps a feed of CVEs and tests your hosts against them. Setting it up isn’t trivial - it brings along PostgreSQL, Redis, the OpenVAS scanner daemon, gvmd, and the web UI - but you end up with the same capability that costs serious money in enterprise licensing.
The original lab setup:
- Scan target - All 6 VLANs (172.16.10.0/24 through 172.16.250.0/24)
- Schedule - Weekly, Sundays at 3am UTC
- Scan config - “Full and Fast” (thorough without running all weekend)
- Credentials - SNMP community strings and SSH keys for authenticated scanning
Authenticated scanning is the part that matters. An unauthenticated scan just tells you which ports are open. An authenticated scan logs into the Linux VM, checks the installed package versions, and tells you that your PostgreSQL build has a specific CVE patched three point-releases ago. It’s the difference between knowing a door exists and knowing whether it’s locked.
Nmap Discovery: The Daily Pulse
Where GVM runs weekly and goes deep, Nmap runs daily and goes wide:
# Runs daily at 02:00 UTC via cronnmap -sn -oX /opt/homelab/discovery/scan_$(date +%Y-%m-%d).xml 172.16.0.0/16A script converts the XML output to JSON and enriches it with MAC address lookups over SSH against the Juniper core switch. The switch’s ARP table knows which MAC address sits behind each IP, and the MAC OUI tells you who made the NIC. A Raspberry Pi shows up under Raspberry Pi Trading. A cheap smart plug shows up under whatever ODM made its WiFi chip.
The JSON files sit in /opt/homelab/discovery/ behind a small HTTP server on port 8080, which Clawdia (the AI assistant) called each day to put together the network summary.
The Automation Scripts
Four shell scripts in F:\Projects\lab-automation\scripts\ set the whole thing up:
01-install-greenbone.sh- Idempotent GVM installer. You can run it on a fresh Kali VM and walk away with a working scanner, which matters because VMs get rebuilt and “I remember how I set this up” is not a recovery plan.02-nmap-discovery.sh- Sets up the daily Nmap job, the ARP enrichment step, and the HTTP results server.03-setup-cron.sh- Installs the cron schedules: daily Nmap at 2am UTC, weekly GVM feed sync on Sunday at 2am UTC, and the scan itself an hour later at 3am UTC.04-configure-gvm.sh- Creates the GVM scan target across all six VLANs, attaches the credentials, and outputs the task and target UUIDs. Write those UUIDs down. You will go looking for them later.
The Use Case: Knowing What’s Running Before You Forget
The practical payoff is a daily check-in that replaced a much worse habit: SSHing into the firewall to eyeball DHCP leases and wondering if a mystery IP is a new gadget or something worth worrying about.
At 12.15pm AEST, Clawdia sent a WhatsApp voice note comparing today’s scan JSON against yesterday’s. It sounded like a weather report for the LAN:
“Two new hosts appeared on the IoT VLAN overnight: one Espressif device (likely ESP32) and one device with an unknown OUI. Three hosts from yesterday are no longer responding. Your Synology NAS is healthy. No significant changes to the VM estate.”
It’s the kind of thing you don’t think you need until it’s running, and then you don’t want to go back.
What GVM Actually Finds
In a home lab kept reasonably up to date, GVM finds fewer headline CVEs than you might expect. What it reliably catches is config drift:
- Weak cipher suites on older gear (the Synology NAS still had TLS 1.0 enabled for legacy compatibility - now disabled)
- Default SNMP community strings on managed switches (replaced with a custom string stored in the vault)
- Outdated firmware on access points and switches (the Aruba APs were 14 months behind - updated)
- Missing security headers on internal web UIs (added via Traefik middleware)
None of these are cinematic. All of them are real attack surface that sat there quietly until an automated scan complained about them.
Update - August 2026
The scripts live under F:\Projects\homelab\scripts\kali\ now, and both schedules changed.
The daily scan stopped being an Nmap sweep and became an identity register. I rewrote it on 10 July 2026 so it no longer leads with Nmap at all. Instead, it pulls the DHCP bindings and ARP table straight off the Juniper core over a read-only SSH session. Because the core switch is both the DHCP server and the L3 gateway for every VLAN, it already knows every device that has asked for an address or spoken on the wire.
Keying the inventory on MAC address instead of IP fixed the main annoyance with the original pipeline: a phone picking up a new DHCP lease is not a new device, and being told it is every day just trains you to ignore the alerts. Now a known MAC changing IP is purely informational, and only a never-before-seen MAC triggers a notification. Randomised, locally administered MACs (which modern phones mint per SSID) get logged without paging me, otherwise every visitor looks like an incident. I seeded the baseline with 63 devices.
It moved to midday instead of 2am. Partly because a lunchtime summary actually gets read, and mostly because the Kali VM’s timezone had been sitting on America/New_York for longer than I care to admit - so “2am” wasn’t the hour anyone thought it was. I flipped it to Australia/Brisbane the same day.
GVM now runs monthly, not weekly. First Sunday of the month at 3am UTC. Weekly full-and-fast scans across six subnets produced the exact same report every seven days and stopped getting read, which is worse than useless - it just gives you the illusion of coverage. The CVE feed sync still runs weekly so the vulnerability database stays fresh.
Credentialed scanning finally went live on 10 July 2026, and the results were a great argument for doing it earlier. All four Linux VMs authenticated cleanly. At the default 70% confidence threshold the lab came back almost spotless: zero critical, zero high, two medium, and ten low findings (all TCP timestamp disclosures). Below that confidence threshold sat 55 “critical” and 126 “high” items - every single one an unconfirmed banner guess. That gap is the whole case for credentialed scanning: unauthenticated scanners guess from version strings, and their guesses are loud and mostly wrong.
I ran a credentialed scan against the Juniper core switch the same day using the read-only MCP key. Junos 23.4R2-S7.4 came back with zero confirmed advisories and didn’t drop a single ping during the scan. The four highs it flagged were SSH banner false positives - Juniper backports security fixes without bumping the OpenSSH banner version, so every scanner on earth thinks their switches are vulnerable to bugs patched years ago.
The alert channel moved too. After I retired Clawdia in June, new-device alerts moved to Telegram, pushed from Kali through Homer’s gateway with no LLM in the loop. A brand-new MAC address is a fact, not a writing prompt - running it through a model just adds a way for it to come out wrong.
Update - October 2026
- Discovery moved to 6.40am and folded into the single 7am morning report - Rather than firing a separate midday message, the Kali discovery script now runs twenty minutes before the morning digest and pushes any newly seen MACs over a locked-down, single-purpose SSH pipe into the assistant VM’s spool directory. If a new device joined overnight, it shows up in the 7am report alongside everything else. If nothing changed, it stays quiet.
- Unnecessary listeners on Kali were shut down - Because discovery results now push straight to the assistant VM’s spool, the old port-8080 HTTP server on Kali had no reason to exist, so I removed it. I also bound Greenbone’s web UI strictly to
127.0.0.1(accessed over an SSH tunnel when needed) - a vulnerability scanner shouldn’t expose its own web interface to the lab subnet when I only open it once a month.