mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-10-03 14:36:52 +02:00
fix(repl/cli): /target re-derives scope; wildcard target tests subdomains; version banners
Two reported bugs: 1) A scope left over from a previous session persisted in the project session and kept denying every new target (DENY_TARGET_OUTSIDE_GRANT ... scope *.example.com even after /target zoom.us). With no verified capability, /target now re-derives the authorized scope from the new target (preserving excludes + guardrails), so the target you pick is the target you test — same model as `neurosploit run <url>`. 2) A wildcard target (`*.zoom.us`) now authorizes the apex AND all subdomains and seeds recon with the apex (a literal `*.zoom.us` has no DNS record to probe), so subdomain enumeration happens inside the wildcard scope. Applied in both the REPL /target and the one-shot `run` path. Also: the run banner and clap about showed v4.1.0 — now use CARGO_PKG_VERSION / 4.2.1. 421 tests passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
9076d30c59
commit
8a3cb42c1f
2 files changed
+60
-7
No files matched your search
@@ -1,4 +1,4 @@
|
||||
//! NeuroSploit v4.1.0 — interactive harness + CLI (`run` / `whitebox` / `agents` / `models`).
|
||||
//! NeuroSploit — interactive harness + CLI (`run` / `whitebox` / `agents` / `models`).
|
||||
|
||||
mod rectify;
|
||||
mod repl;
|
||||
@@ -13,8 +13,8 @@ use std::path::{Path, PathBuf};
|
||||
#[command(
|
||||
name = "neurosploit",
|
||||
version,
|
||||
about = "NeuroSploit v4.1.0 — multi-model autonomous pentest harness",
|
||||
long_about = "NeuroSploit v4.1.0 — a Rust multi-model harness that drives a pool of LLMs \
|
||||
about = "NeuroSploit v4.2.1 — multi-model autonomous pentest harness",
|
||||
long_about = "NeuroSploit v4.2.1 — a Rust multi-model harness that drives a pool of LLMs \
|
||||
(API key or local subscription: Claude/Codex/Gemini/Grok/OpenCode/Hermes) to autonomously test a target. \
|
||||
After recon it INTELLIGENTLY selects only the agents matching the discovered surface, runs \
|
||||
them in parallel, then validates every finding by cross-model voting before reporting.\n\n\
|
||||
@@ -846,6 +846,18 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
Cmd::Run { url, models, max_agents, vote_n, chain_depth, recon, quick, offline, subscription, mcp, creds, focus, objective, out_of_scope, in_scope, scope_file, environment, policy, budget, token_limit, deep_test_limit, coverage_first, depth_first, sample_per_route, revalidate_poc, compliance, jira, only, verbose } => {
|
||||
let url = if url.starts_with("http") { url } else { format!("https://{url}") };
|
||||
// A wildcard target (`*.zoom.us`) is domain-wide: seed recon with the
|
||||
// apex (a literal `*.zoom.us` has no DNS record to probe) and widen
|
||||
// the grant to every subdomain so enumeration stays in scope.
|
||||
let mut in_scope = in_scope;
|
||||
let url = {
|
||||
let h = harness::scope::host_of(&url);
|
||||
if let Some(apex) = h.strip_prefix("*.") {
|
||||
in_scope.push(format!("*.{apex}"));
|
||||
if recon < 3 { /* leave as set; recon arg is explicit here */ }
|
||||
format!("https://{apex}")
|
||||
} else { url }
|
||||
};
|
||||
let mut cfg = RunConfig::new(&url);
|
||||
cfg.max_agents = max_agents;
|
||||
cfg.vote_n = vote_n;
|
||||
@@ -1266,7 +1278,7 @@ pub(crate) fn spawn_engagement(base: &Path, mut cfg: RunConfig, mcp: bool, mode:
|
||||
println!(" │ ua : {ua}");
|
||||
write_status(&workdir, "running", &format!("\"target\":{:?}", cfg.target));
|
||||
|
||||
println!(" ┌─ NeuroSploit v4.1.0 · by Joas A Santos & Red Team Leaders");
|
||||
println!(" ┌─ NeuroSploit v{} · by Joas A Santos & Red Team Leaders", env!("CARGO_PKG_VERSION"));
|
||||
println!(" │ run id : {run_id}");
|
||||
println!(" │ target : {}", cfg.target);
|
||||
println!(" │ models : {}", cfg.models.join(", "));
|
||||
|
||||
@@ -697,9 +697,50 @@ pub async fn repl(base: &Path, auth: SessionAuth) -> anyhow::Result<()> {
|
||||
let ts: Vec<String> = arg.split(',').map(|x| x.trim()).filter(|x| !x.is_empty())
|
||||
.map(|x| crate::rectify::rectify_url(x).unwrap_or_else(|| x.to_string()))
|
||||
.collect();
|
||||
s.target = Some(ts.join(","));
|
||||
if ts.len() > 1 { println!(" targets ({}): {}", ts.len(), ts.join(", ")); println!(" \x1b[2m/run tests them sequentially, one report each\x1b[0m"); }
|
||||
else { println!(" target: {}", ts.first().cloned().unwrap_or_default()); }
|
||||
// A wildcard target (`*.zoom.us`) means "the whole domain":
|
||||
// authorize the apex AND every subdomain, and seed recon with
|
||||
// the apex (a literal `*.zoom.us` has no DNS record to probe),
|
||||
// so subdomain enumeration happens inside the wildcard scope.
|
||||
let mut wildcard_domain: Option<String> = None;
|
||||
let seeds: Vec<String> = ts.iter().map(|t| {
|
||||
let h = harness::scope::host_of(t);
|
||||
if let Some(apex) = h.strip_prefix("*.") {
|
||||
wildcard_domain = Some(apex.to_string());
|
||||
format!("https://{apex}")
|
||||
} else { t.clone() }
|
||||
}).collect();
|
||||
s.target = Some(seeds.join(","));
|
||||
// Re-derive the authorized scope from the NEW target unless a
|
||||
// verified capability sets the ceiling. Without this, a scope
|
||||
// left over from a previous session (persisted in the project
|
||||
// session) keeps denying every new target — the operator sets
|
||||
// /target zoom.us but the grant still says *.example.com. With
|
||||
// no capability, the target the operator picks IS the grant
|
||||
// (same model as `neurosploit run <url>`); explicit excludes
|
||||
// and guardrails are preserved.
|
||||
if s.capability.is_none() {
|
||||
let keep_exclude = s.policy.exclude.clone();
|
||||
let keep_soft = s.policy.soft.clone();
|
||||
let mut np = harness::scope::ScopePolicy::for_target(&seeds[0]);
|
||||
for extra in seeds.iter().skip(1) { np.allow(&harness::scope::host_of(extra)); }
|
||||
// Each wildcard entry widens the grant to all its subdomains.
|
||||
for t in &ts {
|
||||
let h = harness::scope::host_of(t);
|
||||
if h.starts_with("*.") { np.allow(&h); }
|
||||
}
|
||||
np.exclude = keep_exclude;
|
||||
np.soft = keep_soft;
|
||||
s.policy = np;
|
||||
}
|
||||
if ts.len() > 1 { println!(" targets ({}): {}", ts.len(), seeds.join(", ")); println!(" \x1b[2m/run tests them sequentially, one report each\x1b[0m"); }
|
||||
else { println!(" target: {}", seeds.first().cloned().unwrap_or_default()); }
|
||||
if let Some(d) = &wildcard_domain {
|
||||
println!(" \x1b[2mscope: *.{d} — apex + all subdomains authorized; recon will enumerate subdomains\x1b[0m");
|
||||
// Nudge recon toward active subdomain discovery for a domain-wide engagement.
|
||||
if s.recon_intensity < 3 { s.recon_intensity = 3; }
|
||||
} else if s.capability.is_none() {
|
||||
println!(" \x1b[2mscope: authorized against this target (add more with /inscope, exclude with /scope-out)\x1b[0m");
|
||||
}
|
||||
}
|
||||
}
|
||||
"/timeout" | "/idle" => {
|
||||
|
||||
Reference in new issue
Block a user