CIS490/scripts/install-tier-3-4.sh
Elliott Kolden 667f042707 Tier-3 bring-up: 9 bugs fixed on elliott-ThinkPad (2026-05-01)
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>
2026-05-02 12:26:19 -06:00

173 lines
7.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# Tier-3 + Tier-4 deploy orchestrator. Idempotent. ZERO operator
# interaction — including no API key, no signup, no manual upload.
#
# Steps (each idempotent on its own):
# 1. install-msfrpcd.sh — auto-install metasploit-framework via
# Rapid7 omnibus + drop systemd unit
# 2. fetch-metasploitable2.sh — pull the disk image from the
# SourceForge public mirror (TOFU)
# 3. setup_bridge.sh — bring up br-malware host-only bridge
# for callback-payload modules
# 4. Tier-3 verify — fire vsftpd_234_backdoor against the
# freshly-fetched VM, confirm session
# lands and an episode is recorded
# 5. Tier-4 deploy — clone theZoo (public security-research
# repo, no auth), extract one real
# binary per manifest family, stage at
# samples/store/<sha256>, rewrite
# manifest.toml in place. MANDATORY:
# the deploy fails if zero samples land.
#
# Inputs (env, all optional):
# SKIP_VERIFY — set to skip the live Tier-3 fire test
# SKIP_BRIDGE — set to skip bridge setup (limits to non-callback modules)
# SKIP_TIER4 — set to skip Tier-4 deploy entirely (DEPRECATED;
# leaves you with mimic-only data, defeats the project)
#
# Run as root from anywhere on the lab host. Sub-scripts handle their
# own root checks.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
INSTALL_ROOT="${INSTALL_ROOT:-/opt/cis490}"
DATA_ROOT="${DATA_ROOT:-/var/lib/cis490}"
ETC_ROOT="${ETC_ROOT:-/etc/cis490}"
log() { printf '[install-tier-3-4] %s\n' "$*" >&2; }
die() { log "FATAL: $*"; exit 1; }
[[ $EUID -eq 0 ]] || die "must run as root"
# Resolve script paths — prefer $INSTALL_ROOT (production) over
# $REPO_ROOT (dev clone) so a re-run under systemd uses the same
# scripts the orchestrator does.
script_path() {
local name="$1"
if [[ -x "$INSTALL_ROOT/scripts/$name" ]]; then echo "$INSTALL_ROOT/scripts/$name"; return
elif [[ -x "$REPO_ROOT/scripts/$name" ]]; then echo "$REPO_ROOT/scripts/$name"; return
elif [[ -x "$INSTALL_ROOT/vm/$name" ]]; then echo "$INSTALL_ROOT/vm/$name"; return
elif [[ -x "$REPO_ROOT/vm/$name" ]]; then echo "$REPO_ROOT/vm/$name"; return
else die "$name not found in $INSTALL_ROOT or $REPO_ROOT"
fi
}
# --- 1. msfrpcd --------------------------------------------------------
log "[1/5] install metasploit-framework + msfrpcd unit"
"$(script_path install-msfrpcd.sh)"
if ! systemctl is-active --quiet cis490-msfrpcd; then
log "starting cis490-msfrpcd"
systemctl enable --now cis490-msfrpcd
fi
sleep 3
if ! ss -ltn 2>/dev/null | grep -q ':55553'; then
log "cis490-msfrpcd not listening on 127.0.0.1:55553 yet — waiting up to 30s"
for _ in $(seq 1 30); do
ss -ltn 2>/dev/null | grep -q ':55553' && break
sleep 1
done
fi
ss -ltn 2>/dev/null | grep -q ':55553' || \
die "msfrpcd never bound to :55553 — check 'journalctl -u cis490-msfrpcd'"
log "msfrpcd ✓"
# --- 2. metasploitable2 image ------------------------------------------
log "[2/5] fetch Metasploitable2 disk image"
OUT_DIR="$DATA_ROOT/vm/images"
install -d -m 0755 -o cis490 -g cis490 "$OUT_DIR"
OUT_DIR="$OUT_DIR" "$(script_path fetch-metasploitable2.sh)"
chown cis490:cis490 "$OUT_DIR/metasploitable2.qcow2" 2>/dev/null || true
log "metasploitable2.qcow2 ✓"
# --- 3. bridge ---------------------------------------------------------
if [[ -z "${SKIP_BRIDGE:-}" ]]; then
log "[3/5] bring up br-malware host-only bridge"
"$(script_path setup_bridge.sh)" || log "bridge setup failed (non-fatal); only non-callback modules will fire"
log "br-malware ✓"
else
log "[3/5] SKIP_BRIDGE set — limiting to non-callback modules"
fi
# --- 4. Tier-3 verify --------------------------------------------------
if [[ -z "${SKIP_VERIFY:-}" ]]; then
log "[4/5] verify Tier-3 fire (vsftpd_234_backdoor)"
set -a
# shellcheck disable=SC1091
. "$ETC_ROOT/msfrpc.env"
set +a
PY="$INSTALL_ROOT/.venv/bin/python"
[[ -x "$PY" ]] || PY="$(command -v python3)"
if ! sudo -E -u cis490 "$PY" "$INSTALL_ROOT/tools/run_tier3_demo.py" \
--module vsftpd_234_backdoor \
--target-port 2021 \
--data-root "$DATA_ROOT/data" \
--target-boot-timeout 240 \
> /tmp/cis490-tier3-verify.log 2>&1; then
log "verify run failed — log at /tmp/cis490-tier3-verify.log; dumping last 30 lines:"
tail -30 /tmp/cis490-tier3-verify.log >&2 || true
die "Tier-3 fire failed"
fi
if grep -q '^episode_id = ' /tmp/cis490-tier3-verify.log; then
log "Tier-3 verified ✓ ($(grep '^episode_id = ' /tmp/cis490-tier3-verify.log))"
else
log "verify run finished but no episode_id seen — log at /tmp/cis490-tier3-verify.log"
fi
else
log "[4/5] SKIP_VERIFY set"
fi
# --- 5. Tier-4 deploy (MANDATORY, no auth required) --------------------
if [[ -n "${SKIP_TIER4:-}" ]]; then
log "[5/5] SKIP_TIER4 set — leaving this host on Tier 2/3 mimic-only."
log " This is NOT the recommended configuration; the project's"
log " training target is real-binary episodes."
else
log "[5/5] Tier-4 deploy (real malware fetch from theZoo — mandatory)"
command -v git >/dev/null || die "git not installed; need it to clone theZoo"
PY="$INSTALL_ROOT/.venv/bin/python"
[[ -x "$PY" ]] || PY="$(command -v python3)"
# theZoo clone lives on shared persistent storage so re-runs don't
# re-download. cis490 user owns it for periodic git pull.
THEZOO_DIR="${THEZOO_DIR:-/var/lib/cis490/theZoo}"
install -d -o cis490 -g cis490 -m 0755 "$(dirname "$THEZOO_DIR")"
if ! sudo -E -u cis490 "$PY" \
"$INSTALL_ROOT/tools/auto_fetch_samples.py" \
--thezoo-clone-dir "$THEZOO_DIR" \
> /tmp/cis490-tier4-deploy.log 2>&1; then
log "Tier-4 fetch failed — last 30 lines of /tmp/cis490-tier4-deploy.log:"
tail -30 /tmp/cis490-tier4-deploy.log >&2 || true
die "Tier-4 deploy failed; without real binaries this host produces only mimics"
fi
REAL_COUNT="$(ls "$INSTALL_ROOT/samples/store/" 2>/dev/null | wc -l)"
if [[ "$REAL_COUNT" -lt 1 ]]; then
log "auto_fetch_samples.py exited 0 but samples/store/ is empty — see /tmp/cis490-tier4-deploy.log"
tail -30 /tmp/cis490-tier4-deploy.log >&2 || true
die "Tier-4 deploy failed: no real binaries staged"
fi
log "Tier-4 ✓ ($REAL_COUNT real binaries staged in $INSTALL_ROOT/samples/store/)"
fi
# Restart the orchestrator now so the next wave actually runs Tier-3
# against the freshly-staged msfrpcd + samples. Skipped only if the
# unit isn't enabled yet (first install hasn't run `systemctl enable`).
if systemctl is-enabled --quiet cis490-orchestrator 2>/dev/null; then
log "restarting cis490-orchestrator to pick up new modules + samples"
systemctl restart cis490-orchestrator || \
log "WARN: orchestrator restart failed — check 'journalctl -u cis490-orchestrator'"
fi
log ""
log "================================================================="
log " Tier-3 deploy complete on $(hostname)"
log "================================================================="
log " - metasploit-framework + cis490-msfrpcd.service active"
log " - $OUT_DIR/metasploitable2.qcow2 staged"
log " - bridge: $(ip link show br-malware >/dev/null 2>&1 && echo up || echo skipped)"
log " - Tier-4: $(ls "$INSTALL_ROOT/samples/store/" 2>/dev/null | wc -l) real binaries staged"
log "================================================================="