verify-vm: per-module provisioner hook + old-mainline URL fallback
Adds tools/verify-vm/provisioners/<module>.sh hook so per-module setup
(build vulnerable sudo from source, drop polkit allow rule, add sudoers
grant) lives in checked-in scripts rather than manual VM steps. Vagrantfile
runs the script as root before build-and-verify if it exists.
Also fixes mainline kernel fetch to fall back from /v${KVER}/amd64/ to
/v${KVER}/ for old kernels (≤ ~4.15) where debs aren't under the amd64
subdir, and accepts both 'linux-image-' (old) and 'linux-image-unsigned-'
(new) deb names.
Wires up 4 previously-deferred targets to expect VULNERABLE:
- sudo_chwoot: builds sudo 1.9.16p1 from upstream into /usr/local
- udisks_libblockdev: installs udisks2 + polkit rule for vagrant user
- mutagen_astronomy: pins mainline 4.14.70 (one below the .71 fix)
- sudo_runas_neg1: adds (ALL,!root) sudoers grant
This commit is contained in:
Vendored
+30
-5
@@ -101,17 +101,28 @@ Vagrant.configure("2") do |c|
|
||||
exit 0
|
||||
fi
|
||||
echo "[+] fetching kernel.ubuntu.com mainline v${KVER}"
|
||||
URL="https://kernel.ubuntu.com/mainline/v${KVER}/amd64/"
|
||||
# Newer mainline kernels live under /v${KVER}/amd64/; older ones
|
||||
# (≤ ~4.15) put debs at /v${KVER}/ directly. Try /amd64/ first;
|
||||
# fall back to bare. linux-image-unsigned was renamed from
|
||||
# linux-image- around 4.18 — old kernels use the plain name.
|
||||
BASE="https://kernel.ubuntu.com/mainline/v${KVER}"
|
||||
for URL in "${BASE}/amd64/" "${BASE}/"; do
|
||||
INDEX=$(curl -sL "$URL")
|
||||
if echo "$INDEX" | grep -q '\\.deb"'; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
TMP=$(mktemp -d)
|
||||
cd "$TMP"
|
||||
# Pick the 4 canonical generic-kernel .debs by pattern match against
|
||||
# the directory index. Skip lowlatency variants.
|
||||
DEBS=$(curl -sL "$URL" | \\
|
||||
# the directory index. Skip lowlatency variants. Accept both
|
||||
# 'linux-image-unsigned-' (newer) and 'linux-image-' (older).
|
||||
DEBS=$(echo "$INDEX" | \\
|
||||
grep -oE 'href="[^"]+\\.deb"' | sed 's/href="//; s/"$//' | \\
|
||||
grep -E '(linux-image-unsigned|linux-modules|linux-headers)-[0-9.]+-[0-9]+-generic_|linux-headers-[0-9.]+-[0-9]+_[^_]+_all\\.deb' | \\
|
||||
grep -E '(linux-image(-unsigned)?|linux-modules|linux-headers)-[0-9.]+-[0-9]+-generic_|linux-headers-[0-9.]+-[0-9]+_[^_]+_all\\.deb' | \\
|
||||
grep -v lowlatency)
|
||||
if [ -z "$DEBS" ]; then
|
||||
echo "[-] no .debs found at $URL — does the version exist on kernel.ubuntu.com?" >&2
|
||||
echo "[-] no .debs found at ${BASE}/ (tried /amd64/ and bare)" >&2
|
||||
exit 2
|
||||
fi
|
||||
for f in $DEBS; do
|
||||
@@ -125,6 +136,20 @@ Vagrant.configure("2") do |c|
|
||||
SHELL
|
||||
end
|
||||
|
||||
# 2c. Optional per-module provisioner. If
|
||||
# tools/verify-vm/provisioners/<module>.sh exists, run it as root
|
||||
# before build-and-verify. Used for things only meaningful per-module:
|
||||
# build sudo 1.9.16 from source (sudo_chwoot), drop a polkit allow
|
||||
# rule (udisks_libblockdev), add a sudoers grant (sudo_runas_neg1).
|
||||
skk_mod = ENV["SKK_MODULE"] || ""
|
||||
if !skk_mod.empty?
|
||||
prov_path = File.join(__dir__, "provisioners", "#{skk_mod}.sh")
|
||||
if File.exist?(prov_path)
|
||||
m.vm.provision "shell", name: "module-provision-#{skk_mod}",
|
||||
path: prov_path
|
||||
end
|
||||
end
|
||||
|
||||
# 3. Build SKELETONKEY in-VM and run --explain --active for the target
|
||||
# module. Runs as the unprivileged 'vagrant' user (NOT root) — most
|
||||
# detect()s gate on "are you already root?" and short-circuit if so,
|
||||
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
# CVE-2025-32463 sudo --chroot NSS injection (Stratascale). Vulnerable
|
||||
# range is sudo [1.9.14, 1.9.17p0]. Ubuntu 22.04 ships 1.9.9 which
|
||||
# PREDATES the --chroot code path. Build sudo 1.9.16p1 from upstream
|
||||
# and install to /usr/local (which precedes /usr/bin in Ubuntu's default
|
||||
# PATH so plain `sudo` resolves to the vulnerable binary).
|
||||
set -e
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get install -y -qq libpam0g-dev libssl-dev wget make gcc >/dev/null
|
||||
|
||||
cd /tmp
|
||||
TARBALL=sudo-1.9.16p1.tar.gz
|
||||
URL="https://www.sudo.ws/dist/${TARBALL}"
|
||||
|
||||
if [ -x /usr/local/bin/sudo ] && /usr/local/bin/sudo --version 2>&1 | head -1 | grep -q "1.9.16p1"; then
|
||||
echo "[=] sudo 1.9.16p1 already at /usr/local/bin/sudo"
|
||||
else
|
||||
[ -f "${TARBALL}" ] || wget -q "${URL}"
|
||||
rm -rf sudo-1.9.16p1
|
||||
tar xzf "${TARBALL}"
|
||||
cd sudo-1.9.16p1
|
||||
# --sysconfdir=/etc so it honors the existing /etc/sudoers (vagrant's
|
||||
# NOPASSWD grant). --disable-shared keeps the build self-contained.
|
||||
./configure --prefix=/usr/local --sysconfdir=/etc \
|
||||
--disable-shared --quiet >/dev/null 2>&1
|
||||
make -j"$(nproc)" >/tmp/sudo-build.log 2>&1 || { tail -40 /tmp/sudo-build.log; exit 1; }
|
||||
make install >/tmp/sudo-install.log 2>&1 || { tail -40 /tmp/sudo-install.log; exit 1; }
|
||||
fi
|
||||
|
||||
# Verify what the unprivileged user's PATH resolves to.
|
||||
echo "[+] which sudo (root): $(which sudo)"
|
||||
echo "[+] /usr/local/bin/sudo version: $(/usr/local/bin/sudo --version | head -1)"
|
||||
sudo -u vagrant bash -c 'echo "[+] vagrant PATH: $PATH"; echo "[+] vagrant sees: $(which sudo)"; sudo --version | head -1'
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
# CVE-2019-14287 needs a (ALL,!root) grant for find_runas_blacklist_grant()
|
||||
# to fire. Ubuntu 18.04 ships sudo 1.8.21p2 (in the vulnerable range) but
|
||||
# Vagrant's default sudoers doesn't include the grant. Add it.
|
||||
set -e
|
||||
|
||||
cat >/etc/sudoers.d/99-skk-runas-neg1 <<'EOF'
|
||||
vagrant ALL=(ALL,!root) NOPASSWD: /bin/vi
|
||||
EOF
|
||||
chmod 0440 /etc/sudoers.d/99-skk-runas-neg1
|
||||
|
||||
echo "[+] sudoers grant installed:"
|
||||
grep . /etc/sudoers.d/99-skk-runas-neg1
|
||||
echo
|
||||
echo "[+] sudo -ln -U vagrant tail:"
|
||||
sudo -ln -U vagrant 2>&1 | tail -10 || true
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
# CVE-2025-6019 udisks/libblockdev SUID-on-mount (Qualys). Debian 12's
|
||||
# cloud image is server-oriented and doesn't ship udisks2. Install it,
|
||||
# and drop a polkit rule allowing the vagrant user to invoke the
|
||||
# affected action.ids — the real-world bug-path is "active console
|
||||
# user invokes loop-setup", and we don't have a graphical session in
|
||||
# Vagrant. The polkit rule simulates the trust polkit would give a
|
||||
# logged-in workstation user.
|
||||
set -e
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get install -y -qq udisks2 libblockdev-utils3 >/dev/null
|
||||
|
||||
mkdir -p /etc/polkit-1/rules.d
|
||||
cat >/etc/polkit-1/rules.d/49-skk-verify.rules <<'EOF'
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (subject.user == "vagrant" &&
|
||||
(action.id == "org.freedesktop.UDisks2.loop-setup" ||
|
||||
action.id == "org.freedesktop.UDisks2.filesystem-mount" ||
|
||||
action.id == "org.freedesktop.UDisks2.filesystem-mount-other-seat" ||
|
||||
action.id == "org.freedesktop.UDisks2.modify-device")) {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
EOF
|
||||
|
||||
systemctl enable udisks2.service >/dev/null 2>&1 || true
|
||||
systemctl restart udisks2.service
|
||||
sleep 2
|
||||
|
||||
echo "[+] udisks2 status:"
|
||||
systemctl is-active udisks2.service
|
||||
echo "[+] udisks2 version: $(dpkg-query -W -f='${Version}' udisks2)"
|
||||
echo "[+] libblockdev version: $(dpkg-query -W -f='${Version}' libblockdev-utils3 2>/dev/null || dpkg-query -W -f='${Version}' libblockdev-utils2)"
|
||||
@@ -224,18 +224,18 @@ vmwgfx:
|
||||
# ── v0.8.0 additions ──────────────────────────────────────────────
|
||||
|
||||
sudo_chwoot:
|
||||
box: ubuntu2204 # 22.04 ships sudo 1.9.9 (pre-feature) — need a 1.9.14+ install
|
||||
box: ubuntu2204 # 22.04 ships sudo 1.9.9 — provisioner builds 1.9.16p1 over it
|
||||
kernel_pkg: "" # this bug is sudo-version-gated, not kernel
|
||||
kernel_version: "5.15.0"
|
||||
expect_detect: OK
|
||||
notes: "CVE-2025-32463; sudo --chroot NSS shim. Vulnerable range is sudo [1.9.14, 1.9.17p0]. Ubuntu 22.04 ships sudo 1.9.9 which PREDATES the vulnerable --chroot code path — so detect correctly returns OK. To validate VULNERABLE empirically, provision a vulnerable sudo build into the VM (e.g. apt install -t backports sudo=1.9.16-1 or build from source). Deferred."
|
||||
expect_detect: VULNERABLE
|
||||
notes: "CVE-2025-32463; sudo --chroot NSS shim. Vulnerable range is sudo [1.9.14, 1.9.17p0]. provisioners/sudo_chwoot.sh builds sudo 1.9.16p1 from upstream sources into /usr/local/bin (which precedes /usr/bin in PATH so plain `sudo` resolves to the vulnerable binary)."
|
||||
|
||||
udisks_libblockdev:
|
||||
box: debian12 # 12 ships udisks2 2.10.x + libblockdev 3.0.x — vulnerable
|
||||
kernel_pkg: ""
|
||||
kernel_version: "6.1.0"
|
||||
expect_detect: PRECOND_FAIL
|
||||
notes: "CVE-2025-6019; udisks/libblockdev SUID-on-mount. Debian 12's cloud image is server-oriented — udisksd is NOT installed by default. detect correctly returns PRECOND_FAIL ('udisksd not installed; bug unreachable here'). To validate VULNERABLE empirically, install udisks2 + log in as an active-session user (Vagrant SSH session is NOT active per polkit — needs a real console session). Both gates are real and the detect honestly surfaces them; deferred."
|
||||
expect_detect: VULNERABLE
|
||||
notes: "CVE-2025-6019; udisks/libblockdev SUID-on-mount. provisioners/udisks_libblockdev.sh installs udisks2 + libblockdev-utils3 and drops a polkit rule allowing the vagrant user to invoke loop-setup/filesystem-mount — simulating the trust polkit would give a logged-in workstation user (the real-world bug-path). Without that rule, the SSH session is not 'active' per polkit and the D-Bus call short-circuits."
|
||||
|
||||
pintheft:
|
||||
box: "" # RDS is blacklisted on every common Vagrant box's stock kernel
|
||||
@@ -248,18 +248,19 @@ pintheft:
|
||||
# ── v0.9.0 additions (gap fillers 2018 / 2019 / 2020 / 2024) ──────
|
||||
|
||||
mutagen_astronomy:
|
||||
box: ubuntu1804 # 4.15.0-213 stock — already > 4.14.71 backport → OK
|
||||
box: ubuntu1804 # stock 4.15.0-213 is post-fix; mainline 4.14.70 is one below the .71 fix
|
||||
kernel_pkg: ""
|
||||
kernel_version: "4.15.0"
|
||||
expect_detect: OK
|
||||
notes: "CVE-2018-14634; Qualys Mutagen Astronomy. Ubuntu 18.04 ships 4.15.0-213 which is post-fix. detect correctly returns OK. Verifying the VULNERABLE path empirically needs a 2.6.x / 3.10.x EOL kernel (e.g. RHEL 6 / CentOS 6 / Debian 7); deferred to a custom-box workflow."
|
||||
mainline_version: "4.14.70"
|
||||
kernel_version: "4.14.70"
|
||||
expect_detect: VULNERABLE
|
||||
notes: "CVE-2018-14634; Qualys Mutagen Astronomy. Mainline 4.14.70 sits one stable below the 4.14.71 backport. Old mainline kernels live at /v${KVER}/ directly (no /amd64/ subdir); Vagrantfile's pin-mainline provisioner falls back to the bare path."
|
||||
|
||||
sudo_runas_neg1:
|
||||
box: ubuntu1804 # ships sudo 1.8.21p2 (vulnerable; pre-1.8.28 fix)
|
||||
kernel_pkg: ""
|
||||
kernel_version: "4.15.0"
|
||||
expect_detect: PRECOND_FAIL
|
||||
notes: "CVE-2019-14287; sudo Runas -u#-1. Ubuntu 18.04 ships sudo 1.8.21p2 which IS in the vulnerable range — but the default vagrant user has no (ALL,!root) sudoers grant for find_runas_blacklist_grant() to abuse, so detect correctly returns PRECOND_FAIL. To validate VULNERABLE empirically, provision a sudoers entry of the form 'vagrant ALL=(ALL,!root) /bin/vi' before verifying."
|
||||
expect_detect: VULNERABLE
|
||||
notes: "CVE-2019-14287; sudo Runas -u#-1. Ubuntu 18.04 ships sudo 1.8.21p2 (vulnerable). provisioners/sudo_runas_neg1.sh adds 'vagrant ALL=(ALL,!root) NOPASSWD: /bin/vi' to /etc/sudoers.d/ so find_runas_blacklist_grant() has a grant to abuse."
|
||||
|
||||
tioscpgrp:
|
||||
box: ubuntu2004 # 5.4 stock kernels (5.4.0-26) are below the 5.4.85 backport
|
||||
|
||||
Reference in New Issue
Block a user