from __future__ import annotations import subprocess from pathlib import Path from typing import Any, Dict, List from lab.utils import write_json TOOL_COMMANDS = { "xss-fuzzer": ["python3", "/Users/x/websafe/02-xss/tools/xss-fuzzer.py"], "xss-scanner": ["go", "run", "/Users/x/websafe/02-xss/tools/xss-scanner.go"], "sqli-scanner": ["python3", "/Users/x/websafe/01-sql-injection/tools/sqli-scanner.py"], "blind-sqli": ["python3", "/Users/x/websafe/01-sql-injection/tools/blind-sqli.py"], "session-lab": ["python3", "/Users/x/websafe/03-authentication/session/tools/session-lab.py"], "misconfig-lab": ["python3", "/Users/x/websafe/04-server-security/misconfiguration/tools/misconfig-lab.py"], "tls-scanner": ["python3", "/Users/x/websafe/04-server-security/tls/tools/tls-scanner.py"], "site-scope-mapper": ["python3", "/Users/x/websafe/04-server-security/infrastructure/tools/site-scope-mapper.py"], } def _render_args(step: Dict[str, Any], profile: Dict[str, Any], advisory: Dict[str, Any], run_dir: Path) -> List[str]: target = (profile.get("baseline_urls") or [""])[0] mapping = { "{target_url}": target, "{run_id}": run_dir.name, "{case_id}": advisory["canonical_id"], "{evidence_dir}": str(run_dir / "logs"), } args: List[str] = [] for item in step.get("args", []): rendered = item for key, value in mapping.items(): rendered = rendered.replace(key, value) args.append(rendered) return args def run_attack(profile: Dict[str, Any], advisory: Dict[str, Any], run_dir: Path, dry_run: bool = False) -> Dict[str, Any]: steps: List[Dict[str, Any]] = [] for step in profile.get("attack_actions", []): tool_name = step.get("tool") args = _render_args(step, profile, advisory, run_dir) record = { "kind": step.get("kind", "tool"), "tool": tool_name, "args": args, "status": "planned" if dry_run else "skipped", } if step.get("kind") == "tool" and tool_name in TOOL_COMMANDS and not dry_run: output_path = run_dir / "logs" / f"{tool_name}.json" cmd = TOOL_COMMANDS[tool_name] + args + ["--ack-authorized", "--format", "json", "--output", str(output_path)] completed = subprocess.run(cmd, text=True, capture_output=True) record.update( { "status": "completed" if completed.returncode == 0 else "failed", "returncode": completed.returncode, "stdout_excerpt": completed.stdout[-400:], "stderr_excerpt": completed.stderr[-400:], "result_path": str(output_path), } ) steps.append(record) payload = {"steps": steps} write_json(run_dir / "logs" / "attack.json", payload) return payload