#!/usr/bin/env bash
# Verify the produced shellshock target satisfies its spec.toml
# promises (PIPELINE.md §4.2 acceptance).
#
# Inputs (env, set by tools/build_target.py):
#   IMAGE_PATH                 — staged qcow2 we just built
#   EXPECTED_SERVICE_NAME      — "apache"
#   EXPECTED_SERVICE_PORT      — 80
#   EXPECTED_SERVICE_PROTO     — "tcp"
#   EXPECTED_VULN_SOFTWARE     — "bash"
#   EXPECTED_VULN_VERSION      — "4.2"
#
# Containment (§4.13) during verification:
#   - SLIRP with restrict=on → no upstream egress (build is done; the
#     image must be self-contained from here on). One hostfwd for the
#     promised port.
#   - snapshot=on so we don't mutate the image.
#   - QEMU as the calling user (whoever ran build_target.py); we're not
#     a root-owned daemon.
#   - No -virtfs / -fsdev shared mounts.

set -euo pipefail

if [[ -z "${IMAGE_PATH:-}" ]]; then
    echo "IMAGE_PATH not set" >&2
    exit 2
fi

PORT="${EXPECTED_SERVICE_PORT:?}"
PROTO="${EXPECTED_SERVICE_PROTO:?}"
VULN_SW="${EXPECTED_VULN_SOFTWARE:?}"
VULN_VER="${EXPECTED_VULN_VERSION:?}"

if [[ "$PROTO" != "tcp" ]]; then
    echo "[verify:shellshock] only TCP services supported in this verifier; got $PROTO" >&2
    exit 1
fi

# Choose an unprivileged host port that maps to guest:$PORT.
HOST_PORT=$((20000 + RANDOM % 5000))
RUN_DIR="$(mktemp -d)"
trap 'qemu-down; rm -rf "$RUN_DIR"' EXIT

qemu-down() {
    if [[ -f "$RUN_DIR/qemu.pid" ]]; then
        local pid
        pid=$(cat "$RUN_DIR/qemu.pid" 2>/dev/null || echo "")
        if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
            kill "$pid" 2>/dev/null || true
            sleep 1
            kill -9 "$pid" 2>/dev/null || true
        fi
    fi
}

echo "[verify:shellshock] booting under §4.13 containment posture"
qemu-system-x86_64 \
    -name cis490-verify-shellshock \
    -machine q35,accel=kvm \
    -cpu host \
    -smp 1 \
    -m 512 \
    -drive file="$IMAGE_PATH",format=qcow2,if=virtio,snapshot=on \
    -netdev "user,id=n0,restrict=on,hostfwd=tcp:127.0.0.1:${HOST_PORT}-:${PORT}" \
    -device virtio-net-pci,netdev=n0 \
    -nographic \
    -display none \
    -serial unix:"$RUN_DIR/serial.sock",server=on,wait=off \
    -monitor unix:"$RUN_DIR/monitor.sock",server=on,wait=off \
    -qmp unix:"$RUN_DIR/qmp.sock",server=on,wait=off \
    -pidfile "$RUN_DIR/qemu.pid" \
    -daemonize

# Wait for the service to come up. Apache + first-boot init can take
# 60-90s on cold start; budget 180s.
echo "[verify:shellshock] waiting for service on 127.0.0.1:${HOST_PORT}"
deadline=$((SECONDS + 180))
while (( SECONDS < deadline )); do
    if curl -sf -m 2 "http://127.0.0.1:${HOST_PORT}/cgi-bin/test.cgi" -o "$RUN_DIR/probe.body" 2>/dev/null; then
        break
    fi
    sleep 2
done
if (( SECONDS >= deadline )); then
    echo "[verify:shellshock] FAIL: service never came up on 127.0.0.1:${HOST_PORT}" >&2
    exit 1
fi

echo "[verify:shellshock] service responded; checking version + vulnerability"

# The CGI script prints `bash --version`. Assert the running bash is
# the promised vulnerable version (4.2).
if ! grep -q "bash, version ${VULN_VER}" "$RUN_DIR/probe.body"; then
    echo "[verify:shellshock] FAIL: probe body does not show ${VULN_SW} ${VULN_VER}:" >&2
    cat "$RUN_DIR/probe.body" >&2
    exit 1
fi

# Confirm the actual shellshock vulnerability is present. CVE-2014-6271:
# bash mis-parses environment values that LOOK like function definitions
# and execute trailing commands.
echo "[verify:shellshock] confirming CVE-2014-6271 reachable via CGI"
RESP=$(curl -s -m 5 \
    -H 'User-Agent: () { :;}; echo VULN_OK_MARKER_$$' \
    "http://127.0.0.1:${HOST_PORT}/cgi-bin/test.cgi" \
    -D "$RUN_DIR/headers" -o "$RUN_DIR/body")
if ! grep -q "VULN_OK_MARKER" "$RUN_DIR/body" "$RUN_DIR/headers" 2>/dev/null; then
    echo "[verify:shellshock] FAIL: shellshock probe didn't trigger payload echo" >&2
    echo "  headers:" >&2; cat "$RUN_DIR/headers" >&2
    echo "  body:" >&2;    cat "$RUN_DIR/body" >&2
    exit 1
fi

echo "[verify:shellshock] PASS: ${VULN_SW} ${VULN_VER} on ${EXPECTED_SERVICE_NAME}:${PORT} confirmed exploitable"
