Generate event rule documentation
This commit is contained in:
parent
e43d7689a0
commit
7f4d5b42fd
8 changed files with 378 additions and 5 deletions
|
|
@ -40,6 +40,51 @@ def find_rule(cfg: Config, sid: int) -> dict[str, Any] | None:
|
|||
return None
|
||||
|
||||
|
||||
def render_markdown(cfg: Config) -> str:
|
||||
"""Render active event-rule metadata as operator documentation."""
|
||||
lines = [
|
||||
"# Enodia Sentinel Event Rule Reference",
|
||||
"",
|
||||
"Generated from the active exec/syscall rule defaults plus any configured "
|
||||
"`exec_rules_file` entries.",
|
||||
"",
|
||||
"Use `enodia-sentinel rules list/show/test` to inspect rules and validate "
|
||||
"event fixtures locally.",
|
||||
"",
|
||||
]
|
||||
for rule in list_rules(cfg):
|
||||
doc = _RULE_DOCS.get(rule["sid"], {})
|
||||
lines.extend([
|
||||
f"## SID {rule['sid']}: {rule['msg']}",
|
||||
"",
|
||||
f"- Event: `{rule['event']}`",
|
||||
f"- Signature: `{rule['signature']}`",
|
||||
f"- Classtype: `{rule['classtype']}`",
|
||||
f"- Severity: `{rule['severity']}`",
|
||||
f"- Origin: `{rule['origin']}`",
|
||||
"",
|
||||
"Match fields:",
|
||||
])
|
||||
conditions = rule.get("conditions", {})
|
||||
if conditions:
|
||||
for key, value in conditions.items():
|
||||
lines.append(f"- `{key}`: {_format_condition(value)}")
|
||||
else:
|
||||
lines.append("- none")
|
||||
lines.extend([
|
||||
"",
|
||||
"Expected false positives:",
|
||||
])
|
||||
for fp in doc.get("false_positives", _default_false_positives(rule)):
|
||||
lines.append(f"- {fp}")
|
||||
lines.extend([
|
||||
"",
|
||||
f"Drill or fixture: {doc.get('drill', _default_drill(rule))}",
|
||||
"",
|
||||
])
|
||||
return "\n".join(lines).rstrip() + "\n"
|
||||
|
||||
|
||||
def load_event_json(path: str) -> dict[str, Any]:
|
||||
if path == "-":
|
||||
import sys
|
||||
|
|
@ -96,6 +141,105 @@ def _syscall_rule_record(rule: SyscallRule, origin: str) -> dict[str, Any]:
|
|||
}
|
||||
|
||||
|
||||
_RULE_DOCS: dict[int, dict[str, Any]] = {
|
||||
100001: {
|
||||
"false_positives": [
|
||||
"Temporary build or installer helpers intentionally executed from `/tmp`, `/var/tmp`, or `/dev/shm`.",
|
||||
"One-shot administrative diagnostics copied into a writable directory.",
|
||||
],
|
||||
"drill": "`sentinel-redteam ebpf_exec` fires a short-lived writable-path execution event when the eBPF exec monitor is enabled.",
|
||||
},
|
||||
100002: {
|
||||
"false_positives": [
|
||||
"Security training labs or safe self-tests that intentionally include reverse-shell command text.",
|
||||
"Benign scripts containing literal `/dev/tcp` or `pty.spawn` examples in their argv.",
|
||||
],
|
||||
"drill": "`sentinel-redteam ebpf_exec` emits a `/dev/tcp` argv fixture; `rules test` can validate a captured exec JSON event offline.",
|
||||
},
|
||||
100003: {
|
||||
"false_positives": [
|
||||
"Legitimate web applications invoking maintenance scripts through shell wrappers.",
|
||||
"Database or web service containers whose entrypoint intentionally spawns an interpreter.",
|
||||
],
|
||||
"drill": "Use `rules test` with an exec event whose `parent_comm` is a web/database service and whose `filename` is an interpreter.",
|
||||
},
|
||||
100004: {
|
||||
"false_positives": [
|
||||
"Bootstrap scripts that intentionally pipe downloaded install content into a shell.",
|
||||
"Developer setup tooling run interactively during provisioning.",
|
||||
],
|
||||
"drill": "Use `rules test` with argv like `curl http://example.invalid/x | sh`.",
|
||||
},
|
||||
100060: {
|
||||
"false_positives": [
|
||||
"JIT runtimes or emulators that make pages writable and executable.",
|
||||
"Security tooling that deliberately tests W^X policy.",
|
||||
],
|
||||
"drill": "Use `rules test` with syscall `mprotect` and `args[2]` containing write+exec permissions, for example `0x6`.",
|
||||
},
|
||||
100061: {
|
||||
"false_positives": [
|
||||
"JIT runtimes, emulators, or language VMs that allocate RWX memory.",
|
||||
"Compatibility layers that request executable writable mappings.",
|
||||
],
|
||||
"drill": "Use `rules test` with syscall `mmap` and `args[2]` containing write+exec permissions.",
|
||||
},
|
||||
100062: {
|
||||
"false_positives": [
|
||||
"Browsers, sandbox helpers, and runtimes that legitimately use anonymous memfd files.",
|
||||
"Container or IPC frameworks using memfd as a transport primitive.",
|
||||
],
|
||||
"drill": "Use `rules test` with syscall `memfd_create`; include `text` to document the captured name.",
|
||||
},
|
||||
100063: {
|
||||
"false_positives": [
|
||||
"Debuggers, profilers, crash handlers, and endpoint tooling that attach to processes.",
|
||||
"Developer sessions running `strace`, `gdb`, or similar tracing tools.",
|
||||
],
|
||||
"drill": "Use `rules test` with syscall `ptrace` and request `16` (`PTRACE_ATTACH`) or `0x4206` (`PTRACE_SEIZE`).",
|
||||
},
|
||||
100064: {
|
||||
"false_positives": [
|
||||
"Browsers, container runtimes, and sandboxed services enabling seccomp as normal hardening.",
|
||||
"Security test harnesses validating seccomp policy.",
|
||||
],
|
||||
"drill": "Use `rules test` with syscall `seccomp`, or syscall `prctl` with `arg0` set to `22` (`PR_SET_SECCOMP`).",
|
||||
},
|
||||
100065: {
|
||||
"false_positives": [
|
||||
"Debuggers, profilers, memory scanners, and EDR tools inspecting another process.",
|
||||
"Backup or checkpoint tooling that reads process memory intentionally.",
|
||||
],
|
||||
"drill": "Use `rules test` with syscall `process_vm_readv` or `process_vm_writev`.",
|
||||
},
|
||||
100066: {
|
||||
"false_positives": [
|
||||
"Databases, crypto agents, and credential stores locking sensitive memory.",
|
||||
"Realtime or performance-sensitive services using `mlock` intentionally.",
|
||||
],
|
||||
"drill": "Use `rules test` with syscall `mlock`, `mlock2`, or `mlockall`.",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _format_condition(value: Any) -> str:
|
||||
if isinstance(value, list):
|
||||
return ", ".join(f"`{v}`" for v in value) or "`[]`"
|
||||
return f"`{value}`"
|
||||
|
||||
|
||||
def _default_false_positives(rule: dict[str, Any]) -> list[str]:
|
||||
if rule.get("origin") == "configured":
|
||||
return ["Operator supplied rule; document expected benign matches beside the TOML rule."]
|
||||
return ["No documented benign case yet; validate with `rules test` before tuning."]
|
||||
|
||||
|
||||
def _default_drill(rule: dict[str, Any]) -> str:
|
||||
if rule.get("origin") == "configured":
|
||||
return "Use `enodia-sentinel rules test <event-json>` with a fixture that should match the configured rule."
|
||||
return "Use `enodia-sentinel rules test <event-json>` with a representative fixture."
|
||||
|
||||
|
||||
def _event_kind(event: dict[str, Any]) -> str:
|
||||
explicit = str(event.get("event") or event.get("type") or "").lower()
|
||||
if explicit in {"exec", "execve"}:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue