Add tamper-evidence: package-DB integrity, self-integrity, dead-man's switch
Answers two hard questions: "what guards the hashes FIM trusts?" and "how do we make the sensor itself hard to silently disable?" — within the honest limit that a root attacker who shares your privileges can't be fully stopped on-box, only made loud. - pkgdb.py: guards the package DB that `pacman -Qkk` trusts. Anchors a fingerprint of /var/lib/pacman/local (refreshed ONLY by the pacman hook) and cross-checks pacman.log; a DB change with no logged transaction is flagged pkgdb_tamper (CRITICAL, sid 100021) — catches an attacker rewriting a stored checksum to mask a modified binary. Verified end-to-end against a simulated hash-overwrite. - selfprotect.py: Sentinel's own binaries/config/units/hook are always in the FIM watch set (self-integrity); a heartbeat is written each loop; an external `watchdog` command polls a remote dashboard and pushes if the sensor goes silent or unreachable — silence becomes the alarm. - daemon: heartbeat + slow-cadence pkgdb check; DB anchor re-anchored in build_fim_baseline so the pacman hook refreshes it after each transaction - web: /api/status now reports heartbeat_age/stale; dashboard shows it - cli: pkgdb-check, watchdog (--url/--token/--max-age, bypasses min-severity) - config: pkgdb_verify/_interval, heartbeat_max_age - README: threat model (trust-anchor problem) + hardening layers (immutability, signed-package + external anchor); reframes "anti-rootkit" as tamper-evidence - tests: +8 (DB fingerprint, anchor/transaction logic, pacman.log parse, heartbeat + watchdog verdicts). 80/80 pass Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
5d577b624f
commit
34bc09041a
13 changed files with 465 additions and 9 deletions
50
README.md
50
README.md
|
|
@ -239,6 +239,52 @@ notify_ntfy_url = "https://ntfy.sh"
|
|||
notify_ntfy_topic = "enodia-7Hq2x" # keep this secret — it's the access control
|
||||
```
|
||||
|
||||
## Tamper-evidence & self-protection
|
||||
|
||||
An attacker's first move against a sensor is to disable or blind it — and on a
|
||||
box where they have root, *any* purely-local defense is ultimately defeatable
|
||||
(they share your privileges). Sentinel doesn't pretend otherwise. The goal is to
|
||||
make tampering **evident** by anchoring trust where the attacker has less
|
||||
control, and to make going silent *loud*.
|
||||
|
||||
**Package-DB integrity.** `pacman -Qkk` trusts the local package database — so a
|
||||
root attacker can modify `/usr/bin/ssh` *and* rewrite its stored checksum, and
|
||||
verification passes. Sentinel guards the DB itself: a legitimate change only
|
||||
happens during a logged transaction, so it anchors a fingerprint of
|
||||
`/var/lib/pacman/local` (refreshed *only* by the pacman hook) and cross-checks
|
||||
`pacman.log`. A DB change with **no corresponding transaction** is flagged
|
||||
`pkgdb_tamper` (CRITICAL, `sid 100021`) — directly catching the "overwrite the
|
||||
hashes" attack.
|
||||
|
||||
**Self-integrity.** Sentinel's own binaries, config, systemd units, and pacman
|
||||
hook are always in the FIM watch set, so tampering with the watchdog trips the
|
||||
watchdog.
|
||||
|
||||
**Dead-man's switch.** The daemon writes a heartbeat every loop; the dashboard
|
||||
exposes its age. Run an external watcher on another host (over Tailscale) and
|
||||
*silence becomes the alarm*:
|
||||
|
||||
```bash
|
||||
# on a SEPARATE machine — alerts you if the sensor or the whole box goes dark
|
||||
enodia-sentinel watchdog --url http://100.x.x.x:8787 --token <T> --max-age 120
|
||||
```
|
||||
|
||||
**Hardening (the layers beyond on-box detection):**
|
||||
|
||||
1. **Immutability** — `chattr +i` Sentinel's binaries, config, baselines, and
|
||||
the pacman hook so even root must visibly clear the flag first.
|
||||
2. **Cryptographic anchor (next)** — verify files against the *signed* package
|
||||
in the cache rather than the mutable DB; a maintainer's PGP signature is a
|
||||
root of trust the attacker doesn't hold.
|
||||
3. **External anchor (next)** — mirror the DB/FIM fingerprints off-box so a
|
||||
local attacker can't refresh the anchor to cover their tracks.
|
||||
|
||||
> On "anti-rootkit": the robust version isn't stealth (fragile, and a genuine
|
||||
> dual-use rootkit technique) — it's tamper-*evidence*. Don't hide; be
|
||||
> un-hideable. The durable defenses move the trust anchor below or outside the
|
||||
> attacker: signatures, external monitors, and ultimately the kernel (the eBPF
|
||||
> roadmap) rather than userland the attacker can rewrite.
|
||||
|
||||
## File integrity monitoring (Tripwire-style)
|
||||
|
||||
Detects tampering with binaries and critical configs by **content hash**, so it
|
||||
|
|
@ -349,6 +395,10 @@ regression suite for both.
|
|||
|
||||
## Project status
|
||||
|
||||
v0.6 — adds **tamper-evidence**: out-of-band package-DB integrity
|
||||
(catches rewritten checksums), self-integrity of Sentinel's own footprint, and a
|
||||
dead-man's-switch heartbeat with an external watchdog.
|
||||
|
||||
v0.5 — adds **file integrity monitoring** (SHA-256 baseline + `pacman -Qkk`
|
||||
verification, auto-refreshed by a pacman hook) and **false-positive triage**
|
||||
via package-ownership provenance.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue