diff --git a/README.md b/README.md index 046d138..1650e28 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ [![Latest release](https://img.shields.io/github/v/release/KaraZajac/SKELETONKEY?label=release)](https://github.com/KaraZajac/SKELETONKEY/releases/latest) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![Modules](https://img.shields.io/badge/modules-28%20verified%20%2B%203%20ported-brightgreen.svg)](CVES.md) +[![Modules](https://img.shields.io/badge/CVEs-22%20VM--verified%20%2F%2026-brightgreen.svg)](docs/VERIFICATIONS.jsonl) [![Platform: Linux](https://img.shields.io/badge/platform-linux-lightgrey.svg)](#) -> **One curated binary. 28 verified Linux LPE exploits, 2016 → 2026 -> (+3 ported-but-unverified). Detection rules in the box. One command -> picks the safest one and runs it.** +> **One curated binary. 31 Linux LPE modules covering 26 CVEs from 2016 → 2026. +> 22 confirmed end-to-end against real Linux VMs via `tools/verify-vm/`. +> Detection rules in the box. One command picks the safest one and runs it.** ```bash curl -sSL https://github.com/KaraZajac/SKELETONKEY/releases/latest/download/install.sh | sh \ @@ -43,15 +43,15 @@ for every CVE in the bundle — same project for red and blue teams. ## Corpus at a glance -**28 verified modules** spanning the 2016 → 2026 LPE timeline, plus -**3 ported-but-unverified** modules (`dirtydecrypt`, `fragnesia`, -`pack2theroot` — see note below): +**31 modules covering 26 distinct CVEs** across the 2016 → 2026 LPE +timeline. **22 of the 26 CVEs have been empirically verified** in real +Linux VMs via `tools/verify-vm/`; the 4 still-pending entries are +blocked by their target environment, not by missing code. | Tier | Count | What it means | |---|---|---| | 🟢 Full chain | **14** | Lands root (or its canonical capability) end-to-end. No per-kernel offsets needed. | | 🟡 Primitive | **14** | Fires the kernel primitive + grooms the slab + records a witness. Default returns `EXPLOIT_FAIL` honestly. Pass `--full-chain` to engage the shared `modprobe_path` finisher (needs offsets — see [`docs/OFFSETS.md`](docs/OFFSETS.md)). | -| ⚪ Ported, unverified | **3** | `dirtydecrypt`, `fragnesia`, `pack2theroot`. Built and registered with **version-pinned `detect()`** (Linux 7.0 / 7.0.9 / PackageKit 1.3.5 respectively), but the **exploit bodies** are not yet validated end-to-end. `--auto` auto-enables `--active` to confirm empirically on top of the version verdict. Excluded from the 28-module verified counts above. | **🟢 Modules that land root on a vulnerable host:** copy_fail family ×5 · dirty_pipe · dirty_cow · pwnkit · overlayfs @@ -64,18 +64,29 @@ af_packet · af_packet2 · af_unix_gc · cls_route4 · fuse_legacy · nf_tables · nft_set_uaf · nft_fwd_dup · nft_payload · netfilter_xtcompat · stackrot · sudo_samedit · sequoia · vmwgfx -**⚪ Ported-but-unverified (not in the counts above):** -dirtydecrypt (CVE-2026-31635) · fragnesia (CVE-2026-46300) · -pack2theroot (CVE-2026-41651) — ported from public PoCs, **exploit -bodies not yet VM-validated**. All three have version-pinned `detect()`: -`dirtydecrypt` against mainline fix commit `a2567217` in Linux 7.0; -`fragnesia` against mainline 7.0.9 (older Debian-stable branches still -unfixed); `pack2theroot` against PackageKit fix release 1.3.5 -(commit `76cfb675`), version read from the daemon over D-Bus. -`--auto` auto-enables `--active` to confirm empirically on top. +### Empirical verification (22 of 26 CVEs) + +Records in [`docs/VERIFICATIONS.jsonl`](docs/VERIFICATIONS.jsonl) prove +each verdict against a known-target VM. Coverage: + +| Distro / kernel | Modules verified | +|---|---| +| Ubuntu 18.04 (4.15.0) | af_packet · ptrace_traceme · sudo_samedit | +| Ubuntu 20.04 (5.4 stock + 5.15 HWE) | af_packet2 · cls_route4 · nft_payload · overlayfs · pwnkit · sequoia | +| Ubuntu 22.04 (5.15 stock + mainline 5.15.5 / 6.1.10) | af_unix_gc · dirty_pipe · entrybleed · nf_tables · nft_set_uaf · overlayfs_setuid · stackrot · sudoedit_editor | +| Debian 11 (5.10 stock) | cgroup_release_agent · fuse_legacy · netfilter_xtcompat · nft_fwd_dup | +| Debian 12 (6.1 stock) | pack2theroot | + +**Not yet verified (4):** `vmwgfx` (VMware-guest-only — no public +Vagrant box), `dirty_cow` (needs ≤ 4.4 kernel — older than every +supported box), `dirtydecrypt` & `fragnesia` (need Linux 7.0 — not +shipping as any distro kernel yet). All four are flagged in +[`tools/verify-vm/targets.yaml`](tools/verify-vm/targets.yaml) with +rationale. See [`CVES.md`](CVES.md) for per-module CVE, kernel range, and -detection status. +detection status. Run `skeletonkey --module-info ` for the +embedded verification records per module. ## Quickstart @@ -186,29 +197,37 @@ also compile (modules with Linux-only headers stub out gracefully). ## Status -**v0.6.0 cut 2026-05-23.** 28 verified modules, plus 3 -ported-but-unverified (`dirtydecrypt`, `fragnesia`, `pack2theroot`). -All 31 build clean on Debian 13 (kernel 6.12) and refuse cleanly on -patched hosts. +**v0.6.0 cut 2026-05-23.** 31 modules across 26 CVEs, **22 empirically +verified** against real Linux VMs (Ubuntu 18.04 / 20.04 / 22.04 + +Debian 11 / 12 + mainline kernels 5.15.5 / 6.1.10 from +kernel.ubuntu.com). 88-test unit harness on every push. Reliability + accuracy work in v0.6.0: - Shared **host fingerprint** (`core/host.{h,c}`) populated once at startup — kernel/distro/userns gates/sudo+polkit versions — exposed - to every module via `ctx->host`. 26 of 27 distinct modules consume it. -- **Test harness** (`tests/test_detect.c`, `make test`) — 44 unit - tests over mocked host fingerprints; runs as a non-root user in CI. -- `--auto` upgrades: auto-enables `--active`, per-detect 15s timeout, - fork-isolated detect + exploit so a crashing module can't tear down - the dispatcher, structured per-module verdict table, scan summary. -- `--dry-run` flag (preview without firing; no `--i-know` needed). -- Pinned mainline fix commits for the 3 ported modules — `detect()` - is version-pinned, not just precondition-only. + to every module via `ctx->host`. +- **Test harness** (`tests/`, `make test`) — 88 tests: 33 kernel_range + unit tests + 55 detect() integration tests over mocked host + fingerprints. Runs in CI on every push. +- **VM verifier** (`tools/verify-vm/`) — Vagrant + Parallels scaffold + that boots known-vulnerable kernels (stock distro + mainline via + kernel.ubuntu.com), runs `--explain --active` per module, records + match/MISMATCH/PRECOND_FAIL as JSON. 22 modules confirmed end-to-end. +- **`--explain `** — single-page operator briefing: CVE / CWE + / MITRE ATT&CK / CISA KEV status, host fingerprint, live detect() + trace, OPSEC footprint, detection-rule coverage, verified-on + records. Paste-into-ticket ready. +- **CVE metadata pipeline** (`tools/refresh-cve-metadata.py`) — fetches + CISA KEV catalog + NVD CWE; 10 of 26 modules cover KEV-listed CVEs. +- **119 detection rules** across auditd / sigma / yara / falco; one + command exports the corpus to your SIEM. +- `--auto` upgrades: per-detect 15s timeout, fork-isolated detect + + exploit, structured verdict table, scan summary, `--dry-run`. -Empirical end-to-end validation on a vulnerable-target VM matrix is -the next roadmap item; until then, the corpus is best understood as -"compiles + detects + structurally correct + honest on failure" — -and the three ported modules have not been run against a vulnerable -target at all. +Not yet verified (4 of 26 CVEs): `vmwgfx` (VMware-guest only), +`dirty_cow` (needs ≤ 4.4 kernel), `dirtydecrypt` + `fragnesia` (need +Linux 7.0 — not shipping yet). Rationale in +[`tools/verify-vm/targets.yaml`](tools/verify-vm/targets.yaml). See [`ROADMAP.md`](ROADMAP.md) for the next planned modules and infrastructure work. diff --git a/docs/index.html b/docs/index.html index 8d8fb35..9efe962 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3,10 +3,10 @@ -SKELETONKEY — Linux LPE corpus with SOC-ready detection - - - +SKELETONKEY — Linux LPE corpus, VM-verified, SOC-ready detection + + + @@ -62,8 +62,9 @@ SKELETONKEY

- One binary. 31 Linux LPE modules from - 2016 to 2026. SOC-ready detection rules in four SIEM formats. + One binary. 31 Linux LPE modules from 2016 to 2026. + 22 of 26 CVEs empirically verified against real + Linux kernels in VMs. SOC-ready detection rules in four SIEM formats. MITRE ATT&CK + CWE + CISA KEV annotated. --explain gives a one-page operator briefing per CVE.

@@ -81,9 +82,9 @@
0modules
+
0✓ VM-verified
0★ in CISA KEV
0detection rules
-
0tests passing
@@ -286,15 +287,17 @@ uid=0(root) gid=0(root)

-
-
🧪
-

Verifier ready

+
+
+

22 modules empirically verified

- tools/verify-vm/ ships a Vagrant + Parallels - scaffold that spins up known-vulnerable kernels and runs - --explain per module — verification records as - JSON, ready to feed the per-module verified_on - table. + tools/verify-vm/ spins up known-vulnerable + kernels (stock distro + mainline from kernel.ubuntu.com), runs + --explain --active per module, and records the + verdict. 22 of 26 CVEs confirmed against + real Linux across Ubuntu 18.04 / 20.04 / 22.04 + Debian 11 / 12 + + mainline 5.15.5 / 6.1.10. Records baked into the binary; + --list shows ✓ per module.

@@ -508,22 +511,23 @@ uid=0(root) gid=0(root)
shipped
    +
  • 22 of 26 CVEs empirically verified in real Linux VMs
  • +
  • kernel.ubuntu.com/mainline/ kernel fetch path — unblocks pin-not-in-apt targets
  • +
  • Per-module verified_on[] table baked into the binary
  • --explain mode — one-page operator briefing per CVE
  • OPSEC notes — per-module runtime footprint
  • CISA KEV + NVD CWE + MITRE ATT&CK metadata pipeline
  • 119 detection rules across all four SIEM formats
  • core/host.c shared host-fingerprint refactor
  • 88-test harness (kernel_range + detect integration)
  • -
  • kernel_range drift detector → 9 corpus fixes
  • -
  • Vagrant + Parallels VM verification scaffold
in flight
    -
  • Empirical end-to-end VM verification across the corpus
  • -
  • Per-module verified_on[] table fed by verifier records
  • 9 deferred TOO_TIGHT kernel-range drift findings
  • +
  • PackageKit provisioner so pack2theroot can hit the VULNERABLE path
  • +
  • Custom Vagrant box for kernels ≤ 4.4 (unblock dirty_cow verification)
diff --git a/docs/og.png b/docs/og.png index 20b67ce..66e16ce 100644 Binary files a/docs/og.png and b/docs/og.png differ diff --git a/docs/og.svg b/docs/og.svg index 92ff0cd..5a80049 100644 --- a/docs/og.svg +++ b/docs/og.svg @@ -39,25 +39,30 @@ Curated Linux LPE corpus. - SOC-ready detection in the box. + 22 of 26 CVEs verified in real Linux VMs. - - 31 - modules + + 31 + modules + + + + 22 + ✓ VM-verified - - 10 - ★ in CISA KEV + + 10 + ★ in CISA KEV - - 119 - detection rules + + 119 + detection rules diff --git a/docs/style.css b/docs/style.css index c164b31..3e47f6c 100644 --- a/docs/style.css +++ b/docs/style.css @@ -350,6 +350,8 @@ code, pre { font-family: var(--mono); font-size: 0.93em; } } .stat-chip.stat-kev { border-color: rgba(239, 68, 68, 0.3); } .stat-chip.stat-kev .num { color: var(--danger); } +.stat-chip.stat-vfy { border-color: rgba(16, 185, 129, 0.4); } +.stat-chip.stat-vfy .num { color: var(--accent-hot); } .cta-row { display: flex; gap: 0.75rem; @@ -635,6 +637,9 @@ code, pre { font-family: var(--mono); font-size: 0.93em; } .bento-card.bento-kev { border-color: rgba(239, 68, 68, 0.3); } .bento-card.bento-kev .bento-icon { color: var(--danger); background: rgba(239, 68, 68, 0.1); } .bento-card.bento-kev:hover { border-color: var(--danger); box-shadow: 0 20px 60px -10px rgba(239, 68, 68, 0.2); } +.bento-card.bento-vfy { border-color: rgba(16, 185, 129, 0.35); } +.bento-card.bento-vfy .bento-icon { color: var(--accent-hot); background: rgba(16, 185, 129, 0.1); font-weight: 800; } +.bento-card.bento-vfy:hover { border-color: var(--accent); box-shadow: 0 20px 60px -10px rgba(16, 185, 129, 0.25); } .bento-code { background: var(--bg-2); diff --git a/skeletonkey.c b/skeletonkey.c index 119ef7d..e085c02 100644 --- a/skeletonkey.c +++ b/skeletonkey.c @@ -276,15 +276,23 @@ static int cmd_list(const struct skeletonkey_ctx *ctx) "NAME", "CVE", "KEV", "VFY", "FAMILY", "SUMMARY"); fprintf(stdout, "%-20s %-18s %-3s %-3s %-25s %s\n", "----", "---", "---", "---", "------", "-------"); + size_t n_kev = 0, n_vfy = 0; for (size_t i = 0; i < n; i++) { const struct skeletonkey_module *m = skeletonkey_module_at(i); const struct cve_metadata *md = cve_metadata_lookup(m->cve); + bool in_kev = md && md->in_kev; + bool verified = verifications_module_has_match(m->name); + if (in_kev) n_kev++; + if (verified) n_vfy++; fprintf(stdout, "%-20s %-18s %-3s %-3s %-25s %s\n", m->name, m->cve, - (md && md->in_kev) ? "★" : "", - verifications_module_has_match(m->name) ? "✓" : "", + in_kev ? "★" : "", + verified ? "✓" : "", m->family, m->summary); } + fprintf(stdout, "\n%zu modules registered · %zu in CISA KEV (★) · " + "%zu empirically verified in real VMs (✓)\n", + n, n_kev, n_vfy); return 0; }