5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / setup.sh SH
#!/bin/bash
# ─────────────────────────────────────────────────────────────────────
# KSMBD-012 Test Environment Setup
# ─────────────────────────────────────────────────────────────────────
#
# Builds a QEMU-bootable kernel (6.19.x) with ksmbd and an initramfs
# that auto-starts a vulnerable ksmbd server on boot.
#
# Current Ubuntu/Debian LTS kernels (<=6.11) do not include ksmbd
# durable handle support (merged in 6.12-rc1, commit c8efcc786146),
# so a QEMU environment is required.
#
# Prerequisites:
#   sudo apt install build-essential flex bison bc libelf-dev libssl-dev \
#       libglib2.0-dev libnl-3-dev libnl-genl-3-dev libtool autoconf \
#       qemu-system-x86 busybox-static cpio python3-pip
#   pip3 install impacket
#
# Usage:
#   ./setup.sh                  # downloads kernel, builds everything
#   ./setup.sh /path/to/source  # use existing kernel source tree
#
# After setup completes, run:
#   ./run.sh                          # boots QEMU, ksmbd starts automatically
#   python3 exploit.py acl-bypass ... # from another terminal
# ─────────────────────────────────────────────────────────────────────
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
WORK="$SCRIPT_DIR/.build"
KERNEL_VER="${KERNEL_VER:-6.19.11}"
KSMBD_TOOLS_REPO="https://github.com/cifsd-team/ksmbd-tools.git"

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
info()  { echo -e "${GREEN}[*]${NC} $*"; }
warn()  { echo -e "${YELLOW}[!]${NC} $*"; }
err()   { echo -e "${RED}[-]${NC} $*" >&2; exit 1; }

# ── Check prerequisites ───────────────────────────────────────────
for cmd in make gcc qemu-system-x86_64 cpio gzip git autoconf; do
    command -v "$cmd" &>/dev/null || err "Missing: $cmd"
done

BUSYBOX="$(command -v busybox 2>/dev/null || true)"
[ -n "$BUSYBOX" ] && file "$BUSYBOX" | grep -q "statically linked" || \
    err "Need statically-linked busybox (apt install busybox-static)"

mkdir -p "$WORK"

# ── Step 1: Kernel source ─────────────────────────────────────────
if [ -n "${1:-}" ] && [ -f "$1/Makefile" ]; then
    KSRC="$(cd "$1" && pwd)"
    info "Using existing kernel source: $KSRC"
else
    KSRC="$WORK/linux-$KERNEL_VER"
    if [ -f "$KSRC/Makefile" ]; then
        info "Kernel source already present at $KSRC"
    else
        TARBALL="$WORK/linux-$KERNEL_VER.tar.xz"
        if [ ! -f "$TARBALL" ]; then
            MAJOR="${KERNEL_VER%%.*}"
            URL="https://cdn.kernel.org/pub/linux/kernel/v${MAJOR}.x/linux-${KERNEL_VER}.tar.xz"
            info "Downloading kernel $KERNEL_VER..."
            curl -L -o "$TARBALL" "$URL"
        fi
        info "Extracting kernel source..."
        tar -xf "$TARBALL" -C "$WORK"
    fi
fi

# ── Step 2: Build ksmbd-tools ─────────────────────────────────────
TOOLS="$WORK/ksmbd-tools"
if [ ! -f "$TOOLS/tools/ksmbd.tools" ]; then
    info "Building ksmbd-tools..."
    [ -d "$TOOLS" ] || git clone --depth=1 "$KSMBD_TOOLS_REPO" "$TOOLS"
    (cd "$TOOLS" && autoreconf -i && \
     ./configure --prefix=/ --sysconfdir=/etc --localstatedir=/var && \
     make -j"$(nproc)")
fi

# Verify durable handle support
if ! strings "$TOOLS/tools/ksmbd.tools" | grep "durable handles" >/dev/null 2>&1; then
    err "ksmbd-tools lacks durable handle support"
fi
info "ksmbd-tools ready ($(cd "$TOOLS" && ./tools/ksmbd.tools --version 2>&1 | head -1 || true))"

# ── Step 3: Configure and build kernel ─────────────────────────────
info "Configuring kernel..."
cd "$KSRC"
if [ ! -f .config ]; then
    make defconfig
