Files
KaraZajac e457b22c1f release v0.9.9: install.sh needs no sudo + CVE metadata drift fix
install.sh never escalates to sudo. The installer defaulted to
/usr/local/bin and fell back to `sudo mv`, prompting for a password on
exactly the unprivileged accounts a privilege-escalation tool targets. It
now uses /usr/local/bin only when already writable and otherwise installs
to a per-user $HOME/.local/bin (honoring XDG_BIN_HOME), no sudo ever. An
explicit SKELETONKEY_PREFIX is honored and errors rather than escalating.
The documented one-liner prepends ~/.local/bin to PATH so it resolves on a
fresh login, and the quickstart drops the misleading sudo from --scan /
--audit / --auto.

CVE metadata drift (the failing weekly drift-check):
  - CVE-2022-0492 (cgroup_release_agent) entered CISA KEV 2026-06-02;
    corpus now 13 of 36 modules cover KEV-listed CVEs.
  - CVE-2026-46333 (ptrace_pidfd) gained CWE-269 from NVD (was unclassified
    at module-add time).
Refreshed CVE_METADATA.json, generated cve_metadata.c, and KEV_CROSSREF.md;
README + website KEV counts and version bumped to 0.9.9.
2026-06-08 10:16:24 -04:00

161 lines
6.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# SKELETONKEY one-shot installer.
#
# Usage:
# curl -sSL https://github.com/KaraZajac/SKELETONKEY/releases/latest/download/install.sh | sh
#
# Or with explicit version:
# SKELETONKEY_VERSION=v0.1.0 curl ... | sh
#
# Or install to a different prefix:
# SKELETONKEY_PREFIX=$HOME/.local/bin curl ... | sh
#
# Environment:
# SKELETONKEY_VERSION release tag (default: latest)
# SKELETONKEY_PREFIX install dir (default: /usr/local/bin if writable, else error)
# SKELETONKEY_REPO override repo (default: KaraZajac/SKELETONKEY)
#
# Exit codes:
# 0 — installed successfully
# 1 — error (unsupported arch, download failure, permission denied)
# POSIX-friendly: -eu is universal, pipefail only on shells that
# support it (bash, ksh, dash >= 0.5.12). Without pipefail the
# installer still exits on the first hard error since every curl/
# tar/install step is checked explicitly.
set -eu
(set -o pipefail) 2>/dev/null && set -o pipefail || true
REPO="${SKELETONKEY_REPO:-KaraZajac/SKELETONKEY}"
VERSION="${SKELETONKEY_VERSION:-latest}"
# 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; }
fail() { printf '[\033[1;31m-\033[0m] %s\n' "$*" >&2; exit 1; }
# Detect architecture. Default to the musl-static binary on both
# x86_64 and arm64 — works on every libc (glibc 2.x of any version,
# musl, uclibc); costs ~800 KB extra vs dynamic but eliminates the
# GLIBC_2.NN portability ceiling that bites on Debian-stable, older
# RHEL hosts, and Alpine. Set SKELETONKEY_DYNAMIC=1 to fetch the
# smaller dynamic build (needs glibc >= 2.38 for x86_64 — Ubuntu
# 24.04 / Debian 13 / RHEL 10).
arch=$(uname -m)
case "$arch" in
x86_64|amd64)
if [ "${SKELETONKEY_DYNAMIC:-0}" = "1" ]; then
target=x86_64
else
target=x86_64-static
fi
;;
aarch64|arm64)
if [ "${SKELETONKEY_DYNAMIC:-0}" = "1" ]; then
target=arm64
else
target=arm64-static
fi
;;
*) fail "Unsupported architecture: $arch (only x86_64 and arm64 currently)" ;;
esac
log "detected arch: $target"
# Resolve version → download URL
if [ "$VERSION" = "latest" ]; then
url="https://github.com/${REPO}/releases/latest/download/skeletonkey-${target}"
sha_url="https://github.com/${REPO}/releases/latest/download/skeletonkey-${target}.sha256"
else
url="https://github.com/${REPO}/releases/download/${VERSION}/skeletonkey-${target}"
sha_url="https://github.com/${REPO}/releases/download/${VERSION}/skeletonkey-${target}.sha256"
fi
log "downloading from: $url"
# Need curl. wget fallback would be nice but skipping for simplicity.
if ! command -v curl >/dev/null 2>&1; then
fail "curl is required (apt install curl / dnf install curl)"
fi
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
if ! curl -fsSLo "$tmp/skeletonkey" "$url"; then
fail "download failed. Check the version exists at https://github.com/${REPO}/releases"
fi
# Verify checksum if available
if curl -fsSLo "$tmp/skeletonkey.sha256" "$sha_url" 2>/dev/null; then
# The .sha256 file has the binary's original name; normalize for our local copy
expected=$(awk '{print $1}' "$tmp/skeletonkey.sha256")
if command -v sha256sum >/dev/null 2>&1; then
actual=$(sha256sum "$tmp/skeletonkey" | awk '{print $1}')
elif command -v shasum >/dev/null 2>&1; then
actual=$(shasum -a 256 "$tmp/skeletonkey" | awk '{print $1}')
else
actual=""
log "no sha256sum/shasum available — skipping checksum verification"
fi
if [ -n "$actual" ]; then
if [ "$actual" = "$expected" ]; then
ok "checksum verified"
else
fail "checksum mismatch (expected $expected, got $actual)"
fi
fi
else
log "no checksum file at $sha_url — skipping verification"
fi
chmod +x "$tmp/skeletonkey"
# 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
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 <<EOF
[\033[1;33m!\033[0m] AUTHORIZED TESTING ONLY — see https://github.com/${REPO}/blob/main/docs/ETHICS.md
Quickstart (no root required — gaining it is the point):
skeletonkey --scan # what's this box vulnerable to?
skeletonkey --audit # broader system hygiene
skeletonkey --auto --i-know # run the safest available LPE
Deploy detection rules (defensive; only the write to /etc/audit needs root):
skeletonkey --detect-rules --format=auditd \\
| sudo tee /etc/audit/rules.d/99-skeletonkey.rules
See \`skeletonkey --help\` for all commands.
EOF