Root causes and fixes documented in TIER3-BRINGUP.md. Summary:
1. BRIDGE env var leaked into Tier-3 subprocess → target VM used tap
instead of SLIRP; fix: env.pop("BRIDGE") in fleet _run_slot.
2. usable_modules filter conditioned on BRIDGE presence → bridge-requiring
modules selected on SLIRP runs; fix: always filter requires_bridge.
3. cmd/unix/interact creates no session.list entry → session_open_timeout
every episode; fix: switch samba_usermap_script to cmd/unix/bind_perl.
4. Per-slot LPORT hostfwd used wrong guest port (host:5444→guest:4444);
fix: extra_host_port:extra_host_port mapping so guest binds the
per-slot LPORT directly.
5. vsftpd backdoor port 6200 hardcoded → collision across concurrent slots;
fix: requires_bridge=true filters it from SLIRP fleet runs.
6. SLIRP false-positive in _wait_for_tcp → exploit fires before Samba
boots (~60 s too early); fix: replace TCP probe with serial console
_wait_for_serial_login that waits for actual "login:" prompt.
7. Stale QEMU survives orchestrator restart (start_new_session=True) →
holds hostfwd ports, new QEMU silently fails; fix: kill by pgid from
old pidfile before rmtree.
8. PORT_BASE default used privileged port 21; fix: default to 2021+slot*100.
9. msfrpcd 6.x returns bytes for all string values even with raw=False;
fix: MSFRpcClient._str() recursive decoder applied to all responses.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
153 lines
5.8 KiB
Bash
Executable file
153 lines
5.8 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Install + configure ``msfrpcd`` for the Tier-3 exploit driver.
|
|
#
|
|
# Idempotent: re-running on a host that already has msfrpcd refreshes
|
|
# the systemd unit and credentials but doesn't reinstall the framework.
|
|
#
|
|
# Steps:
|
|
# 1. Install metasploit-framework via the host package manager (or
|
|
# report the right one-liner for that distro). Big download —
|
|
# ~1 GiB and several minutes.
|
|
# 2. Generate a strong password and store at /etc/cis490/msfrpc.env
|
|
# (mode 0640, owner root:cis490).
|
|
# 3. Drop /etc/systemd/system/cis490-msfrpcd.service that runs
|
|
# msfrpcd bound to 127.0.0.1:55553 with the generated password.
|
|
# 4. Enable + start.
|
|
#
|
|
# After this runs, ``MSFRPC_PASSWORD=$(. /etc/cis490/msfrpc.env;
|
|
# echo $MSFRPC_PASSWORD)`` makes tools/run_tier3_demo.py work zero-touch.
|
|
|
|
set -euo pipefail
|
|
|
|
ETC_ROOT="/etc/cis490"
|
|
ENV_FILE="$ETC_ROOT/msfrpc.env"
|
|
UNIT="/etc/systemd/system/cis490-msfrpcd.service"
|
|
PORT="${MSFRPC_PORT:-55553}"
|
|
USER_NAME="${MSFRPC_USER:-msf}"
|
|
|
|
log() { printf '[install-msfrpcd] %s\n' "$*" >&2; }
|
|
die() { log "FATAL: $*"; exit 1; }
|
|
|
|
[[ $EUID -eq 0 ]] || die "must run as root"
|
|
command -v systemctl >/dev/null || die "systemd not found"
|
|
|
|
# --- 1. install metasploit-framework -----------------------------------
|
|
# Auto-install paths per package manager. Rapid7's omnibus installer
|
|
# is the canonical zero-touch path for Debian/Ubuntu — it adds the
|
|
# apt repo, the GPG key, and apt-installs the framework. Other
|
|
# distros use their native package or fall back to the omnibus shell
|
|
# script.
|
|
if ! command -v msfrpcd >/dev/null && [[ ! -x /opt/metasploit-framework/bin/msfrpcd ]]; then
|
|
log "msfrpcd not found; installing metasploit-framework (~1 GiB)"
|
|
if command -v apt-get >/dev/null; then
|
|
# Rapid7's omnibus installer wraps the apt-repo + GPG-key
|
|
# bootstrap + apt install in a single script. We fetch and
|
|
# exec it non-interactively. The script does:
|
|
# 1. add apt.metasploit.com to /etc/apt/sources.list.d/
|
|
# 2. install the GPG key
|
|
# 3. apt-get install -y metasploit-framework
|
|
log "running Rapid7 omnibus installer"
|
|
TMP="$(mktemp -d)"
|
|
curl -fsSL \
|
|
https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb \
|
|
-o "$TMP/msfinstall"
|
|
chmod +x "$TMP/msfinstall"
|
|
DEBIAN_FRONTEND=noninteractive "$TMP/msfinstall" </dev/null
|
|
rm -rf "$TMP"
|
|
elif command -v pacman >/dev/null; then
|
|
log "pacman -S metasploit"
|
|
pacman -Sy --noconfirm metasploit
|
|
elif command -v dnf >/dev/null; then
|
|
# The omnibus installer also supports rpm distros via the
|
|
# same script — it auto-detects and uses dnf/yum.
|
|
log "running Rapid7 omnibus installer (dnf path)"
|
|
TMP="$(mktemp -d)"
|
|
curl -fsSL \
|
|
https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb \
|
|
-o "$TMP/msfinstall"
|
|
chmod +x "$TMP/msfinstall"
|
|
"$TMP/msfinstall" </dev/null
|
|
rm -rf "$TMP"
|
|
else
|
|
die "unknown package manager — install metasploit-framework manually, then re-run"
|
|
fi
|
|
fi
|
|
|
|
# After install, msfrpcd may live at /opt/metasploit-framework/bin/
|
|
# (omnibus) or on PATH (apt repo). Symlink so callers find it.
|
|
if ! command -v msfrpcd >/dev/null; then
|
|
if [[ -x /opt/metasploit-framework/bin/msfrpcd ]]; then
|
|
ln -sf /opt/metasploit-framework/bin/msfrpcd /usr/local/bin/msfrpcd
|
|
fi
|
|
fi
|
|
command -v msfrpcd >/dev/null || die "msfrpcd still missing after install — see journalctl"
|
|
|
|
# --- 2. generate password ----------------------------------------------
|
|
install -d -m 0755 -o root -g root "$ETC_ROOT"
|
|
if ! id -u cis490 >/dev/null 2>&1; then
|
|
useradd --system --no-create-home --shell /usr/sbin/nologin cis490
|
|
fi
|
|
if [[ ! -f "$ENV_FILE" ]]; then
|
|
log "generating msfrpc password"
|
|
PW="$(openssl rand -base64 24 | tr -d '/+=' | head -c 32)"
|
|
install -m 0640 -o root -g cis490 /dev/stdin "$ENV_FILE" <<EOF
|
|
# Auto-generated by install-msfrpcd.sh — do not edit.
|
|
MSFRPC_HOST=127.0.0.1
|
|
MSFRPC_PORT=$PORT
|
|
MSFRPC_USER=$USER_NAME
|
|
MSFRPC_PASSWORD=$PW
|
|
EOF
|
|
else
|
|
log "$ENV_FILE exists; preserving existing password"
|
|
fi
|
|
|
|
# --- 3. systemd unit ----------------------------------------------------
|
|
# msfrpcd writes module cache + logs to $HOME/.msf4. With ProtectHome=true
|
|
# the service can't reach /root, so we redirect HOME to a path under
|
|
# /var/lib/cis490 that is always writable.
|
|
MSF_HOME="/var/lib/cis490/msf4"
|
|
install -d -m 0755 -o root -g root "$MSF_HOME"
|
|
|
|
log "installing systemd unit"
|
|
cat > "$UNIT" <<EOF
|
|
[Unit]
|
|
Description=CIS490 — Metasploit RPC daemon (loopback only)
|
|
Documentation=https://maxgit.wg/spectral/CIS490
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
EnvironmentFile=$ENV_FILE
|
|
Environment=HOME=$MSF_HOME
|
|
# msfrpcd flags:
|
|
# -P <pw> password
|
|
# -U <user> username
|
|
# -a <ip> bind address (loopback only — Tier-3 driver runs locally)
|
|
# -p <port> port
|
|
# -f foreground (no daemonization, so systemd manages PID)
|
|
ExecStart=/usr/bin/env msfrpcd -P \${MSFRPC_PASSWORD} -U \${MSFRPC_USER} -a 127.0.0.1 -p \${MSFRPC_PORT} -f
|
|
Restart=on-failure
|
|
RestartSec=5
|
|
NoNewPrivileges=true
|
|
PrivateTmp=true
|
|
ProtectSystem=full
|
|
ProtectHome=true
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
systemctl enable --now cis490-msfrpcd
|
|
|
|
# --- 4. final smoke -----------------------------------------------------
|
|
sleep 2
|
|
if ! ss -ltn 2>/dev/null | grep -q ":$PORT"; then
|
|
log "WARN: nothing listening on 127.0.0.1:$PORT yet — check"
|
|
log " journalctl -u cis490-msfrpcd"
|
|
fi
|
|
|
|
log "done. To run a Tier-3 episode:"
|
|
log " set -a; . $ENV_FILE; set +a"
|
|
log " python tools/run_tier3_demo.py --module vsftpd_234_backdoor"
|