文件
websafe-kb/scripts/lab/attack.py

73 行
3.1 KiB
Python

from __future__ import annotations
import subprocess
from pathlib import Path
from typing import Any, Dict, List
from lab.runners.dispatcher import run_attack as run_runner_attack
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]:
if profile.get("runner_id") and not dry_run:
return run_runner_attack(profile, advisory, run_dir)
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),
}
)
elif step.get("kind") == "note" and not dry_run:
record["status"] = "completed"
steps.append(record)
payload = {"steps": steps}
write_json(run_dir / "logs" / "attack.json", payload)
return payload