fi

scripts/config \
    -e CONFIG_SMB_SERVER \
    -e CONFIG_INET -e CONFIG_NET \
    -e CONFIG_NLS -e CONFIG_NLS_UTF8 -e CONFIG_UNICODE \
    -e CONFIG_CRYPTO_MD5 -e CONFIG_CRYPTO_HMAC -e CONFIG_CRYPTO_SHA256 \
    -e CONFIG_CRYPTO_SHA512 -e CONFIG_CRYPTO_CMAC -e CONFIG_CRYPTO_AES \
    -e CONFIG_CRYPTO_ECB -e CONFIG_CRYPTO_DES -e CONFIG_CRYPTO_CCM \
    -e CONFIG_CRYPTO_GCM -e CONFIG_CRYPTO_CRC32 \
    -e CONFIG_VIRTIO -e CONFIG_VIRTIO_NET -e CONFIG_VIRTIO_PCI \
    -e CONFIG_DEVTMPFS -e CONFIG_DEVTMPFS_MOUNT -e CONFIG_TMPFS \
    -e CONFIG_PROC_FS -e CONFIG_SERIAL_8250 -e CONFIG_SERIAL_8250_CONSOLE \
    -e CONFIG_BLK_DEV_INITRD

make olddefconfig
grep -q "CONFIG_SMB_SERVER=y" .config || err "CONFIG_SMB_SERVER not enabled"

info "Building kernel ($(nproc) jobs)..."
make -j"$(nproc)" bzImage

BZIMAGE="$KSRC/arch/x86/boot/bzImage"
[ -f "$BZIMAGE" ] || err "bzImage not found"

# ── Step 4: Build initramfs ────────────────────────────────────────
info "Building initramfs..."
INITRD="$WORK/initramfs"
rm -rf "$INITRD"
mkdir -p "$INITRD"/{bin,sbin,lib,lib64,etc/ksmbd,proc,sys,dev,tmp/smbtest,run,var/run}

cp "$BUSYBOX" "$INITRD/bin/busybox"
(cd "$INITRD/bin" && for c in sh ls cat echo mkdir mount umount sleep ip ln \
    mknod chmod chown kill rm grep; do ln -sf busybox "$c"; done)

cp "$TOOLS/tools/ksmbd.tools" "$INITRD/sbin/"
(cd "$INITRD/sbin" && ln -sf ksmbd.tools ksmbd.mountd && ln -sf ksmbd.tools ksmbd.adduser)

for lib in $(ldd "$TOOLS/tools/ksmbd.tools" 2>/dev/null | grep -o '/[^ ]*' | sort -u); do
    [ -f "$lib" ] && { mkdir -p "$INITRD$(dirname "$lib")"; cp "$lib" "$INITRD$(dirname "$lib")/"; }
done
cp /lib64/ld-linux-x86-64.so.2 "$INITRD/lib64/" 2>/dev/null || true

# NSS plugin for getpwnam_r — dlopen()ed at runtime, not visible to ldd.
# Without this, ksmbd-tools cannot resolve victim/attacker → POSIX UIDs and
# every SMB user falls back to uid 0 (root), defeating the ACL boundary.
for libdir in /usr/lib/x86_64-linux-gnu /lib/x86_64-linux-gnu /usr/lib64 /lib64; do
    if [ -f "$libdir/libnss_files.so.2" ]; then
        mkdir -p "$INITRD$libdir"
        cp "$libdir/libnss_files.so.2" "$INITRD$libdir/"
        break
    fi
done

cat > "$INITRD/init" << 'INITSCRIPT'
#!/bin/sh
export PATH=/bin:/sbin
mount -t proc proc /proc; mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev; mount -t tmpfs tmpfs /tmp; mount -t tmpfs tmpfs /run
mknod -m 666 /dev/null c 1 3 2>/dev/null
ip link set lo up; ip addr add 127.0.0.1/8 dev lo
for iface in eth0 ens0; do
    ip link set $iface up 2>/dev/null && { ip addr add 10.0.2.15/24 dev $iface; break; }
done
mkdir -p /tmp/smbtest /etc/ksmbd /var/run

