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
|
|
@ -100,8 +100,14 @@ async function refresh(){
|
|||
document.getElementById("host").textContent = st.host || "";
|
||||
document.getElementById("ver").textContent = "v"+st.version;
|
||||
document.getElementById("ebpf").textContent = "eBPF: "+(st.ebpf||"?");
|
||||
document.getElementById("status").textContent =
|
||||
st.running ? "daemon running" : "daemon NOT running";
|
||||
let hb = "";
|
||||
if (st.heartbeat_age != null)
|
||||
hb = st.heartbeat_stale
|
||||
? ` ⚠ heartbeat STALE (${Math.round(st.heartbeat_age)}s) — possible tampering`
|
||||
: ` ♥ ${Math.round(st.heartbeat_age)}s ago`;
|
||||
const st_el = document.getElementById("status");
|
||||
st_el.textContent = (st.running ? "daemon running" : "daemon NOT running") + hb;
|
||||
st_el.style.color = (st.running && !st.heartbeat_stale) ? "" : "var(--crit)";
|
||||
const c = st.counts||{};
|
||||
const cards = document.getElementById("cards"); cards.innerHTML="";
|
||||
for(const [lbl,key] of [["CRITICAL","crit"],["HIGH","high"],["MEDIUM","med"]]){
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue