scripts/recon-scan.sh
scripts/recon-scan.shBrowse 9 files
1,257 tokens
3,930 bytes
Token encoding: o200k_base
Snapshot 24fd22b
← Back to SKILL.md
1#!/usr/bin/env bash2# Rate-limited recon scan wrapper for the web-pentest skill.3# Wraps nmap + whatweb + curl headers; enforces scope.txt.4#5# Usage: recon-scan.sh <engagement-dir> <target-url>6#7# Example:8# recon-scan.sh engagement-20260525-031415 http://127.0.0.1:91199set -euo pipefail10 11ENGAGEMENT_DIR="${1:-}"12TARGET_URL="${2:-}"13 14if [[ -z "$ENGAGEMENT_DIR" || -z "$TARGET_URL" ]]; then15 echo "usage: $0 <engagement-dir> <target-url>" >&216 exit 217fi18 19if [[ ! -d "$ENGAGEMENT_DIR" ]]; then20 echo "Engagement directory $ENGAGEMENT_DIR does not exist." >&221 echo "Run Phase 0 (engagement setup) first." >&222 exit 223fi24 25SCOPE_FILE="$ENGAGEMENT_DIR/scope.txt"26AUTH_FILE="$ENGAGEMENT_DIR/authorization.md"27EVIDENCE_DIR="$ENGAGEMENT_DIR/evidence"28LOG_FILE="$ENGAGEMENT_DIR/request-log.jsonl"29 30if [[ ! -f "$AUTH_FILE" ]]; then31 echo "Missing $AUTH_FILE — no engagement authorization on file." >&232 echo "Fill out templates/authorization.md before running." >&233 exit 334fi35 36if [[ ! -f "$SCOPE_FILE" ]]; then37 echo "Missing $SCOPE_FILE — no scope allowlist on file." >&238 exit 339fi40 41mkdir -p "$EVIDENCE_DIR"42 43# Extract host from URL.44HOST="$(python3 -c "import sys, urllib.parse as u; print(u.urlparse(sys.argv[1]).hostname or '')" "$TARGET_URL")"45if [[ -z "$HOST" ]]; then46 echo "Could not parse host from URL: $TARGET_URL" >&247 exit 448fi49 50# Scope check: hostname must appear literally in scope.txt, OR the51# resolved IP must fall inside a CIDR listed there.52in_scope() {53 local host="$1"54 while IFS= read -r line; do55 # strip comments + whitespace56 local entry57 entry="$(printf '%s' "$line" | sed 's/#.*//' | tr -d '[:space:]')"58 [[ -z "$entry" ]] && continue59 if [[ "$entry" == "$host" ]]; then60 return 061 fi62 # If entry is CIDR, check via python63 if [[ "$entry" == */* ]]; then64 python3 - "$host" "$entry" <<'PY' && return 065import sys, socket, ipaddress66host, cidr = sys.argv[1], sys.argv[2]67try:68 ip = socket.gethostbyname(host)69 if ipaddress.ip_address(ip) in ipaddress.ip_network(cidr, strict=False):70 sys.exit(0)71except Exception:72 pass73sys.exit(1)74PY75 fi76 done < "$SCOPE_FILE"77 return 178}79 80if ! in_scope "$HOST"; then81 echo "Host '$HOST' is NOT in $SCOPE_FILE. Refusing to scan." >&282 echo "Add it to scope.txt only if it is genuinely authorized." >&283 exit 584fi85 86# Resolve URL for logging87TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"88echo "[recon-scan] target=$TARGET_URL host=$HOST ts=$TS"89 90# --- headers ---91echo "[recon-scan] fetching headers..."92HEADERS_FILE="$EVIDENCE_DIR/headers.txt"93curl -sSIk --max-time 15 -A "hermes-pentest/recon" "$TARGET_URL" > "$HEADERS_FILE" || true94sleep 0.295 96# --- whatweb ---97if command -v whatweb >/dev/null 2>&1; then98 echo "[recon-scan] running whatweb..."99 whatweb -v --no-errors "$TARGET_URL" > "$EVIDENCE_DIR/whatweb.txt" 2>&1 || true100 sleep 0.2101else102 echo "[recon-scan] whatweb not installed — skipping. Install with: apt install whatweb"103fi104 105# --- robots / sitemap / .well-known ---106echo "[recon-scan] checking robots/sitemap/.well-known..."107for path in robots.txt sitemap.xml .well-known/security.txt; do108 outfile="$EVIDENCE_DIR/$(echo "$path" | tr / _).txt"109 curl -sSk --max-time 10 -A "hermes-pentest/recon" -o "$outfile" -w "%{http_code}\n" "$TARGET_URL/$path" \110 > "$outfile.status" || true111 sleep 0.2112done113 114# --- nmap (top 100 ports, default scripts off, scope-bounded) ---115if command -v nmap >/dev/null 2>&1; then116 echo "[recon-scan] running nmap (top 100 ports, T3, no NSE)..."117 nmap -sT -T3 --top-ports 100 -Pn -oN "$EVIDENCE_DIR/nmap.txt" "$HOST" >/dev/null 2>&1 || true118else119 echo "[recon-scan] nmap not installed — skipping. Install with: apt install nmap"120fi121 122# Log entry123printf '{"ts":"%s","phase":"recon","url":"%s","host":"%s","in_scope":true,"evidence_ref":"evidence/"}\n' \124 "$TS" "$TARGET_URL" "$HOST" >> "$LOG_FILE"125 126echo "[recon-scan] done. Evidence in $EVIDENCE_DIR/"127