# POSIX users — ksmbd-tools resolves SMB account → uid via getpwnam_r,
# so without these every SMB user maps to uid 0 and the ACL boundary
# we want to demonstrate disappears.
cat > /etc/passwd << 'EOF'
root:x:0:0:root:/root:/bin/sh
victim:x:1000:1000:victim:/tmp:/bin/sh
attacker:x:1001:1001:attacker:/tmp:/bin/sh
EOF
cat > /etc/group << 'EOF'
root:x:0:
victim:x:1000:
attacker:x:1001:
EOF
cat > /etc/nsswitch.conf << 'EOF'
passwd: files
group:  files
shadow: files
EOF

# Pre-stage the share with a victim-owned 0600 file so the ACL bypass
# is provable. Default file name matches `python3 exploit.py acl-bypass --file`.
# Share dir must be victim-writable: SMB DESIRED_ACCESS=DELETE on a file
# requires +w on the parent, otherwise victim's own CREATE is rejected.
chown 1000:1000 /tmp/smbtest
chmod 0700      /tmp/smbtest
echo 'placeholder - will be overwritten by victim' > /tmp/smbtest/secret_0600.txt
chown 1000:1000 /tmp/smbtest/secret_0600.txt
chmod 0600        /tmp/smbtest/secret_0600.txt

ksmbd.adduser -a -p Victim1 victim
ksmbd.adduser -a -p Attacker2 attacker
cat > /etc/ksmbd/ksmbd.conf << 'EOF'
[global]
    server signing = disabled
    smb3 encryption = disabled
    server min protocol = SMB2_10
    server max protocol = SMB3_11
    # SMB2_10 = 2.1 (allows the dialect-regression test); SMB3_11 = 3.1.1.
    durable handles = yes
[share]
    path = /tmp/smbtest
    read only = no
    guest ok = no
    valid users = victim, attacker
    oplocks = yes
EOF
ksmbd.mountd -n &
sleep 2
echo ""
echo "=== ksmbd ready ==="
echo "Users:   victim/Victim1 (uid 1000), attacker/Attacker2 (uid 1001)"
echo "Share:   share -> /tmp/smbtest"
echo "Target:  /tmp/smbtest/secret_0600.txt  (0600 victim:victim)"
echo ""
exec /bin/sh
INITSCRIPT
chmod +x "$INITRD/init"

(cd "$INITRD" && find . | cpio -o -H newc 2>/dev/null | gzip > "$WORK/initramfs.cpio.gz")

# ── Step 5: Create run script ─────────────────────────────────────
cat > "$SCRIPT_DIR/run.sh" << RUNEOF
#!/bin/bash
# Boot the vulnerable ksmbd QEMU environment.
# Once you see "=== ksmbd ready ===" run from another terminal:
#
#   python3 exploit.py acl-bypass \\
#       --target 127.0.0.1 --port 44500 --share share \\
#       --user victim --password Victim1 \\
#       --user2 attacker --password2 Attacker2 \\
#       --file secret_0600.txt
#
# Kill QEMU: Ctrl-A X

DIR="\$(cd "\$(dirname "\$0")" && pwd)"
exec qemu-system-x86_64 \\
    -kernel "$BZIMAGE" \\
    -initrd "$WORK/initramfs.cpio.gz" \\
    -append "console=ttyS0 nokaslr nopti" \\
    -m 512M -nographic -no-reboot \\
    -netdev user,id=net0,hostfwd=tcp::\${PORT:-44500}-:445 \\
    -device virtio-net-pci,netdev=net0
RUNEOF
chmod +x "$SCRIPT_DIR/run.sh"

# ── Done ───────────────────────────────────────────────────────────
echo ""
info "Setup complete."
info ""
info "  Kernel:  $BZIMAGE"
info "  Initrd:  $WORK/initramfs.cpio.gz"
info ""
info "  Terminal 1:  ./run.sh"
info "  Terminal 2:  python3 exploit.py acl-bypass \\"
info "                 --target 127.0.0.1 --port 44500 --share share \\"
info "                 --user victim --password Victim1 \\"
info "                 --user2 attacker --password2 Attacker2 \\"
info "                 --file secret_0600.txt"
info ""
info "  Server-side check (in QEMU console after the exploit runs):"
info "                 ls -l /tmp/smbtest/secret_0600.txt"
info "                 cat   /tmp/smbtest/secret_0600.txt"