diff --git a/CVES.md b/CVES.md index 079c655..bdca178 100644 --- a/CVES.md +++ b/CVES.md @@ -75,7 +75,7 @@ root on a host can upstream their kernel's offsets via PR. | CVE-2022-2588 | net/sched cls_route4 handle-zero dead UAF | LPE (kernel UAF in cls_route4 filter remove) | mainline 5.20 / 5.19.7 (Aug 2022) | `cls_route4` | 🟑 | Userns+netns reach, tc/ip dummy interface + route4 dangling-filter add/del, msg_msg kmalloc-1k spray, UDP classify drive to follow the dangling pointer, slabinfo delta witness. Stops at empirical UAF-fired signal; no leakβ†’cred overwrite (per-kernel offsets refused). Branch backports: 5.4.213 / 5.10.143 / 5.15.69 / 5.18.18 / 5.19.7. | | CVE-2016-5195 | Dirty COW β€” COW race via /proc/self/mem + madvise | LPE (page-cache write into root-owned files) | mainline 4.9 (Oct 2016) | `dirty_cow` | 🟒 | Full detect + exploit + cleanup. **Old-systems coverage** β€” affects RHEL 6/7 (3.10 baseline), Ubuntu 14.04 (3.13), Ubuntu 16.04 (4.4), embedded boxes, IoT. Phil-Oester-style two-thread race: writer thread via `/proc/self/mem` vs madvise(MADV_DONTNEED) thread. Targets /etc/passwd UID flip + `su`. Ships auditd watch on /proc/self/mem + sigma rule for non-root mem-open. Pthread-linked. | | CVE-2019-13272 | PTRACE_TRACEME β†’ setuid execve β†’ cred escalation | LPE (kernel ptrace race; no exotic preconditions) | mainline 5.1.17 (Jun 2019) | `ptrace_traceme` | 🟒 | Full detect + exploit. Branch backports: 4.4.182 / 4.9.182 / 4.14.131 / 4.19.58 / 5.0.20 / 5.1.17. jannh-style: fork β†’ child `PTRACE_TRACEME` β†’ child sleep+attach β†’ parent `execve` setuid bin (pkexec/su/passwd auto-selected) β†’ child wins stale-ptrace_link β†’ POKETEXT x86_64 shellcode β†’ root sh. x86_64-only; ARM/other return PRECOND_FAIL cleanly. | -| CVE-2022-0492 | cgroup v1 `release_agent` privilege check in wrong namespace | LPE (host root from rootless container or unprivileged userns) | mainline 5.17 (Mar 2022) | `cgroup_release_agent` | 🟒 | Universal structural exploit β€” no per-kernel offsets, no race. unshare(user|mount|cgroup), mount cgroup v1 RDP controller, write release_agent β†’ ./payload, trigger via notify_on_release. Ships auditd rules covering cgroupfs mount + release_agent writes. Kept as a portable "containers misconfigured" demo. | +| CVE-2022-0492 | cgroup v1 `release_agent` privilege check in wrong namespace | LPE (host root from rootless container or unprivileged userns) | mainline 5.17 (Mar 2022) | `cgroup_release_agent` | 🟒 | Universal structural exploit β€” no per-kernel offsets, no race. unshare(user|mount|cgroup), mount cgroup v1 RDP controller, write release_agent β†’ ./payload, trigger via notify_on_release. Ships auditd rules covering cgroupfs mount + release_agent writes. Kept as a portable "containers misconfigured" demo. **Added to CISA KEV 2026-06-02 β€” now confirmed exploited in the wild.** | | CVE-2023-0386 | overlayfs `copy_up` preserves setuid bit across mount-ns boundary | LPE (host root via setuid carrier from unprivileged mount) | mainline 5.11 / 6.2-rc6 (Jan 2023) | `overlayfs_setuid` | 🟒 | Distro-agnostic β€” places a setuid binary in an overlay lower, mounts via fuse-overlayfs userns trick, executes from upper to inherit the setuid bit + root euid. Branch backports tracked for 5.10.169 / 5.15.92 / 6.1.11 / 6.2.x. | | CVE-2021-22555 | iptables xt_compat heap-OOB β†’ cross-cache UAF | LPE (kernel R/W via 4-byte heap OOB write + msg_msg/sk_buff groom) | mainline 5.12 / 5.11.10 (Apr 2021) | `netfilter_xtcompat` | 🟑 | Hand-rolled `ipt_replace` blob + setsockopt(IPT_SO_SET_REPLACE) fires the 4-byte OOB, msg_msg spray in kmalloc-2k + sk_buff sidecar, MSG_COPY scan for cross-cache landing + slabinfo delta. Stops before the leak β†’ modprobe_path overwrite chain (per-kernel offsets refused). Branch backports: 5.11.10 / 5.10.27 / 5.4.110 / 4.19.185 / 4.14.230 / 4.9.266 / 4.4.266. **Bug existed since 2.6.19 (2006).** Andy Nguyen's PGZ disclosure. | | CVE-2017-7308 | AF_PACKET TPACKET_V3 integer overflow β†’ heap write-where | LPE (CAP_NET_RAW via userns) | mainline 4.11 / 4.10.6 (Mar 2017) | `af_packet` | 🟑 | Konovalov's TPACKET_V3 overflow + 200-skb spray + best-effort cred race. Offset table (Ubuntu 16.04/4.4 + 18.04/4.15) + `SKELETONKEY_AFPACKET_OFFSETS` env override for other kernels. x86_64-only; ARM returns PRECOND_FAIL. Branch backports: 4.10.6 / 4.9.18 / 4.4.57 / 3.18.49. | diff --git a/README.md b/README.md index cd4ff65..d60091e 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ ```bash curl -sSL https://github.com/KaraZajac/SKELETONKEY/releases/latest/download/install.sh | sh \ + && export PATH="$HOME/.local/bin:$PATH" \ && skeletonkey --auto --i-know ``` @@ -205,7 +206,7 @@ also compile (modules with Linux-only headers stub out gracefully). ## Status -**v0.9.8 cut 2026-06-02.** 41 modules across 36 CVEs β€” **every +**v0.9.9 cut 2026-06-08.** 41 modules across 36 CVEs β€” **every year 2016 β†’ 2026 now covered**. Newest: `ptrace_pidfd` (CVE-2026-46333, Qualys's `__ptrace_may_access` / `pidfd_getfd` credential-steal) and `sudo_host` (CVE-2025-32462, Stratascale's sudo `--host` policy bypass). @@ -238,7 +239,7 @@ Reliability + accuracy work in v0.7.x: 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; 12 of 34 modules cover KEV-listed CVEs. + CISA KEV catalog + NVD CWE; 13 of 36 modules cover KEV-listed CVEs. - **151 detection rules** across auditd / sigma / yara / falco; one command exports the corpus to your SIEM. - `--auto` upgrades: per-detect 15s timeout, fork-isolated detect + diff --git a/core/cve_metadata.c b/core/cve_metadata.c index 61550ae..ab5fc80 100644 --- a/core/cve_metadata.c +++ b/core/cve_metadata.c @@ -121,8 +121,8 @@ const struct cve_metadata cve_metadata_table[] = { .cwe = "CWE-287", .attack_technique = "T1611", .attack_subtechnique = NULL, - .in_kev = false, - .kev_date_added = "", + .in_kev = true, + .kev_date_added = "2026-06-02", }, { .cve = "CVE-2022-0847", @@ -286,7 +286,7 @@ const struct cve_metadata cve_metadata_table[] = { }, { .cve = "CVE-2026-46333", - .cwe = NULL, + .cwe = "CWE-269", .attack_technique = "T1068", .attack_subtechnique = NULL, .in_kev = false, diff --git a/docs/CVE_METADATA.json b/docs/CVE_METADATA.json index 3f36b6a..82583ed 100644 --- a/docs/CVE_METADATA.json +++ b/docs/CVE_METADATA.json @@ -122,8 +122,8 @@ "cwe": "CWE-287", "attack_technique": "T1611", "attack_subtechnique": null, - "in_kev": false, - "kev_date_added": "" + "in_kev": true, + "kev_date_added": "2026-06-02" }, { "cve": "CVE-2022-0847", @@ -308,7 +308,7 @@ { "cve": "CVE-2026-46333", "module_dir": "ptrace_pidfd_cve_2026_46333", - "cwe": null, + "cwe": "CWE-269", "attack_technique": "T1068", "attack_subtechnique": null, "in_kev": false, diff --git a/docs/KEV_CROSSREF.md b/docs/KEV_CROSSREF.md index 777f3d0..4dc688c 100644 --- a/docs/KEV_CROSSREF.md +++ b/docs/KEV_CROSSREF.md @@ -4,7 +4,7 @@ Which SKELETONKEY modules cover CVEs that CISA has observed exploited in the wild per the Known Exploited Vulnerabilities catalog. Refreshed via `tools/refresh-cve-metadata.py`. -**12 of 34 modules cover KEV-listed CVEs.** +**13 of 36 modules cover KEV-listed CVEs.** ## In KEV (prioritize patching) @@ -22,6 +22,7 @@ Refreshed via `tools/refresh-cve-metadata.py`. | CVE-2025-32463 | 2025-09-29 | CWE-829 | `sudo_chwoot_cve_2025_32463` | | CVE-2021-22555 | 2025-10-06 | CWE-787 | `netfilter_xtcompat_cve_2021_22555` | | CVE-2018-14634 | 2026-01-26 | CWE-190 | `mutagen_astronomy_cve_2018_14634` | +| CVE-2022-0492 | 2026-06-02 | CWE-287 | `cgroup_release_agent_cve_2022_0492` | ## Not in KEV @@ -36,7 +37,6 @@ and are technically reachable. "Not in KEV" is not the same as | CVE-2020-14386 | CWE-250 | `af_packet2_cve_2020_14386` | | CVE-2020-29661 | CWE-416 | `tioscpgrp_cve_2020_29661` | | CVE-2021-33909 | CWE-190 | `sequoia_cve_2021_33909` | -| CVE-2022-0492 | CWE-287 | `cgroup_release_agent_cve_2022_0492` | | CVE-2022-25636 | CWE-269 | `nft_fwd_dup_cve_2022_25636` | | CVE-2022-2588 | CWE-416 | `cls_route4_cve_2022_2588` | | CVE-2023-0179 | CWE-190 | `nft_payload_cve_2023_0179` | @@ -48,8 +48,10 @@ and are technically reachable. "Not in KEV" is not the same as | CVE-2023-4622 | CWE-416 | `af_unix_gc_cve_2023_4622` | | CVE-2024-26581 | ? | `nft_pipapo_cve_2024_26581` | | CVE-2024-50264 | CWE-416 | `vsock_uaf_cve_2024_50264` | +| CVE-2025-32462 | CWE-863 | `sudo_host_cve_2025_32462` | | CVE-2025-6019 | CWE-250 | `udisks_libblockdev_cve_2025_6019` | | CVE-2026-31635 | CWE-130 | `dirtydecrypt_cve_2026_31635` | | CVE-2026-41651 | CWE-367 | `pack2theroot_cve_2026_41651` | | CVE-2026-43494 | ? | `pintheft_cve_2026_43494` | | CVE-2026-46300 | CWE-787 | `fragnesia_cve_2026_46300` | +| CVE-2026-46333 | CWE-269 | `ptrace_pidfd_cve_2026_46333` | diff --git a/docs/LAUNCH.md b/docs/LAUNCH.md index a7818e7..783c466 100644 --- a/docs/LAUNCH.md +++ b/docs/LAUNCH.md @@ -26,6 +26,7 @@ haven't been maintained in years. ```bash curl -sSL https://github.com/KaraZajac/SKELETONKEY/releases/latest/download/install.sh | sh \ + && export PATH="$HOME/.local/bin:$PATH" \ && skeletonkey --auto --i-know ``` diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index d7d0053..81a0dfa 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -1,3 +1,37 @@ +## SKELETONKEY v0.9.9 β€” install.sh needs no root; CVE-2022-0492 KEV drift + +Two maintenance fixes, no new modules. + +**`install.sh` never escalates to sudo.** SKELETONKEY is a privilege- +escalation tool β€” the operator by definition does *not* have root yet, so +the installer must not demand it. The old default wrote to `/usr/local/bin` +and fell back to `sudo mv` when that wasn't writable, prompting for a +password on exactly the unprivileged accounts this tool targets. It now +installs sudo-free: `/usr/local/bin` is used only when already writable, +otherwise it falls back to a per-user `$HOME/.local/bin` (honoring +`XDG_BIN_HOME`), created as needed. An explicit `SKELETONKEY_PREFIX` is +honored exactly and errors rather than escalating if unwritable. When the +chosen dir isn't on `$PATH` the installer prints the absolute path, and the +documented `curl … | sh && skeletonkey --auto --i-know` one-liner now +prepends `$HOME/.local/bin` to `$PATH` so it resolves on a fresh login. The +quickstart no longer prefixes `sudo` to `--scan`/`--audit`/`--auto` β€” +detection and escalation run as the unprivileged user; only writing audit +rules into `/etc/audit` legitimately needs root. + +**Federal metadata drift (the failing scheduled build).** The weekly +`drift-check` caught two upstream changes since v0.9.8: + +- **CVE-2022-0492 entered CISA KEV (2026-06-02).** The cgroup v1 + `release_agent` container-escape (`cgroup_release_agent`) is now on the + Known Exploited Vulnerabilities catalog. The corpus reports **13 of 36** + modules covering KEV-listed CVEs (was 12). +- **CVE-2026-46333 gained a CWE.** When `ptrace_pidfd` was added two weeks + after disclosure, NVD had not yet classified it; it is now **CWE-269** + (Improper Privilege Management). + +Refreshed `CVE_METADATA.json`, the generated `cve_metadata.c` table, and +`KEV_CROSSREF.md` accordingly (README + website counts updated). + ## SKELETONKEY v0.9.8 β€” two new LPE modules (ptrace_pidfd, sudo_host) Adds the two most compelling recent Linux LPEs not already in the corpus, diff --git a/docs/app.js b/docs/app.js index b13e161..c64e784 100644 --- a/docs/app.js +++ b/docs/app.js @@ -10,7 +10,7 @@ * 1. typed install command in the hero * ============================================================ */ const installCmd = - 'curl -sSL https://github.com/KaraZajac/SKELETONKEY/releases/latest/download/install.sh | sh \\\n && skeletonkey --auto --i-know'; + 'curl -sSL https://github.com/KaraZajac/SKELETONKEY/releases/latest/download/install.sh | sh \\\n && export PATH="$HOME/.local/bin:$PATH" \\\n && skeletonkey --auto --i-know'; const typedEl = document.getElementById('install-typed'); const cursorEl = document.getElementById('install-cursor'); diff --git a/docs/index.html b/docs/index.html index cfbb936..e4b973d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -4,7 +4,7 @@ SKELETONKEY β€” Linux LPE corpus, VM-verified, SOC-ready detection - + @@ -56,7 +56,7 @@
- v0.9.8 β€” released 2026-06-02 + v0.9.9 β€” released 2026-06-08

SKELETONKEY @@ -227,7 +227,7 @@ uid=0(root) gid=0(root)
β˜…

CISA KEV prioritized

- 12 of 36 CVEs in the corpus are in CISA's Known Exploited + 13 of 36 CVEs in the corpus are in CISA's Known Exploited Vulnerabilities catalog β€” actively exploited in the wild. Refreshed on demand via tools/refresh-cve-metadata.py.

@@ -600,7 +600,7 @@ uid=0(root) gid=0(root) who found the bugs.

diff --git a/install.sh b/install.sh index a1c725d..a503981 100755 --- a/install.sh +++ b/install.sh @@ -28,7 +28,11 @@ set -eu REPO="${SKELETONKEY_REPO:-KaraZajac/SKELETONKEY}" VERSION="${SKELETONKEY_VERSION:-latest}" -PREFIX="${SKELETONKEY_PREFIX:-/usr/local/bin}" +# PREFIX resolution is deferred until install time so we can pick a +# sudo-free default. SKELETONKEY is a privilege-escalation tool β€” by +# definition the operator does NOT have root yet, so the installer must +# NEVER need sudo. Empty here means "auto-pick a writable dir below". +PREFIX="${SKELETONKEY_PREFIX:-}" log() { printf '[\033[1;36m*\033[0m] %s\n' "$*" >&2; } ok() { printf '[\033[1;32m+\033[0m] %s\n' "$*" >&2; } @@ -108,29 +112,49 @@ fi chmod +x "$tmp/skeletonkey" -# Install. Try $PREFIX directly; if not writable, sudo. -target_path="$PREFIX/skeletonkey" -if [ -w "$PREFIX" ] || [ "$(id -u)" -eq 0 ]; then - mv "$tmp/skeletonkey" "$target_path" -elif command -v sudo >/dev/null 2>&1; then - log "$PREFIX needs sudo; you may be prompted for password" - sudo mv "$tmp/skeletonkey" "$target_path" +# Choose install dir β€” NEVER escalate to sudo. If the user pinned +# SKELETONKEY_PREFIX we honor it exactly (creating it if needed) and +# error rather than escalate when it isn't writable. Otherwise prefer +# /usr/local/bin only when it happens to already be writable, and fall +# back to a guaranteed per-user dir ($HOME/.local/bin) that needs no +# privileges. This keeps `curl ... | sh` password-free for the exact +# users this tool is meant for: unprivileged accounts. +if [ -n "$PREFIX" ]; then + [ -d "$PREFIX" ] || mkdir -p "$PREFIX" 2>/dev/null \ + || fail "cannot create SKELETONKEY_PREFIX=$PREFIX" + [ -w "$PREFIX" ] || fail "SKELETONKEY_PREFIX=$PREFIX not writable (the installer never uses sudo β€” pick a writable dir)" +elif [ -w /usr/local/bin ]; then + PREFIX=/usr/local/bin else - fail "$PREFIX not writable and sudo not available. Try SKELETONKEY_PREFIX=\$HOME/.local/bin" + PREFIX="${XDG_BIN_HOME:-$HOME/.local/bin}" + mkdir -p "$PREFIX" 2>/dev/null || fail "cannot create $PREFIX" fi +target_path="$PREFIX/skeletonkey" +mv "$tmp/skeletonkey" "$target_path" || fail "failed to install to $target_path" ok "installed: $target_path" + +# ~/.local/bin is frequently absent from PATH on fresh accounts β€” tell +# the user how to invoke it rather than letting `skeletonkey` 404. +case ":$PATH:" in + *":$PREFIX:"*) : ;; + *) log "note: $PREFIX is not on \$PATH β€” run it as $target_path, or add the dir to PATH" ;; +esac + "$target_path" --version cat >&2 < #include -#define SKELETONKEY_VERSION "0.9.8" +#define SKELETONKEY_VERSION "0.9.9" static const char BANNER[] = "\n" diff --git a/tools/__pycache__/refresh-cve-metadata.cpython-314.pyc b/tools/__pycache__/refresh-cve-metadata.cpython-314.pyc new file mode 100644 index 0000000..e725055 Binary files /dev/null and b/tools/__pycache__/refresh-cve-metadata.cpython-314.pyc differ