e4a600fef29801cbed64789873ccde76191d4453
17 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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.
|
||
|
|
8938a74d04 |
detection rules: YARA + Falco for the 6 highest-rank modules + playbook
Closes the 'rules in the box' gap — the README has claimed YARA + Falco coverage but detect_yara and detect_falco were NULL on every module. This commit lights up both formats for the 6 highest-value modules (covering 10 of 31 registered modules via family-shared rules), and the existing operational playbook gains the format-specific deployment recipes + the cross-format correlation table. YARA rules (8 rules, 9 module-headers, 152 lines): - copy_fail_family — etc_passwd_uid_flip + etc_passwd_root_no_password (shared across copy_fail / copy_fail_gcm / dirty_frag_esp / dirty_frag_esp6 / dirty_frag_rxrpc) - dirty_pipe — passwd UID flip pattern, dirty-pipe-specific tag - dirtydecrypt — 28-byte ELF prefix match on tiny_elf[] + setuid+execve shellcode tail, detects the page-cache overlay landing - fragnesia — 28-byte ELF prefix on shell_elf[] + setuid+setgid+seteuid cascade, detects the 192-byte page-cache overlay - pwnkit — gconv-modules cache file format (small text file with module UTF-8// X// /tmp/...) - pack2theroot — malicious .deb (ar archive + SUID-bash postinst) + /tmp/.suid_bash artifact scan Falco rules (13 rules, 9 module-headers, 219 lines): - pwnkit — pkexec with empty argv + GCONV_PATH/CHARSET env from non-root - copy_fail_family — AF_ALG socket from non-root + NETLINK_XFRM from unprivileged userns + /etc/passwd modified by non-root - dirty_pipe — splice() of setuid/credential file by non-root - dirtydecrypt — AF_RXRPC socket + add_key(rxrpc) by non-root - fragnesia — TCP_ULP=espintcp from non-root + splice of setuid binary - pack2theroot — SUID bit set on /tmp/.suid_bash + dpkg invoked by packagekitd with /tmp/.pk-*.deb + 2x InstallFiles on same transaction Wiring: each module's .detect_yara and .detect_falco struct fields now point at the embedded string. The dispatcher dedups by pointer, so family-shared rules emit once across the 5 sub-modules. docs/DETECTION_PLAYBOOK.md augmented (302 -> 456 lines): - New 'YARA artifact scanning' subsection under SIEM integration with scheduled-scan cron pattern + per-rule trigger table - New 'Falco runtime detection' subsection with deploy + per-rule trigger table - New 'Per-module detection coverage' table — 4-format matrix - New 'Correlation across formats' section — multi-format incident signature per exploit (the 3-of-4 signal pattern) - New 'Worked example: catching DirtyDecrypt end-to-end' walkthrough from Falco page through yara confirmation, recovery, hunt + patch The existing operational lifecycle / SIEM patterns / FP tuning content is preserved unchanged — this commit only adds. Final stats: - auditd: 109 rule statements across 27 modules - sigma: 16 sigma rules across 19 modules - yara: 8 yara rules across 9 module headers (5 family + 4 distinct) - falco: 13 falco rules across 9 module headers The remaining 21 modules can gain YARA / Falco coverage incrementally by populating their detect_yara / detect_falco struct fields. |
||
|
|
97be306fd2 |
release: bump version to v0.6.0
This release captures the session's reliability + accuracy work
on top of v0.5.0:
- Shared host fingerprint (core/host.{h,c}): kernel/distro/userns
gates / sudo + polkit versions, populated once at startup; every
module consults ctx->host instead of doing its own probes.
- Test harness (tests/test_detect.c, make test): 44 unit tests over
mocked host fingerprints, wired into CI as a non-root step.
- --auto upgrades: auto-enables --active, per-detect 15s timeout,
fork-isolated detect + exploit so a crashing module can't tear
down the dispatcher, per-module verdict table + scan summary.
- --dry-run flag (preview without firing; --i-know not required).
- Pinned mainline fix commits for the 3 ported modules
(dirtydecrypt / fragnesia / pack2theroot) — detect() is now
version-pinned with kernel_range tables, not precondition-only.
- New modules: dirtydecrypt (CVE-2026-31635), fragnesia
(CVE-2026-46300), pack2theroot (CVE-2026-41651).
- macOS dev build works for the first time (all Linux-only code
wrapped in #ifdef __linux__).
- docs/JSON_SCHEMA.md: stable consumer contract for --scan --json.
Version bump:
- SKELETONKEY_VERSION = '0.6.0' in skeletonkey.c
- README status line updated with the v0.6.0 changelog
- docs/JSON_SCHEMA.md example refreshed
|
||
|
|
c63ee72aa1 |
docs: JSON output schema (consumer contract for --scan --json)
Adds docs/JSON_SCHEMA.md documenting the shape and stability promises
of the JSON document --scan --json emits on stdout. The schema is
already what the binary produces — this commit pins the contract so
fleet-scan / SIEM consumers can rely on it across releases.
What it covers:
- Top-level object: { version, modules } and field stability.
- Per-module entry: { name, cve, result } with type + stability.
- The 6-value result enum (OK / TEST_ERROR / VULNERABLE /
EXPLOIT_FAIL / PRECOND_FAIL / EXPLOIT_OK) and what each means
semantically.
- Process exit-code semantics for --scan (worst observed result
becomes the exit code — lets a SIEM treat the binary exit as a
single-host alert level).
- Bash + jq one-liners for the common fleet-roll-up patterns.
- A recommended Python consumer pattern with the forward-compat
guidance (ignore unknown fields, treat unknown result strings as
TEST_ERROR-equivalent).
- Explicit stability promises: which fields cannot change without
a major-version bump, what may be added in future minor
releases, what consumers MUST tolerate.
Verified against the live binary: --scan --json produces exactly
the documented shape (top-level keys {modules, version}; per-module
keys {cve, name, result}; result values come from the documented
enum). 31 modules / 30 unique CVEs at v0.5.0.
README's 'Sysadmins' audience row now links the schema doc:
'JSON output for CI gates ([schema](docs/JSON_SCHEMA.md))'.
|
||
|
|
4f30d00a1c |
core/host: shared host fingerprint refactor
Adds core/host.{h,c} — a single struct skeletonkey_host populated once
at startup and handed to every module callback via ctx->host. Replaces
the per-detect uname / /etc/os-release / sysctl / userns-fork-probe
calls scattered across the corpus with O(1) cached lookups, and gives
the dispatcher one consistent view of the host.
What's in the fingerprint:
- Identity: kernel_version (parsed from uname.release), arch (machine),
nodename, distro_id / distro_version_id / distro_pretty (parsed once
from /etc/os-release).
- Process state: euid, real_uid (defeats userns illusion via
/proc/self/uid_map), egid, username, is_root, is_ssh_session.
- Platform family: is_linux, is_debian_family, is_rpm_family,
is_arch_family, is_suse_family (file-existence checks once).
- Capability gates (Linux): unprivileged_userns_allowed (live
fork+unshare probe), apparmor_restrict_userns,
unprivileged_bpf_disabled, kpti_enabled, kernel_lockdown_active,
selinux_enforcing, yama_ptrace_restricted.
- System services: has_systemd, has_dbus_system.
Wiring:
- core/module.h forward-declares struct skeletonkey_host and adds the
pointer to skeletonkey_ctx. Modules opt-in by including
../../core/host.h.
- core/host.c is fully POD (no heap pointers) — uses a single file-
static instance, returns a stable pointer on every call. Lazily
populated on first skeletonkey_host_get().
- skeletonkey.c calls skeletonkey_host_get() at main() entry, stores
in ctx.host before any register_*() runs.
- cmd_auto's bespoke distro-fingerprint code (was an inline
read_os_release helper) is replaced with skeletonkey_host_print_banner(),
which emits a two-line banner of identity + capability gates.
Migrations:
- dirtydecrypt: kernel_version_current() -> ctx->host->kernel.
- fragnesia: removed local fg_userns_allowed() fork-probe in favour of
ctx->host->unprivileged_userns_allowed (no per-scan fork). Also
pulls kernel from ctx->host. The PRECOND_FAIL message now notes
whether AppArmor restriction is on.
- pack2theroot: access('/etc/debian_version') -> ctx->host->is_debian_family;
also short-circuits when ctx->host->has_dbus_system is false (saves
the GLib g_bus_get_sync attempt on systems without system D-Bus).
- overlayfs: replaced the inline is_ubuntu() /etc/os-release parser
with ctx->host->distro_id comparison. Local helper preserved for
symmetry / standalone builds.
Documentation: docs/ARCHITECTURE.md gains a 'Host fingerprint'
section describing the struct, the opt-in include pattern, and
example detect() usage. ROADMAP --auto accuracy log notes the
landing and flags remaining modules as an incremental follow-up.
Build verification:
- macOS (local): make clean && make -> Mach-O x86_64, 31 modules,
banner prints with distro=?/? (no /etc/os-release).
- Linux (docker gcc:latest + libglib2.0-dev): make clean && make ->
ELF 64-bit, 31 modules. Banner prints with kernel + distro=debian/13
+ 7 capability gates. dirtydecrypt correctly says 'predates the
rxgk code added in 7.0'; fragnesia PRECOND_FAILs with
'(host fingerprint)' annotation; pack2theroot PRECOND_FAILs on
no-DBus; overlayfs reports 'not Ubuntu (distro=debian)'.
|
||
|
|
9a4cc91619 |
pack2theroot (CVE-2026-41651) + --auto accuracy work
Adds the third ported module — Pack2TheRoot, a userspace PackageKit
D-Bus TOCTOU LPE — and spends real effort hardening --auto so its
detect step gives an accurate, robust verdict before deploying.
pack2theroot (CVE-2026-41651):
- Ported from the public Vozec PoC
(github.com/Vozec/CVE-2026-41651). Original disclosure by the
Deutsche Telekom security team.
- Two back-to-back InstallFiles D-Bus calls (SIMULATE then NONE)
overwrite the cached transaction flags between polkit auth and
dispatch. GLib priority ordering makes the overwrite deterministic,
not a timing race; postinst of the malicious .deb drops a SUID bash
in /tmp.
- detect() reads PackageKit's VersionMajor/Minor/Micro directly over
D-Bus and compares against the pinned fix release 1.3.5 (commit
76cfb675). This is a high-confidence verdict, not precondition-only.
- Debian-family only (PoC builds its own .deb in pure C; ar/ustar/
gzip-stored inline). Cleanup removes /tmp .debs + best-effort
unlinks /tmp/.suid_bash + sudo -n dpkg -r the staging packages.
- Adds an optional GLib/GIO build dependency. The top-level Makefile
autodetects via `pkg-config gio-2.0`; when absent the module
compiles as a stub returning PRECOND_FAIL.
- Embedded auditd + sigma rules cover the file-side footprint
(/tmp/.suid_bash, /tmp/.pk-*.deb, non-root dpkg/apt execve).
--auto accuracy improvements:
- Auto-enables --active before the scan. Per-module sentinel probes
(page-cache /tmp files, fork-isolated namespace mounts) turn
version-only checks into definitive verdicts, so silent distro
backports don't fool the scan and --auto won't pick blind on
TEST_ERROR.
- Per-module verdict printing — every module's result is shown
(VULNERABLE / patched / precondition / indeterminate), not just
VULNERABLE rows. Operator sees the full picture.
- Scan-end summary line: "N vulnerable, M patched/n.a., K
precondition-fail, L indeterminate" with a separate callout when
modules crashed.
- Distro fingerprint added to the auto banner (ID + VERSION_ID from
/etc/os-release alongside kernel/arch).
- Fork-isolated detect() — each detector runs in a child process so
a SIGILL/SIGSEGV in one module's probe is contained and the scan
continues. Surfaced live while testing: entrybleed's prefetchnta
KASLR sweep SIGILLs on emulated CPUs (linuxkit on darwin); without
isolation the whole --auto died at module 7 of 31. With isolation
the scan reports "detect() crashed (signal 4) — continuing" and
finishes cleanly.
module_safety_rank additions:
- pack2theroot: 95 (userspace D-Bus TOCTOU; dpkg + /tmp SUID footprint
— clean but heavier than pwnkit's gconv-modules-only path).
- dirtydecrypt / fragnesia: 86 (page-cache writes; one step below the
verified copy_fail/dirty_frag family at 88 to prefer verified
modules when both apply).
Docs:
- README badge / tagline / tier table / ⚪ block / example output /
v0.5.0 status — all updated to "28 verified + 3 ported".
- CVES.md counts line, the ported-modules note (now calling out
pack2theroot's high-confidence detect vs. precondition-only for
the page-cache pair), inventory row, operations table row.
- ROADMAP Phase 7+: pack2theroot moved out of carry-overs into the
"landed (ported, pending VM verification)" group; added a new
"--auto accuracy work" subsection documenting the dispatcher
hardening landed in this commit.
- docs/index.html: scanning-count example bumped to 31, status line
updated to mention 3 ported modules.
Build verification: full `make clean && make` in `docker gcc:latest`
with libglib2.0-dev installed: links into a 31-module skeletonkey
ELF (413KB), `--list` shows all modules including pack2theroot,
`--detect-rules --format=auditd` emits the new pack2theroot section,
`--auto --i-know --no-shell` exercises the new banner + active
probes + verdict table + fork isolation + scan summary end-to-end.
Only build warning is the pre-existing
`-Wunterminated-string-initialization` in dirty_pipe (not introduced
here).
|
||
|
|
ac557b67d0 |
review pass: fidelity + credits + count consistency for ported modules
Three-agent rigorous review of the dirtydecrypt + fragnesia ports plus
repo-wide doc consistency, followed by a full Linux build verification.
dirtydecrypt (NOTICE + detection rules):
- NOTICE.md: removed an unsupported "Zellic co-founder" detail and a
fabricated disclosure-date narrative; tightened phrasing of the
Zellic + V12 credit; noted that upstream poc.c carries no
author/license header of its own.
- Embedded auditd + sigma rules and detect/sigma.yml broadened to
cover every binary in dd_targets[] (added /usr/bin/mount,
/usr/bin/passwd, /usr/bin/chsh) and added the b32 splice rule, so
the embedded ruleset matches the on-disk reference and the carrier
list the exploit actually targets.
- Exploit primitive verified byte-for-byte against the V12 PoC
(tiny_elf[] identical, all rxgk/XDR/fire/pagecache_write logic
token-identical). docker gcc:latest compile of the Linux path:
COMPILE_OK, zero warnings.
fragnesia: review found no defects. Exploit primitive byte-identical
to the V12 PoC (shell_elf[] 192 bytes identical, AF_ALG GCM keystream
table + userns/netns/XFRM + receiver/sender/run_trigger_pair all
faithful). The deliberate omissions (ANSI TUI, CLI arg parsing) drop
nothing exploit-critical. docker gcc:latest compile: COMPILE_OK; full
project build links into a working skeletonkey ELF and --list shows
the module registered correctly.
Repo docs (README.md / CVES.md / ROADMAP.md):
- Chose to keep "28 verified" as the headline; the two ported
modules are represented as a separate clearly-labelled tier
("ported-but-unverified") that is explicitly excluded from the
28-module verified counts. README + CVES.md + ROADMAP.md now tell
one consistent story.
- Filled a pre-existing documentation gap: sudo_samedit, sequoia,
sudoedit_editor, vmwgfx were registered + built but absent from
CVES.md's inventory + operations tables. Added rows synthesized
from each module's .cve / .summary / .kernel_range fields.
- ROADMAP Phase 8 "7 🟡 PRIMITIVE modules" → "14"; added a "Landed
since v0.1.0" group; moved vmwgfx out of the stale carry-overs.
docs site (docs/index.html):
- Stat box "28 / total modules" → "28 / verified modules" (the 14+14
breakdown now sums to the headline consistently).
- Terminal example "scanning 28 modules" → "scanning 30 modules"
(was factually wrong — the binary literally prints module_count()
which is 30).
- Status line: updated to mention the 2 ported-but-unverified
modules and mirror the README phrasing.
- docs/LAUNCH.md left as a dated v0.5.0 launch snapshot.
Build verification: `docker run gcc:latest make clean && make` —
links into a 30-module skeletonkey ELF on Linux. macOS dev box still
hits the pre-existing dirty_pipe header gap; unchanged.
.gitignore: added /skeletonkey to exclude the top-level build
artifact (the existing modules/*/skeletonkey only covered per-module
binaries; the root one was getting picked up by `git add -A`).
|
||
|
|
33f81aeb69 |
site: revert CVE table → pill grid
The sortable table was denser but lost the visual scan-ability of the color-coded pill grid. Restoring the pill view: two grouped sections (🟢 / 🟡) each showing every module name as a pill. Drops the table-sort JS (~25 lines) and the .cve-table CSS block. |
||
|
|
58fb2e0951 |
site: simplify nav + add sortable CVE chart
nav: removed Releases / CVEs / Defenders links — kept only a
right-aligned GitHub link with the Octocat SVG icon.
index.html: replaced pill-grid corpus view with a proper sortable
table — Year, CVE, Bug, Module, Tier columns. Click headers to
sort. Defaults to Year descending. 28 rows covering 2016 → 2026.
style.css: added .nav-github (border-pill style) + table styles
(sortable headers with arrow indicators, hover rows, mobile-
responsive font-size + overflow-x scroll).
JS for sort is ~25 lines vanilla — no library.
|
||
|
|
2904fa159c |
site: GitHub Pages landing page
Single-page static site under /docs/, served by GitHub Pages from
the main branch /docs source.
docs/index.html: hero with one-liner + copy button, why-this-exists,
corpus stats + module pills (14 🟢 + 14 🟡), audience cards
(red/blue/sysadmin/CTF), terminal-shape worked example,
verified-vs-claimed bar, quickstart commands, status, footer.
docs/style.css: dark theme matching GitHub's color palette
(#0d1117 bg, #c9d1d9 text). System sans for prose, ui-monospace
for code. Mobile-responsive with grid breakpoints. No JS framework,
no external fonts, no analytics.
docs/.nojekyll: disable Jekyll so the static HTML is served
verbatim and the existing /docs/*.md files stay as raw markdown
(viewable via GitHub UI, not the Pages site).
|
||
|
|
95135213e5 |
launch: README polish + CONTRIBUTING + LAUNCH.md
README.md: badges (release / license / module-count / platform),
sharpened hero stating value prop in one sentence, audience
framing for red team / sysadmin / blue team.
CONTRIBUTING.md (new): what we accept (offsets, modules, detection
rules, bug reports) and what we don't (untested EXPLOIT_OK,
fabricated offsets, 0days, undisclosed CVEs).
docs/LAUNCH.md (new): ~600-word HN/blog launch post. Copy-paste
ready. Explains the verified-vs-claimed bar + --auto + the
operator-populated offset table approach.
GitHub repo description + 11 topics set via gh repo edit so the
repo is discoverable in topic searches (linux-security,
privilege-escalation, cve, redteam, blueteam, etc.).
|
||
|
|
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.
|
||
|
|
9d88b475c1 |
v0.3.1: --dump-offsets tool + NOTICE.md per module
The README has been claiming "each module credits the original CVE
reporter and PoC author in its NOTICE.md" since v0.1.0, but only
copy_fail_family actually shipped one. Fixed.
modules/<name>/NOTICE.md (×19 new + 1 existing): per-module
research credit covering CVE ID, discoverer, original advisory
URL where public, upstream fix commit, IAMROOT's role.
iamroot.c: new --dump-offsets subcommand. Resolves kernel offsets
via the existing core/offsets.c four-source chain (env →
/proc/kallsyms → /boot/System.map → embedded table), then emits
a ready-to-paste C struct entry for kernel_table[]. Run once
as root on a target kernel build; upstream via PR. Eliminates
fabricating offsets — every shipped entry traces back to a
`iamroot --dump-offsets` invocation on a real kernel.
docs/OFFSETS.md: documents the --dump-offsets workflow.
CVES.md: notes the NOTICE.md convention + offset dump tool.
iamroot.c: bump IAMROOT_VERSION 0.3.0 → 0.3.1.
|
||
|
|
e2a3d6e94f |
release: v0.2.0 — --full-chain root-pop opt-in across 7 🟡 modules
iamroot.c: bump IAMROOT_VERSION 0.1.0 → 0.2.0 CVES.md: redefine 🟡 to note --full-chain capability + docs/OFFSETS.md README.md: update Status section for v0.2.0 docs/OFFSETS.md: new doc — env-var/kallsyms/System.map/embedded-table resolution chain + operator workflow for populating offsets per kernel build + sentinel-based success arbitration. All 7 🟡 modules now expose `--full-chain`. Default behavior unchanged. |
||
|
|
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 |
||
|
|
f1bd896ca8 |
Phase 7: Pwnkit FULL exploit (Qualys-style PoC) + DEFENDERS.md
Pwnkit: 🔵 → 🟢 - Implements the canonical Qualys-style PoC end-to-end: 1. Locate setuid pkexec 2. mkdtemp working directory under /tmp 3. Detect target's gcc/cc (fail-soft if absent) 4. Write payload.c (gconv constructor: unsetenv hostile vars, setuid(0), execle /bin/sh -p with clean PATH) 5. gcc -shared -fPIC payload.c -o pwnkit/PWNKIT.so 6. Write gconv-modules cache pointing UTF-8// → PWNKIT// 7. execve(pkexec, NULL_argv, envp{GCONV_PATH=workdir/pwnkit, PATH=GCONV_PATH=., CHARSET=PWNKIT, SHELL=pwnkit}) → argc=0 triggers argv-overflow-into-envp; pkexec re-execs with PATH set to our tmpdir; libc's iconv loads PWNKIT.so as root; constructor pops /bin/sh with uid=0. - Cleanup: removes /tmp/iamroot-pwnkit-* workdirs. - Auto-refuses on patched hosts (re-runs detect() first). - GCC -Wformat-truncation warnings fixed by sizing path buffers generously (1024/2048 bytes — way more than needed in practice). Verified end-to-end on kctf-mgr (polkit 126 = patched): iamroot --exploit pwnkit --i-know → detect() says fixed → refuses cleanly. Correct behavior. Vulnerable-kernel validation is Phase 4 CI matrix work. docs/DEFENDERS.md — blue-team deployment guide: - TL;DR: scan, deploy rules, mitigate, watch - Operations cheat sheet (--list, --scan, --detect-rules, --mitigate) - Audit-key table mapping rule keys to modules to caught behavior - Fleet-scanning recipe (ssh + jq aggregation) - Known false-positive shapes per rule with tuning hints CVES.md: pwnkit row updated 🔵 → 🟢. ROADMAP.md: Phase 7 Pwnkit checkbox marked complete. |
||
|
|
cf30b249de | Initial skeleton: README, CVE inventory, roadmap, ARCH, ethics + copy_fail_family module absorbed from DIRTYFAIL |