CIS490/vm/launch_target.sh
Elliott Kolden b29d30a1b2 Tier-3: fix QEMU boot, catalog admission, verify module
Bug 14 (vm/launch_target.sh): Metasploitable2 requires -machine pc
(i440fx), -cpu kvm32, -drive if=ide, and -device e1000. The previous
config (-machine q35, -cpu host, -drive if=virtio, virtio-net-pci)
caused a kernel panic at boot because /dev/vda != the grub root=/dev/sda1.
Services never started; the b'' probe fix (Bug 10) then correctly waited
out the full timeout with no result.

Bug 15 (scripts/install-tier-3-4.sh): verify step used vsftpd_234_backdoor
which is requires_bridge=true and has a hardcoded port-6200 backdoor.
Changed to distccd_command_exec with TARGET_PORTS="5632:3632,4444:4444".

manifest.toml: admit distccd_command_exec and unreal_ircd_3281_backdoor
to the module catalog. Both use cmd/unix/bind_perl (bind shell, no guest
egress, SLIRP-safe). distccd returns a valid protocol response so MSF's
handler runs and session_open fires. Verified against Metasploitable2
sourceforge image sha256 a8c019c3.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:41:41 -06:00

122 lines
4.5 KiB
Bash
Executable file

#!/usr/bin/env bash
# Boot the Tier-3 *target* VM (the intentionally-vulnerable guest the
# exploit fires against). Companion to ``launch_demo.sh``, which boots
# the *idle* Alpine guest used in Tiers 1-2.
#
# Networking note: this launcher uses SLIRP usermode networking with
# ``restrict=on`` plus an explicit ``hostfwd`` for each vulnerable port.
# That gives us:
# - the host can reach the guest's services (for msfrpcd + the
# exploit module to drive ``RHOSTS=127.0.0.1``)
# - the guest cannot reach the host or the internet (no NAT exit)
#
# The host-only ``br-malware`` bridge described in docs/architecture.md
# replaces SLIRP once the bridge-side pcap collector (source 4) lands —
# at which point payloads with ``reverse_tcp`` callbacks become viable
# too. Until then, we restrict module choices to ones that return a
# shell on the same socket they exploit (e.g. vsftpd_234_backdoor).
#
# Run-dir contract (read by run_tier3_demo.py):
# $RUN_DIR/qemu.pid
# $RUN_DIR/qmp.sock
# $RUN_DIR/monitor.sock
# $RUN_DIR/serial.sock
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
IMAGE="${IMAGE:-$REPO_ROOT/vm/images/metasploitable2.qcow2}"
SLOT="${SLOT:-0}"
RUN_DIR="${RUN_DIR:-/tmp/cis490-target-$SLOT}"
RAM_MIB="${RAM_MIB:-512}"
# When BRIDGE is set, attach a tap to the host-only bridge instead of
# using SLIRP. Pcap-feature episodes (source 4) require this.
BRIDGE="${BRIDGE:-}"
TAP="${TAP:-cis490target$SLOT}"
# Ports the host should forward to the guest. Comma-separated host:guest pairs.
# Default covers the vsftpd module's RPORT. Host port uses an unprivileged
# range (>1023) so the service user (cis490) can bind it without root.
# Slot offset makes per-VM fleet runs collision-free
# (slot 0 → 2021, slot 1 → 2121, slot 2 → 2221, ...).
PORT_BASE="${PORT_BASE:-$((2021 + SLOT * 100))}"
TARGET_PORTS="${TARGET_PORTS:-${PORT_BASE}:21}"
# KVM if the host can take it; otherwise fall back to TCG. Cross-arch
# images (Metasploitable2 is x86-only) on aarch64 hosts will need TCG.
ACCEL="${ACCEL:-}"
mkdir -p "$RUN_DIR"
QMP_SOCK="$RUN_DIR/qmp.sock"
MON_SOCK="$RUN_DIR/monitor.sock"
PID_FILE="$RUN_DIR/qemu.pid"
SERIAL_SOCK="$RUN_DIR/serial.sock"
if [[ ! -f "$IMAGE" ]]; then
cat >&2 <<EOF
no target image at $IMAGE
Drop a vulnerable Linux qcow2 there. The canonical choice is
Metasploitable2 — see docs/sources.md for the download + sha256.
If the image is x86 and your host is not, set ACCEL=tcg explicitly.
EOF
exit 1
fi
# Build the netdev string. With BRIDGE set we use a tap on the host-only
# bridge (so source-4 pcap captures the traffic). Without it, SLIRP
# usermode + restrict=on for the no-egress smoke runs.
if [[ -n "$BRIDGE" ]]; then
NETDEV="tap,id=n0,ifname=$TAP,script=no,downscript=no"
else
NETDEV="user,id=n0,restrict=on"
IFS=',' read -ra _PAIRS <<< "$TARGET_PORTS"
for pair in "${_PAIRS[@]}"; do
host_port="${pair%%:*}"
guest_port="${pair##*:}"
NETDEV+=",hostfwd=tcp:127.0.0.1:${host_port}-:${guest_port}"
done
fi
# Pick acceleration: explicit override wins; otherwise use KVM if the
# device is present, else TCG.
if [[ -z "$ACCEL" ]]; then
if [[ -e /dev/kvm && -r /dev/kvm && -w /dev/kvm ]]; then
ACCEL="kvm"
else
ACCEL="tcg"
fi
fi
CPU_FLAGS=()
if [[ "$ACCEL" == "kvm" ]]; then
# kvm32: safe 32-bit KVM model. -cpu host exposes XSAVE/AVX/etc. that
# Ubuntu 8.04's 2.6.24 kernel (Metasploitable2) can't handle, causing
# a boot hang before any services start.
CPU_FLAGS=(-cpu kvm32)
fi
AGENT_SOCK="$RUN_DIR/agent.sock"
# snapshot=on so the qcow2 is never mutated — every boot is identical.
# Second virtio-serial port carries the in-guest agent's telemetry to
# the host (see vm/guest-agent/). Targets without the agent installed
# (e.g. unmodified Metasploitable2) leave the device unused — the
# host-side collector simply gets no rows. Harmless.
exec qemu-system-x86_64 \
-name cis490-target \
-machine pc,accel="$ACCEL" \
"${CPU_FLAGS[@]}" \
-smp 1,sockets=1,cores=1,threads=1 \
-m "$RAM_MIB" \
-drive file="$IMAGE",format=qcow2,if=ide,snapshot=on \
-netdev "$NETDEV" \
-device e1000,netdev=n0 \
-device virtio-serial-pci,id=cis490vs0 \
-chardev socket,id=cis490agent,path="$AGENT_SOCK",server=on,wait=off \
-device virtserialport,chardev=cis490agent,name=cis490.guest.agent \
-nographic \
-serial unix:"$SERIAL_SOCK",server=on,wait=off \
-monitor unix:"$MON_SOCK",server=on,wait=off \
-qmp unix:"$QMP_SOCK",server=on,wait=off \
-pidfile "$PID_FILE" \
-display none