2c4cde1031d5621bb2a3c4581624078957a3c909
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2c4cde1031 |
verify-vm: fix Vagrantfile for first real run
Two issues surfaced during the first end-to-end verification attempt
(verify.sh pwnkit, generic/ubuntu2004):
1. 'The machine with the name skk-pwnkit was not found' — the original
Vagrantfile used c.vm.box/hostname without a c.vm.define block, so
passing a machine name to 'vagrant up <name>' had nothing to match.
Wrap every per-machine config in 'c.vm.define host do |m| ... end'
so each module gets its own tracked machine in
.vagrant/machines/skk-<module>/parallels/.
2. 'Installing the proper version of Parallels Tools' fails on
Ubuntu 20.04: 'Error: current Linux kernel version 5.4.0-169-generic
is outdated and not supported'. The latest Parallels Tools wants
newer guest kernels. We don't need the Tools at all — rsync
sync_folder over plain SSH does our source mount. Disable both:
p.update_guest_tools = false
p.check_guest_tools = false
Verified externally (with Apple hypervisor as a temporary bypass
during the user's pending Parallels-extension allow + Mac restart):
the VM boots, SSH connects, network works. The only remaining gate
was the Parallels Tools provisioner now skipped.
|
||
|
|
554a58757e |
tools/verify-vm: turnkey Vagrant + Parallels verification scaffolding
Closes the gap between 'detect() compiles and passes unit tests' and
'exploit() actually works on a real vulnerable kernel'. One-time
setup + one command per module to verify against a known-vulnerable
guest, with results emitted as JSON verification records.
Files:
setup.sh — one-shot bootstrap. Installs Vagrant via brew if
missing, installs vagrant-parallels plugin, pre-
downloads 5 base boxes (~5 GB):
generic/ubuntu1804 (4.15.0)
generic/ubuntu2004 (5.4.0 + HWE)
generic/ubuntu2204 (5.15.0 + HWE)
generic/debian11 (5.10.0)
generic/debian12 (6.1.0)
Idempotent; can pass --boxes subset.
Vagrantfile — single parameterized config driven by SKK_VM_*
env vars. Provisioners: build-deps install,
kernel pin (apt + snapshot.debian.org fallback),
build-and-verify (kept run='never' so verify.sh
invokes explicitly after reboot if pin'd).
targets.yaml — module → (box, kernel_pkg, kernel_version,
expect_detect, notes) mapping for all 26 modules.
3 marked manual: true (vmwgfx needs VMware guest;
dirtydecrypt + fragnesia need Linux 7.0 not yet
shipping as distro kernel).
verify.sh — entrypoint. 'verify.sh <module>' provisions if
needed, pins kernel + reboots if needed, runs
'skeletonkey --explain --active' inside the VM,
parses VERDICT, compares to expect_detect, emits
JSON verification record. --list shows the full
target matrix. --keep / --destroy lifecycle flags.
README.md — workflow + extending the targets table.
Design notes:
- Pure bash + awk targets.yaml parsing — no PyYAML dep (macOS Python
is PEP-668 'externally managed' and refuses pip --user installs).
- Sources of vulnerable kernel packages: stock distro kernels where
they're below the fix backport, otherwise pinned via apt with
snapshot.debian.org as last-resort fallback (the Debian apt
snapshot archive is the canonical source for historical kernel .deb
packages).
- Repo mounted at /vagrant via rsync (not 9p — vagrant-parallels'
9p is finicky on macOS Sequoia per the plugin issue tracker).
- VM lifecycle defaults to suspend-after-verify so the next run
resumes in ~5s instead of cold-booting.
- kernel pin reboots are handled by checking 'uname -r' after the
pin provisioner and triggering 'vagrant reload' if mismatched.
Verification records (JSON on stdout per run) are intended to feed a
per-module verified_on[] table in a follow-up commit — that's the
'permanent trust artifact' angle from the earlier roadmap discussion.
Smoke tests (no VM actually spun up):
- 'verify.sh --list': renders the 26-module matrix correctly.
- 'verify.sh nf_tables': dispatches to generic/ubuntu2204 + kernel
5.15.0-43 + expect=VULNERABLE; fails cleanly at 'vagrant: command
not found' (expected — user runs setup.sh first).
- 'verify.sh vmwgfx': errors with 'is marked manual: true' + note.
.gitignore: tools/verify-vm/{logs,.vagrant}/ excluded.
Usage:
./tools/verify-vm/setup.sh # one time, ~5 min
./tools/verify-vm/verify.sh nf_tables # ~5 min first run, ~1 min after
./tools/verify-vm/verify.sh --list # show all targets
|
||
|
|
e4a600fef2 |
module metadata: CWE + ATT&CK + CISA KEV triage from federal sources
Adds per-CVE triage annotations that turn SKELETONKEY's JSON output
into something a SIEM/CTI/threat-intel pipeline can route on, and a
KEV badge in --list so operators see at-a-glance which modules
cover actively-exploited bugs.
New tool — tools/refresh-cve-metadata.py:
- Discovers CVEs by scanning modules/<dir>/ (no hardcoded list).
- Fetches CISA's Known Exploited Vulnerabilities catalog
(https://www.cisa.gov/.../known_exploited_vulnerabilities.csv).
- Fetches CWE classifications from NVD's CVE API 2.0
(services.nvd.nist.gov), throttled to the anonymous
5-req/30s limit (~3 minutes for 26 CVEs).
- Hand-curated ATT&CK technique mapping (T1068 default; T1611 for
container escapes, T1082 for kernel info leaks — MITRE doesn't
publish a clean CVE→technique feed).
- Generates three outputs:
docs/CVE_METADATA.json machine-readable, drift-checkable
docs/KEV_CROSSREF.md human-readable table
core/cve_metadata.c auto-generated lookup table
- --check mode diffs the committed JSON against a fresh fetch for
CI drift detection.
New core API — core/cve_metadata.{h,c}:
struct cve_metadata { cve, cwe, attack_technique, attack_subtechnique,
in_kev, kev_date_added };
const struct cve_metadata *cve_metadata_lookup(const char *cve);
Lookup keyed by CVE id, not module name — the metadata is properties
of the CVE (two modules covering the same bug see the same metadata).
The opsec_notes field stays on the module struct because exploit
technique varies per-module (different footprints).
Output surfacing:
- --list: new KEV column shows ★ for KEV-listed CVEs.
- --module-info (text): prints cwe / att&ck / 'in CISA KEV: YES (added
YYYY-MM-DD)' between summary and operations.
- --module-info / --scan (JSON): emits a 'triage' subobject with the
full record, plus an 'opsec_notes' field at top level when set.
Initial snapshot:
- 10 of 26 modules cover KEV-listed CVEs (dirty_cow, dirty_pipe,
pwnkit, sudo_samedit, ptrace_traceme, fuse_legacy, nf_tables,
overlayfs, overlayfs_setuid, netfilter_xtcompat).
- 24 of 26 have NVD CWE mappings; 2 unmapped (NVD has no weakness
record for CVE-2019-13272 and CVE-2026-46300 yet).
- All 26 mapped to an ATT&CK technique.
Verification:
- macOS local: 33 kernel_range + clean build, --module-info shows
'in CISA KEV: YES (added 2024-05-30)' for nf_tables, --list KEV
column renders.
- Linux (docker gcc:latest): 33 + 54 = 87 passes, 0 fails.
Follow-up commits will add per-module OPSEC notes and --explain mode.
|
||
|
|
df4b879527 |
tools: refresh-kernel-ranges.py — Debian tracker drift detection
Standalone Python script that pulls Debian's security-tracker JSON
and compares each module's hardcoded kernel_patched_from table
against the fixed-versions Debian actually ships. Surfaces real
drift the no-fabrication rule needs us to fix:
MISSING — Debian has a fix on a kernel branch we have no entry
for. Module's detect() would say VULNERABLE on a host
that's actually patched.
TOO_TIGHT — Our threshold is later than Debian's earliest fix on
the same branch. Module would call a patched host
VULNERABLE. False-positive on production fleets.
INFO — Our threshold is earlier than Debian's. We're more
permissive; usually fine (we tracked a different
upstream-stable cut), but flagged for review.
Three output modes:
default (text) — human-readable report on stderr
--json — machine-readable for CI / dashboards
--patch — unified-diff-style proposed C-source edits
--refresh — bypass the 12h cache TTL and re-fetch
Implementation:
- urllib (no pip deps) fetches the ~70MB tracker JSON.
- Cached at /tmp/skeletonkey-debian-tracker.json with 12h TTL.
- Parses every modules/*/skeletonkey_modules.c for the .cve = '...'
field + the kernel_patched_from <name>[] = { {M,m,p}, ... } array.
- Per CVE, builds {debian_release -> upstream_version_tuple} from
the tracker's 'releases.*.fixed_version' field (stripping Debian
-N / +bN / ~bpoN suffixes to recover the upstream version).
- Groups by (major, minor) branch; flags MISSING / TOO_TIGHT / INFO.
- Exits non-zero when MISSING or TOO_TIGHT findings exist (suitable
for a CI 'detect-drift' job).
First-run output found drift in 17 of 20 modules with kernel_range
tables — operator-reviewable. NOT auto-applied; this commit only
ships the diagnostic tool, not the suggested fixes.
README's Contributing section now points at the tool.
|
||
|
|
9593d90385 |
rename: IAMROOT → SKELETONKEY across the entire project
Breaking change. Tool name, binary name, function/type names,
constant names, env vars, header guards, file paths, and GitHub
repo URL all rebrand IAMROOT → SKELETONKEY.
Changes:
- All "IAMROOT" → "SKELETONKEY" (constants, env vars, enum
values, docs, comments)
- All "iamroot" → "skeletonkey" (functions, types, paths, CLI)
- iamroot.c → skeletonkey.c
- modules/*/iamroot_modules.{c,h} → modules/*/skeletonkey_modules.{c,h}
- tools/iamroot-fleet-scan.sh → tools/skeletonkey-fleet-scan.sh
- Binary "iamroot" → "skeletonkey"
- GitHub URL KaraZajac/IAMROOT → KaraZajac/SKELETONKEY
- .gitignore now expects build output named "skeletonkey"
- /tmp/iamroot-* tmpfiles → /tmp/skeletonkey-*
- Env vars IAMROOT_MODPROBE_PATH etc. → SKELETONKEY_*
New ASCII skeleton-key banner (horizontal key icon + ANSI Shadow
SKELETONKEY block letters) replaces the IAMROOT banner in
skeletonkey.c and README.md.
VERSION: 0.3.1 → 0.4.0 (breaking).
Build clean on Debian 6.12.86. `skeletonkey --version` → 0.4.0.
All 24 modules still register; no functional code changes — pure
rename + banner refresh.
|
||
|
|
ea5d021f0c |
tools/iamroot-fleet-scan.sh + docs/DETECTION_PLAYBOOK.md
iamroot-fleet-scan.sh — bash wrapper that scp's the iamroot binary to a host list, ssh-runs --scan --json on each, aggregates results into a single JSON document. Supports: - hosts list from file or stdin - user@host:port syntax - parallel xargs execution (default -P 4) - ssh key / extra ssh opts pass-through - --no-sudo for hosts where root isn't required - --summary-only to suppress per-host detail - --no-cleanup to leave the binary on disk Critical fix during smoke-test: iamroot's exit codes are SEMANTIC (0=OK, 2=VULNERABLE, 4=PRECOND_FAIL, 5=EXPLOIT_OK). The wrapper must NOT treat nonzero exit as a transport failure; success is defined by 'stdout contains valid JSON', failure by 'stdout empty'. Verified end-to-end on kctf-mgr → kctf-fuzz: fleet-scan reports ok=1, failed=0, summary.vulnerable groups by CVE: copy_fail_gcm, dirty_frag_esp×2, entrybleed. Per-host detail included. docs/DETECTION_PLAYBOOK.md — operational integration guide: - Lifecycle diagram (inventory → scan → fleet scan → deploy/mitigate/upgrade → monitor) - Recipes by team size: single host, small fleet, large fleet - SIEM integration patterns: Splunk, Elastic, Sigma - Auditd-event lookup commands per module key - VULNERABLE decision tree (patch vs mitigate vs compensate) - Mitigation revert procedures + side-effect table - False-positive tuning table per rule key - Pre-patch quarantine pattern - Maintenance contract / module-shipping SLA |