mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-06-30 16:45:29 +02:00
55af0d4634
Re-model the pentest agent into an autonomous, markdown-driven engine that turns a URL into a full engagement and delegates execution to a locally installed agentic CLI backend. Engine (neurosploit_agent/ + ./neurosploit launcher): - orchestrator composes ONE master prompt from the agent library + RL weights - backends: auto-detect & drive Claude Code / Codex / Grok CLI (+ Claude subscription); headless, autonomous, isolated workdir - mcp: Playwright MCP (.mcp.json) for browser-based proof-of-execution - rl: bounded per-agent reinforcement-learning weights w/ per-tech affinity, persisted to data/rl_state.json - models: latest registry incl. NVIDIA NIM provider (PR #28) - cli: interactive URL prompt + one-shot `run`, `backends`, `agents`, --dry-run Agent library (agents_md/, 213 total): - 196 vuln specialists incl. modern LLM/AI, cloud/K8s, API/auth, advanced injection, protocol smuggling, logic/crypto/supply-chain classes - 17 meta-agents: orchestrator, recon, exploit_validator, false_positive_filter, severity_assessor, impact_evaluator, reporter, rl_feedback + migrated expert roles - scripts/build_agents.py data-driven builder; REGISTRY.md index Docs: rewritten README.md, v3.3.0 RELEASE.md, .env.example (NVIDIA NIM, xAI, engine vars). Retire legacy Python orchestration (neurosploit.py + agent classes) to legacy/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
164 lines
6.6 KiB
Python
164 lines
6.6 KiB
Python
"""
|
|
NeuroSploit v3.3.0 — terminal launcher.
|
|
|
|
Two ways in:
|
|
|
|
neurosploit # interactive: prompts for URL + choices
|
|
neurosploit run https://t.example --backend claude --model claude-opus-4-8
|
|
|
|
The interactive flow asks for a URL, lets you pick from the agentic CLI backends
|
|
actually installed on this machine (Claude Code / Codex / Grok, or a Claude
|
|
subscription), picks a model, then launches the autonomous engagement.
|
|
"""
|
|
|
|
import argparse
|
|
import sys
|
|
|
|
from . import backends, models
|
|
from .config import RunConfig
|
|
from .orchestrator import run_engagement
|
|
|
|
BANNER = r"""
|
|
_ _ ____ _ _ _
|
|
| \ | | ___ _ _ _ __ ___ / ___|_ __ | | ___ (_) |_
|
|
| \| |/ _ \ | | | '__/ _ \\___ \| '_ \| |/ _ \| | __|
|
|
| |\ | __/ |_| | | | (_) |___) | |_) | | (_) | | |_
|
|
|_| \_|\___|\__,_|_| \___/|____/| .__/|_|\___/|_|\__|
|
|
v3.3.0 Autonomous MD-Agent Engine
|
|
|_|
|
|
"""
|
|
|
|
|
|
def _progress(msg: str):
|
|
print(f" [*] {msg}", flush=True)
|
|
|
|
|
|
def _choose(prompt, options, default_idx=0):
|
|
for i, (key, label) in enumerate(options):
|
|
mark = "*" if i == default_idx else " "
|
|
print(f" {mark} {i + 1}) {label}")
|
|
raw = input(f"{prompt} [{default_idx + 1}]: ").strip()
|
|
if not raw:
|
|
return options[default_idx][0]
|
|
try:
|
|
return options[int(raw) - 1][0]
|
|
except (ValueError, IndexError):
|
|
print(" invalid choice, using default")
|
|
return options[default_idx][0]
|
|
|
|
|
|
def interactive() -> int:
|
|
print(BANNER)
|
|
installed = backends.detect()
|
|
if not installed:
|
|
print(" [!] No agentic CLI backend found (claude / codex / grok).")
|
|
print(" Install one: Claude Code, Codex CLI, or Grok CLI, then re-run.")
|
|
return 2
|
|
print(f" Detected backends: {', '.join(b.label + ' (' + b.version() + ')' for b in installed)}\n")
|
|
|
|
target = input(" Target URL: ").strip()
|
|
if not target:
|
|
print(" [!] A target URL is required.")
|
|
return 2
|
|
if not target.startswith(("http://", "https://")):
|
|
target = "https://" + target
|
|
scope = input(f" In-scope hosts [default: {target}]: ").strip() or target
|
|
collaborator = input(" OOB collaborator host (optional, for blind/SSRF proof): ").strip()
|
|
|
|
backend_key = _choose(" Choose backend", [(b.key, f"{b.label} [{b.version()}]") for b in installed])
|
|
|
|
# Provider/model: map backend → sensible provider, then pick a model.
|
|
prov_for_backend = {"claude": "anthropic", "codex": "openai", "grok": "xai"}
|
|
provider = prov_for_backend.get(backend_key, "anthropic")
|
|
sub = input(" Use Claude subscription (login) instead of an API key? [y/N]: ").strip().lower()
|
|
if sub == "y" and backend_key == "claude":
|
|
provider = "claude_subscription"
|
|
model_opts = [(m.id, f"{m.label} ({m.context // 1000}k ctx) {m.notes}")
|
|
for m in models.list_models(provider)] or [("", "backend default")]
|
|
model = _choose(" Choose model", model_opts)
|
|
|
|
cfg = RunConfig(target=target, scope=scope, backend=backend_key,
|
|
provider=provider, model=model, collaborator=collaborator)
|
|
print()
|
|
_progress(f"Starting autonomous engagement against {target}")
|
|
result = run_engagement(cfg, progress=_progress)
|
|
_summary(result)
|
|
return 0 if result["returncode"] == 0 else 1
|
|
|
|
|
|
def _summary(result):
|
|
print("\n ── Engagement complete ─────────────────────────────")
|
|
print(f" Workdir : {result['workdir']}")
|
|
print(f" Findings: {len(result['findings'])} validated")
|
|
by_sev = {}
|
|
for f in result["findings"]:
|
|
by_sev[f.get("severity", "?")] = by_sev.get(f.get("severity", "?"), 0) + 1
|
|
if by_sev:
|
|
print(" By severity: " + ", ".join(f"{k}={v}" for k, v in by_sev.items()))
|
|
print(f" Report : reports/ | Raw: {result['workdir']}/findings.json")
|
|
print(" ────────────────────────────────────────────────────")
|
|
|
|
|
|
def main(argv=None) -> int:
|
|
parser = argparse.ArgumentParser(prog="neurosploit",
|
|
description="NeuroSploit v3.3.0 autonomous MD-agent pentest engine")
|
|
sub = parser.add_subparsers(dest="cmd")
|
|
|
|
r = sub.add_parser("run", help="run an engagement against a URL")
|
|
r.add_argument("url")
|
|
r.add_argument("--backend", default=None, help="claude | codex | grok (default: first installed)")
|
|
r.add_argument("--provider", default=None)
|
|
r.add_argument("--model", default=None)
|
|
r.add_argument("--scope", default="")
|
|
r.add_argument("--collaborator", default="")
|
|
r.add_argument("--no-rl", action="store_true")
|
|
r.add_argument("--no-mcp", action="store_true")
|
|
r.add_argument("--max-agents", type=int, default=0)
|
|
r.add_argument("--dry-run", action="store_true", help="compose prompt + show command without executing the backend")
|
|
|
|
sub.add_parser("backends", help="list detected CLI backends")
|
|
sub.add_parser("agents", help="show agent library counts")
|
|
|
|
args = parser.parse_args(argv)
|
|
|
|
if args.cmd is None:
|
|
try:
|
|
return interactive()
|
|
except (KeyboardInterrupt, EOFError):
|
|
print("\n aborted.")
|
|
return 130
|
|
|
|
if args.cmd == "backends":
|
|
for b in backends.detect():
|
|
print(f" {b.key:8} {b.label:14} {b.version()}")
|
|
if not backends.detect():
|
|
print(" none installed (claude / codex / grok)")
|
|
return 0
|
|
|
|
if args.cmd == "agents":
|
|
from .agent_loader import AgentLibrary
|
|
print(AgentLibrary().counts())
|
|
return 0
|
|
|
|
if args.cmd == "run":
|
|
url = args.url if args.url.startswith(("http://", "https://")) else "https://" + args.url
|
|
backend = args.backend or (backends.detect()[0].key if backends.detect() else "claude")
|
|
prov_for_backend = {"claude": "anthropic", "codex": "openai", "grok": "xai"}
|
|
provider = args.provider or prov_for_backend.get(backend, "anthropic")
|
|
model = args.model or (models.list_models(provider)[0].id if models.list_models(provider) else "")
|
|
cfg = RunConfig(target=url, scope=args.scope or url, backend=backend,
|
|
provider=provider, model=model, collaborator=args.collaborator,
|
|
use_rl=not args.no_rl, use_mcp=not args.no_mcp,
|
|
max_agents=args.max_agents, dry_run=args.dry_run)
|
|
print(BANNER)
|
|
result = run_engagement(cfg, progress=_progress)
|
|
_summary(result)
|
|
return 0 if result["returncode"] == 0 else 1
|
|
|
|
parser.print_help()
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|