modules: per-module OPSEC notes — telemetry footprint per exploit

Adds .opsec_notes to every module's struct skeletonkey_module
(31 entries across 26 module files). One paragraph per exploit
describing the runtime footprint a defender/SOC would see:

  - file artifacts created/modified (exact paths from source)
  - syscall observables (the unshare / socket / setsockopt /
    splice / msgsnd patterns the embedded detection rules look for)
  - dmesg signatures (silent on success vs KASAN oops on miss)
  - network activity (loopback-only vs none)
  - persistence side-effects (/etc/passwd modification, dropped
    setuid binaries, backdoors)
  - cleanup behaviour (callback present? what it restores?)

Each note is grounded in the module's source code + its existing
auditd/sigma/yara/falco detection rules — the OPSEC notes are
literally the inverse of those rules (the rules describe what to
look for; the notes describe what the exploit triggers).

Three intelligence agents researched the modules in parallel,
reading source + MODULE.md, then their proposals were embedded
verbatim via tools/inject_opsec.py (one-shot script, not retained).

Where surfaced:
  - --module-info <name>: '--- opsec notes ---' section between
    detect-rules summary and the embedded auditd/sigma rule bodies.
  - --module-info / --scan --json: 'opsec_notes' top-level string.

Audience uses:
  - Red team: see what footprint each exploit leaves so they pick
    chains that match the host's telemetry posture.
  - Blue team: the notes mirror the existing detection rules from the
    attacker side — easy diff to find gaps in their SIEM coverage.
  - Researchers: per-exploit footprint catalog for technique analysis.

copy_fail_family gets one shared note across all 5 register entries
(copy_fail, copy_fail_gcm, dirty_frag_esp, dirty_frag_esp6,
dirty_frag_rxrpc) since they share exploit infrastructure.

Verification:
  - macOS local: clean build, --module-info nf_tables shows full
    opsec section + CWE + ATT&CK + KEV row from previous commit.
  - Linux (docker gcc:latest): 33 + 54 = 87 passes, 0 fails.

Next: --explain mode (uses these notes + the triage metadata to
render a single 'why is this verdict, what would patch fix it, and
what would the SOC see' page per module).
This commit is contained in:
2026-05-23 10:45:38 -04:00
parent e4a600fef2
commit 39ce4dff09
27 changed files with 31 additions and 0 deletions
@@ -632,6 +632,7 @@ const struct skeletonkey_module sudoedit_editor_module = {
.detect_sigma = sudoedit_editor_sigma,
.detect_yara = NULL,
.detect_falco = NULL,
.opsec_notes = "Sets EDITOR='<helper> -- /etc/passwd' so sudoedit splits on the literal '--' and treats /etc/passwd as an additional editable file. Compiled helper appends 'skel::0:0:skeletonkey:/root:/bin/sh' to the post-'--' target; sudoedit runs the helper as root and copies back. Artifacts: /tmp/skeletonkey-sudoedit-XXXXXX (helper.c, helper binary, optional passwd.before backup); /etc/passwd gets the new 'skel' entry; drops root via 'su skel'. Audit-visible via execve(/usr/bin/sudoedit) with EDITOR/VISUAL/SUDO_EDITOR containing the literal '--' token. No network. Cleanup callback restores /etc/passwd from backup (if root) or removes the 'skel' line, and removes the /tmp dir.",
};
void skeletonkey_register_sudoedit_editor(void)