From 0204c77b4145039131232be665907168f86c2659 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Tue, 28 Jul 2026 17:43:56 +0000 Subject: [PATCH] =?UTF-8?q?docs(prd):=20add=20PRD=200008=20=E2=80=94=20Not?= =?UTF-8?q?ice=20what=20changed=20on=20the=20network,=20not=20everything?= =?UTF-8?q?=20on=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Watching all traffic on all ports produces a firehose nobody reads; inbound scanning is background radiation on any public IP. The high-signal facts are about change. A NEW LISTENING PORT is the single most valuable network fact on a server — a process not accepting connections yesterday and accepting them today is either a deploy or a backdoor. Likewise a new outbound destination from a process that has never made one, and a listener whose owning binary changed. Separately, services bound to 0.0.0.0 that should be on loopback are how a large share of small-team data loss happens, and that is available instantly as posture. Designed to work from socket inventory rather than packet capture, so it can run unprivileged and degrade honestly where it cannot. Co-Authored-By: Claude Opus 4.8 --- ...ged-on-the-network-not-everything-on-it.md | 142 ++++++++++++++++++ prd/README.md | 1 + 2 files changed, 143 insertions(+) create mode 100644 prd/0008-notice-what-changed-on-the-network-not-everything-on-it.md diff --git a/prd/0008-notice-what-changed-on-the-network-not-everything-on-it.md b/prd/0008-notice-what-changed-on-the-network-not-everything-on-it.md new file mode 100644 index 0000000..e161ca9 --- /dev/null +++ b/prd/0008-notice-what-changed-on-the-network-not-everything-on-it.md @@ -0,0 +1,142 @@ +--- +openprd: "0.2" +id: "0008" +title: "Notice what changed on the network, not everything on it" +status: Draft +authors: + - anthony@profullstack.com +created: 2026-07-28 +updated: 2026-07-28 +repo: profullstack/threatcrush +discussion: +implementation: +tags: network-monitor, listeners, egress, port-scan, baseline, modules +supersedes: +superseded-by: +--- + +## Problem + +"Watches all TCP/UDP traffic on all ports" is how `PRD.md` describes this +module, and taken literally it produces a firehose nobody reads. Inbound port +scans are constant background radiation on any public IP; alerting on them is +alerting on the weather. + +**The high-signal facts are about change, not volume:** + +- **A new listening port appeared.** This is the single most valuable network + fact on a server. A process that was not accepting connections yesterday and + is today is either a deploy the operator knows about, or a backdoor. +- **A new outbound destination appeared**, especially from a process that has no + business making connections. Exfiltration and C2 both look like this, and + PRD 0002's install-script correlation depends on exactly this signal. +- **A listener's owning process changed** — same port, different binary. + +**Ports bound to `0.0.0.0` that should be on loopback** are the other recurring +finding: a Postgres or Redis reachable from the internet because the default +was never changed. That is a posture fact, available instantly, and it is how a +large share of small-team data loss happens. + +## Goals + +- A **new listening socket** is reported within one interval, with the process, + binary path and user that owns it. +- A **service exposed to the world that should not be** is reported as posture, + before anything exploits it. +- Inbound scanning is **summarized as weather**, never enumerated. +- Anomalous **outbound** connections are surfaced, since that is where + compromise becomes loss. +- The module works without packet capture, so it can run unprivileged where + necessary and degrade honestly where it cannot. + +## Non-Goals + +- **Not an IDS/IPS.** Signature-matching packet inspection is Suricata's job. +- **Not full packet capture.** Storing traffic on a customer's host is a + liability and a privacy problem. +- **Not blocking** — `firewall-rules` (PRD 0010) owns enforcement. +- **Not netflow collection** for analytics. + +## Users + +- **Solo operators** who do not know what is listening on their own server. +- **Platform engineers** verifying that a fleet exposes only what it should. +- **Incident responders** answering "what was it talking to?". + +## Requirements + +### Observe + +- R1 [P0] **Socket inventory** from `/proc/net/{tcp,tcp6,udp,udp6}` plus + `/proc/*/fd`, giving port, state, bind address, pid, process name, binary + path and user. No elevated capture required. +- R2 [P1] **Connection sampling** for established outbound connections, with + remote address and owning process. +- R3 [P1] **Optional packet-level features** (SYN flood detection, scan + fingerprinting) behind an explicit capability, degrading honestly when + unavailable rather than silently doing less. + +### Detect + +- R4 [P0] **New listener** relative to the learned baseline — port, process, + binary. Critical when the binary is in a temp directory or the process is + unnamed. +- R5 [P0] **Listener bound to all interfaces** for services that are almost + always meant to be local: databases, caches, message brokers, admin ports. +- R6 [P0] **Listener whose owning binary changed** for a known port. +- R7 [P1] **New outbound destination** for a process, against its baseline; and + **any** outbound connection from a process that has never made one. +- R8 [P1] **Inbound scan summarization**: one incident per source per window, + with port count and spread, at low severity. +- R9 [P2] SYN flood and connection-rate anomalies, where capture is available. + +### Report + +- R10 [P0] Route through `alert-system` (PRD 0006). Scans low, new listeners + high, world-exposed databases critical. +- R11 [P0] **State what could not be observed.** If `/proc` inspection is + restricted or capture is unavailable, say so — a quiet module must not be + mistaken for a quiet network. + +## UX Notes + +```bash +threatcrush network-monitor listeners # what is listening, and who owns it +threatcrush network-monitor baseline +threatcrush network-monitor egress # outbound destinations by process +``` + +``` +[CRITICAL] network-monitor · database exposed to the internet + + 0.0.0.0:5432 postgres (pid 812, /usr/lib/postgresql/16/bin/postgres) + reachable from any address; no firewall rule restricting it + + Fix: bind to 127.0.0.1 in postgresql.conf, or restrict with firewall-rules. + Then check the logs for connections you cannot account for. +``` + +## Success Metrics + +- New listener detected within one interval, on a fixture that opens a port. +- Zero alerts from ordinary inbound scanning at defaults, beyond one + low-severity summary per source. +- World-exposed database detection: 100% on a fixture host. +- Baseline warmup prevents alerting on every existing listener at install — + the first run must not be a wall of "new" listeners. + +## Risks & Open Questions + +- **Deploys look exactly like backdoors.** Every legitimate release opens new + listeners. Without a deploy signal this module will alert on normal + operations — the same problem PRD 0002 R14 has with dependency drift, and it + should share whatever answer that gets. +- **`/proc` inspection needs privilege** to attribute sockets to processes owned + by other users. Running unprivileged yields ports without owners, which is + much less useful; the degradation must be stated, not hidden. +- **Egress baselining is noisy for anything that talks to the internet** — + package managers, telemetry, CDNs. Likely needs an allowlist of known-good + destinations to be usable. +- **Open:** is packet capture worth the complexity and privilege at all, given + the socket-inventory approach delivers most of the value? Deferring it keeps + the module unprivileged, which is a real product advantage. diff --git a/prd/README.md b/prd/README.md index 8d8d92f..00ad4ac 100644 --- a/prd/README.md +++ b/prd/README.md @@ -20,3 +20,4 @@ these numbered PRDs cover individual changes to it. | [0005](./0005-catch-the-misconfigurations-that-actually-get-servers-breached.md) | Catch the misconfigurations that actually get servers breached | Draft | code-scanner, config, misconfiguration, hardening, exposure, modules | | [0006](./0006-route-alerts-so-they-keep-being-read.md) | Route alerts so they keep being read | Draft | alert-system, routing, deduplication, escalation, notifications, modules | | [0007](./0007-tell-ssh-compromise-apart-from-ssh-background-noise.md) | Tell SSH compromise apart from SSH background noise | Draft | ssh-guard, brute-force, authentication, tunneling, posture, modules | +| [0008](./0008-notice-what-changed-on-the-network-not-everything-on-it.md) | Notice what changed on the network, not everything on it | Draft | network-monitor, listeners, egress, port-scan, baseline, modules |